2011-06-16 01:24:46 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 Intel Corporation
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) version 3.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2011-07-19 01:15:03 +02:00
|
|
|
#include "server.h"
|
2011-06-16 01:24:46 +02:00
|
|
|
#include "connection.h"
|
2011-06-17 12:04:47 +02:00
|
|
|
#include "client.h"
|
|
|
|
|
|
|
|
#include <synthesis/san.h>
|
|
|
|
#include <syncevo/TransportAgent.h>
|
|
|
|
#include <syncevo/SyncContext.h>
|
2011-06-16 01:24:46 +02:00
|
|
|
|
2011-06-17 13:05:42 +02:00
|
|
|
using namespace GDBusCXX;
|
|
|
|
|
2011-06-16 01:24:46 +02:00
|
|
|
SE_BEGIN_CXX
|
|
|
|
|
|
|
|
void Connection::failed(const std::string &reason)
|
|
|
|
{
|
|
|
|
if (m_failure.empty()) {
|
|
|
|
m_failure = reason;
|
|
|
|
if (m_session) {
|
|
|
|
m_session->setStubConnectionError(reason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_state != FAILED) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
m_state = FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Connection::buildDescription(const StringMap &peer)
|
|
|
|
{
|
|
|
|
StringMap::const_iterator
|
|
|
|
desc = peer.find("description"),
|
|
|
|
id = peer.find("id"),
|
|
|
|
trans = peer.find("transport"),
|
|
|
|
trans_desc = peer.find("transport_description");
|
|
|
|
std::string buffer;
|
|
|
|
buffer.reserve(256);
|
|
|
|
if (desc != peer.end()) {
|
|
|
|
buffer += desc->second;
|
|
|
|
}
|
|
|
|
if (id != peer.end() || trans != peer.end()) {
|
|
|
|
if (!buffer.empty()) {
|
|
|
|
buffer += " ";
|
|
|
|
}
|
|
|
|
buffer += "(";
|
|
|
|
if (id != peer.end()) {
|
|
|
|
buffer += id->second;
|
|
|
|
if (trans != peer.end()) {
|
|
|
|
buffer += " via ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (trans != peer.end()) {
|
|
|
|
buffer += trans->second;
|
|
|
|
if (trans_desc != peer.end()) {
|
|
|
|
buffer += " ";
|
|
|
|
buffer += trans_desc->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buffer += ")";
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::wakeupSession()
|
|
|
|
{
|
|
|
|
if (m_loop) {
|
|
|
|
g_main_loop_quit(m_loop);
|
|
|
|
m_loop = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::process(const Caller_t &caller,
|
|
|
|
const std::pair<size_t, const uint8_t *> &message,
|
|
|
|
const std::string &message_type)
|
|
|
|
{
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "D-Bus client %s sends %lu bytes via connection %s, %s",
|
|
|
|
caller.c_str(),
|
|
|
|
(unsigned long)message.first,
|
|
|
|
getPath(),
|
|
|
|
message_type.c_str());
|
|
|
|
|
|
|
|
boost::shared_ptr<Client> client(m_server.findClient(caller));
|
|
|
|
if (!client) {
|
|
|
|
throw runtime_error("unknown client");
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<Connection> myself =
|
|
|
|
boost::static_pointer_cast<Connection, Resource>(client->findResource(this));
|
|
|
|
if (!myself) {
|
|
|
|
throw runtime_error("client does not own connection");
|
|
|
|
}
|
|
|
|
|
|
|
|
// any kind of error from now on terminates the connection
|
|
|
|
try {
|
|
|
|
switch (m_state) {
|
|
|
|
case SETUP: {
|
|
|
|
std::string config;
|
|
|
|
std::string peerDeviceID;
|
|
|
|
bool serverMode = false;
|
|
|
|
bool serverAlerted = false;
|
|
|
|
// check message type, determine whether we act
|
|
|
|
// as client or server, choose config
|
|
|
|
if (message_type == "HTTP Config") {
|
|
|
|
// type used for testing, payload is config name
|
|
|
|
config.assign(reinterpret_cast<const char *>(message.second),
|
|
|
|
message.first);
|
|
|
|
} else if (message_type == TransportAgent::m_contentTypeServerAlertedNotificationDS) {
|
|
|
|
serverAlerted = true;
|
|
|
|
sysync::SanPackage san;
|
|
|
|
if (san.PassSan(const_cast<uint8_t *>(message.second), message.first, 2) || san.GetHeader()) {
|
|
|
|
// We are very tolerant regarding the content of the message.
|
|
|
|
// If it doesn't parse, try to do something useful anyway.
|
|
|
|
// only for SAN 1.2, for SAN 1.0/1.1 we can not be sure
|
|
|
|
// whether it is a SAN package or a normal sync pacakge
|
|
|
|
if (message_type == TransportAgent::m_contentTypeServerAlertedNotificationDS) {
|
|
|
|
config = "default";
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN parsing failed, falling back to 'default' config");
|
|
|
|
}
|
|
|
|
} else { //Server alerted notification case
|
|
|
|
// Extract server ID and match it against a server
|
|
|
|
// configuration. Multiple different peers might use the
|
|
|
|
// same serverID ("PC Suite"), so check properties of the
|
|
|
|
// of our configs first before going back to the name itself.
|
|
|
|
std::string serverID = san.fServerID;
|
|
|
|
SyncConfig::ConfigList servers = SyncConfig::getConfigs();
|
|
|
|
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server,
|
|
|
|
servers) {
|
|
|
|
SyncConfig conf(server.first);
|
|
|
|
vector<string> urls = conf.getSyncURL();
|
|
|
|
BOOST_FOREACH (const string &url, urls) {
|
|
|
|
if (url == serverID) {
|
|
|
|
config = server.first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!config.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// for Bluetooth transports match against mac address.
|
|
|
|
StringMap::const_iterator id = m_peer.find("id"),
|
|
|
|
trans = m_peer.find("transport");
|
|
|
|
if (trans != m_peer.end() && id != m_peer.end()) {
|
|
|
|
if (trans->second == "org.openobex.obexd") {
|
|
|
|
m_peerBtAddr = id->second.substr(0, id->second.find("+"));
|
|
|
|
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server,
|
|
|
|
servers) {
|
|
|
|
SyncConfig conf(server.first);
|
|
|
|
vector<string> urls = conf.getSyncURL();
|
|
|
|
BOOST_FOREACH (string &url, urls){
|
|
|
|
url = url.substr (0, url.find("+"));
|
|
|
|
SE_LOG_DEBUG (NULL, NULL, "matching against %s",url.c_str());
|
|
|
|
if (url.find ("obex-bt://") ==0 && url.substr(strlen("obex-bt://"), url.npos) == m_peerBtAddr) {
|
|
|
|
config = server.first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!config.empty()){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.empty()) {
|
|
|
|
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server,
|
|
|
|
servers) {
|
|
|
|
if (server.first == serverID) {
|
|
|
|
config = serverID;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a default configuration name if none matched
|
|
|
|
if (config.empty()) {
|
|
|
|
config = serverID+"_"+getCurrentTime();
|
|
|
|
SE_LOG_DEBUG(NULL,
|
|
|
|
NULL,
|
|
|
|
"SAN Server ID '%s' unknown, falling back to automatically created '%s' config",
|
|
|
|
serverID.c_str(), config.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN sync with config %s", config.c_str());
|
|
|
|
|
|
|
|
m_SANContent.reset (new SANContent ());
|
|
|
|
// extract number of sources
|
|
|
|
int numSources = san.fNSync;
|
|
|
|
int syncType;
|
|
|
|
uint32_t contentType;
|
|
|
|
std::string serverURI;
|
|
|
|
if (!numSources) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN message with no sources, using selected modes");
|
|
|
|
// Synchronize all known sources with the default mode.
|
|
|
|
if (san.GetNthSync(0, syncType, contentType, serverURI)) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN invalid header, using default modes");
|
|
|
|
} else if (syncType < SYNC_FIRST || syncType > SYNC_LAST) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN invalid sync type %d, using default modes", syncType);
|
|
|
|
} else {
|
|
|
|
m_syncMode = PrettyPrintSyncMode(SyncMode(syncType), true);
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN sync mode for all configured sources: %s", m_syncMode.c_str());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int sync = 1; sync <= numSources; sync++) {
|
|
|
|
if (san.GetNthSync(sync, syncType, contentType, serverURI)) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN invalid sync entry #%d", sync);
|
|
|
|
} else if (syncType < SYNC_FIRST || syncType > SYNC_LAST) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "SAN invalid sync type %d for entry #%d, ignoring entry", syncType, sync);
|
|
|
|
} else {
|
|
|
|
std::string syncMode = PrettyPrintSyncMode(SyncMode(syncType), true);
|
|
|
|
m_SANContent->m_syncType.push_back (syncMode);
|
|
|
|
m_SANContent->m_serverURI.push_back (serverURI);
|
|
|
|
m_SANContent->m_contentType.push_back (contentType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: use the session ID set by the server if non-null
|
|
|
|
} else if (// relaxed checking for XML: ignore stuff like "; CHARSET=UTF-8"
|
|
|
|
message_type.substr(0, message_type.find(';')) == TransportAgent::m_contentTypeSyncML ||
|
|
|
|
message_type == TransportAgent::m_contentTypeSyncWBXML) {
|
|
|
|
// run a new SyncML session as server
|
|
|
|
serverMode = true;
|
|
|
|
if (m_peer.find("config") == m_peer.end() &&
|
|
|
|
!m_peer["config"].empty()) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "ignoring pre-chosen config '%s'",
|
|
|
|
m_peer["config"].c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// peek into the data to extract the locURI = device ID,
|
|
|
|
// then use it to find the configuration
|
|
|
|
SyncContext::SyncMLMessageInfo info;
|
|
|
|
info = SyncContext::analyzeSyncMLMessage(reinterpret_cast<const char *>(message.second),
|
|
|
|
message.first,
|
|
|
|
message_type);
|
|
|
|
if (info.m_deviceID.empty()) {
|
|
|
|
// TODO: proper exception
|
|
|
|
throw runtime_error("could not extract LocURI=deviceID from initial message");
|
|
|
|
}
|
|
|
|
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &entry,
|
|
|
|
SyncConfig::getConfigs()) {
|
|
|
|
SyncConfig peer(entry.first);
|
|
|
|
if (info.m_deviceID == peer.getRemoteDevID()) {
|
|
|
|
config = entry.first;
|
|
|
|
SE_LOG_INFO(NULL, NULL, "matched %s against config %s (%s)",
|
|
|
|
info.toString().c_str(),
|
|
|
|
entry.first.c_str(),
|
|
|
|
entry.second.c_str());
|
|
|
|
// Stop searching. Other peer configs might have the same remoteDevID.
|
|
|
|
// We go with the first one found, which because of the sort order
|
|
|
|
// of getConfigs() ensures that "foo" is found before "foo.old".
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (config.empty()) {
|
|
|
|
// TODO: proper exception
|
|
|
|
throw runtime_error(string("no configuration found for ") +
|
|
|
|
info.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
// abort previous session of this client
|
|
|
|
m_server.killSessions(info.m_deviceID);
|
|
|
|
peerDeviceID = info.m_deviceID;
|
|
|
|
} else {
|
|
|
|
throw runtime_error(StringPrintf("message type '%s' not supported for starting a sync", message_type.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// run session as client or server
|
|
|
|
m_state = PROCESSING;
|
|
|
|
m_session = Session::createSession(m_server,
|
|
|
|
peerDeviceID,
|
|
|
|
config,
|
|
|
|
m_sessionID);
|
|
|
|
if (serverMode) {
|
|
|
|
m_session->initServer(SharedBuffer(reinterpret_cast<const char *>(message.second),
|
|
|
|
message.first),
|
|
|
|
message_type);
|
|
|
|
}
|
|
|
|
m_session->setServerAlerted(serverAlerted);
|
|
|
|
m_session->setPriority(Session::PRI_CONNECTION);
|
|
|
|
m_session->setStubConnection(myself);
|
|
|
|
// this will be reset only when the connection shuts down okay
|
|
|
|
// or overwritten with the error given to us in
|
|
|
|
// Connection::close()
|
|
|
|
m_session->setStubConnectionError("closed prematurely");
|
|
|
|
m_server.enqueue(m_session);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PROCESSING:
|
|
|
|
throw std::runtime_error("protocol error: already processing a message");
|
|
|
|
break;
|
|
|
|
case WAITING:
|
|
|
|
m_incomingMsg = SharedBuffer(reinterpret_cast<const char *>(message.second),
|
|
|
|
message.first);
|
|
|
|
m_incomingMsgType = message_type;
|
|
|
|
m_state = PROCESSING;
|
|
|
|
// get out of DBusTransportAgent::wait()
|
|
|
|
wakeupSession();
|
|
|
|
break;
|
|
|
|
case FINAL:
|
|
|
|
wakeupSession();
|
|
|
|
throw std::runtime_error("protocol error: final reply sent, no further message processing possible");
|
|
|
|
case DONE:
|
|
|
|
throw std::runtime_error("protocol error: connection closed, no further message processing possible");
|
|
|
|
break;
|
|
|
|
case FAILED:
|
|
|
|
throw std::runtime_error(m_failure);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::runtime_error("protocol error: unknown internal state");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (const std::exception &error) {
|
|
|
|
failed(error.what());
|
|
|
|
throw;
|
|
|
|
} catch (...) {
|
|
|
|
failed("unknown exception in Connection::process");
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::close(const Caller_t &caller,
|
|
|
|
bool normal,
|
|
|
|
const std::string &error)
|
|
|
|
{
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "D-Bus client %s closes connection %s %s%s%s",
|
|
|
|
caller.c_str(),
|
|
|
|
getPath(),
|
|
|
|
normal ? "normally" : "with error",
|
|
|
|
error.empty() ? "" : ": ",
|
|
|
|
error.c_str());
|
|
|
|
|
|
|
|
boost::shared_ptr<Client> client(m_server.findClient(caller));
|
|
|
|
if (!client) {
|
|
|
|
throw runtime_error("unknown client");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!normal ||
|
|
|
|
m_state != FINAL) {
|
|
|
|
std::string err = error.empty() ?
|
|
|
|
"connection closed unexpectedly" :
|
|
|
|
error;
|
|
|
|
if (m_session) {
|
|
|
|
m_session->setStubConnectionError(err);
|
|
|
|
}
|
|
|
|
failed(err);
|
|
|
|
} else {
|
|
|
|
m_state = DONE;
|
|
|
|
if (m_session) {
|
|
|
|
m_session->setStubConnectionError("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove reference to us from client, will destruct *this*
|
|
|
|
// instance!
|
|
|
|
client->detach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::abort()
|
|
|
|
{
|
|
|
|
if (!m_abortSent) {
|
|
|
|
sendAbort();
|
|
|
|
m_abortSent = true;
|
|
|
|
m_state = FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::shutdown()
|
|
|
|
{
|
|
|
|
// trigger removal of this connection by removing all
|
|
|
|
// references to it
|
|
|
|
m_server.detach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
Connection::Connection(DBusServer &server,
|
|
|
|
const DBusConnectionPtr &conn,
|
|
|
|
const std::string &sessionID,
|
|
|
|
const StringMap &peer,
|
|
|
|
bool must_authenticate) :
|
|
|
|
DBusObjectHelper(conn.get(),
|
|
|
|
std::string("/org/syncevolution/Connection/") + sessionID,
|
|
|
|
"org.syncevolution.Connection",
|
|
|
|
boost::bind(&DBusServer::autoTermCallback, &server)),
|
|
|
|
m_server(server),
|
|
|
|
m_peer(peer),
|
|
|
|
m_mustAuthenticate(must_authenticate),
|
|
|
|
m_state(SETUP),
|
|
|
|
m_sessionID(sessionID),
|
|
|
|
m_loop(NULL),
|
|
|
|
sendAbort(*this, "Abort"),
|
|
|
|
m_abortSent(false),
|
|
|
|
reply(*this, "Reply"),
|
|
|
|
m_description(buildDescription(peer))
|
|
|
|
{
|
|
|
|
add(this, &Connection::process, "Process");
|
|
|
|
add(this, &Connection::close, "Close");
|
|
|
|
add(sendAbort);
|
|
|
|
add(reply);
|
|
|
|
m_server.autoTermRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
Connection::~Connection()
|
|
|
|
{
|
|
|
|
SE_LOG_DEBUG(NULL, NULL, "done with connection to '%s'%s%s%s",
|
|
|
|
m_description.c_str(),
|
|
|
|
m_state == DONE ? ", normal shutdown" : " unexpectedly",
|
|
|
|
m_failure.empty() ? "" : ": ",
|
|
|
|
m_failure.c_str());
|
|
|
|
try {
|
|
|
|
if (m_state != DONE) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
// DBusTransportAgent waiting? Wake it up.
|
|
|
|
wakeupSession();
|
|
|
|
m_session.use_count();
|
|
|
|
m_session.reset();
|
|
|
|
} catch (...) {
|
|
|
|
// log errors, but do not propagate them because we are
|
|
|
|
// destructing
|
|
|
|
Exception::handle();
|
|
|
|
}
|
|
|
|
m_server.autoTermUnref();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::ready()
|
|
|
|
{
|
|
|
|
//if configuration not yet created
|
|
|
|
std::string configName = m_session->getConfigName();
|
|
|
|
SyncConfig config (configName);
|
|
|
|
if (!config.exists() && m_SANContent) {
|
|
|
|
SE_LOG_DEBUG (NULL, NULL, "Configuration %s not exists for a runnable session in a SAN context, create it automatically", configName.c_str());
|
|
|
|
ReadOperations::Config_t from;
|
|
|
|
const std::string templateName = "SyncEvolution";
|
|
|
|
// TODO: support SAN from other well known servers
|
|
|
|
ReadOperations ops(templateName, m_server);
|
|
|
|
ops.getConfig(true , from);
|
|
|
|
if (!m_peerBtAddr.empty()){
|
|
|
|
from[""]["SyncURL"] = string ("obex-bt://") + m_peerBtAddr;
|
|
|
|
}
|
|
|
|
m_session->setConfig (false, false, from);
|
|
|
|
}
|
|
|
|
const SyncContext context (configName);
|
|
|
|
std::list<std::string> sources = context.getSyncSources();
|
|
|
|
|
|
|
|
if (m_SANContent && !m_SANContent->m_syncType.empty()) {
|
|
|
|
// check what the server wants us to synchronize
|
|
|
|
// and only synchronize that
|
|
|
|
m_syncMode = "disabled";
|
|
|
|
for (size_t sync=0; sync<m_SANContent->m_syncType.size(); sync++) {
|
|
|
|
std::string syncMode = m_SANContent->m_syncType[sync];
|
|
|
|
std::string serverURI = m_SANContent->m_serverURI[sync];
|
|
|
|
//uint32_t contentType = m_SANContent->m_contentType[sync];
|
|
|
|
bool found = false;
|
|
|
|
BOOST_FOREACH(const std::string &source, sources) {
|
|
|
|
boost::shared_ptr<const PersistentSyncSourceConfig> sourceConfig(context.getSyncSourceConfig(source));
|
|
|
|
// prefix match because the local
|
|
|
|
// configuration might contain
|
|
|
|
// additional parameters (like date
|
|
|
|
// range selection for events)
|
|
|
|
if (boost::starts_with(sourceConfig->getURINonEmpty(), serverURI)) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL,
|
|
|
|
"SAN entry #%d = source %s with mode %s",
|
|
|
|
(int)sync, source.c_str(), syncMode.c_str());
|
|
|
|
m_sourceModes[source] = syncMode;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL,
|
|
|
|
"SAN entry #%d with mode %s ignored because Server URI %s is unknown",
|
|
|
|
(int)sync, syncMode.c_str(), serverURI.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_sourceModes.empty()) {
|
|
|
|
SE_LOG_DEBUG(NULL, NULL,
|
|
|
|
"SAN message with no known entries, falling back to default");
|
|
|
|
m_syncMode = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_SANContent) {
|
|
|
|
m_session->setRemoteInitiated(true);
|
|
|
|
}
|
|
|
|
// proceed with sync now that our session is ready
|
|
|
|
m_session->sync(m_syncMode, m_sourceModes);
|
|
|
|
}
|
|
|
|
|
|
|
|
SE_END_CXX
|