syncevo-dbus-server: use Server Alerted Notification (SAN) message content

Selecting a sync mode for all configured sources and selecting
specific sources with one sync mode per source are both supported.

The code is very tolerant of message encoding problems. It logs
errors, then tries to run a sync session with reasonable defaults
despite such errors:
- using a configuration named 'default'
- sync modes as specified in that config

Authorization is not checked at all. In other words, the SAN digest
is ignored. The requested UI mode is also ignored. A sync always runs
in the background, unless a GUI is already running an decides to
display the running sync. Both is consistent with the current design
of SyncEvolution.

The Session ID sent by the server is also ignored. This is an
implementation limitiation which should be fixed. Depends on
a suitable API for the Synthesis Engine.

The Server ID is used to find a corresponding local configuration
as follows:
- first match against syncURL of all configured servers
- if not found, match against the config names themselves

The local configuration must exist. It is not currently created
on-the-fly.

If the SAN message specifies specific URIs, then the corresponding
local data sources are identified by comparing the server's URI
against the beginning of the URI in the local source
configuration. That way a local URI may contain parameters appended to
it (supported by some servers to select the data which is to be
synchronzied).
This commit is contained in:
Patrick Ohly 2009-09-24 12:54:36 +02:00
parent 665bdcb8f7
commit e2aea80e94

View file

@ -29,6 +29,8 @@
#include <syncevo/SoupTransportAgent.h>
#include <syncevo/SyncSource.h>
#include <synthesis/san.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
@ -648,6 +650,11 @@ class Connection : public DBusObjectHelper, public Resource
} m_state;
std::string m_failure;
/** first parameter for Session::sync() */
std::string m_syncMode;
/** second parameter for Session::sync() */
Session::SourceModes_t m_sourceModes;
const std::string m_sessionID;
boost::shared_ptr<Session> m_session;
@ -1441,22 +1448,111 @@ void Connection::process(const Caller_t &caller,
config.assign(reinterpret_cast<const char *>(message.second),
message.first);
} else if (message_type == TransportAgent::m_contentTypeServerAlertedNotificationDS) {
// TODO: extract server ID and match it against a server configuration.
// At the moment, always pick "default" as configuration name.
// sysync::SanPackage san;
// san.PassSan(message.second, message.first);
// san.GetHeader();
// std::string serverID = san.fServerID;
config = "default";
sysync::SanPackage san;
if (san.PassSan(const_cast<uint8_t *>(message.second), message.first)) {
// We are very tolerant regarding the content of the message.
// If it doesn't parse, try to do something useful anyway.
config = "default";
SE_LOG_DEBUG(NULL, NULL, "SAN parsing failed, falling back to 'default' config");
} else {
// 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::ServerList servers = SyncConfig::getServers();
BOOST_FOREACH(const SyncConfig::ServerList::value_type &server,
servers) {
SyncContext context(server.first);
if (context.getSyncURL() == serverID) {
config = serverID;
break;
}
// TODO: extract number of sources
int numSources = 0;
if (!numSources) {
// Synchronize all known sources with the selected mode.
} else {
// TODO: check what the server wants us to synchronize.
// Create the necessary local configuration temporarily,
// using heuristics if necessary.
// TODO: for other transports match against
// transport specific properties, like Bluetooth MAC
// address
}
if (config.empty()) {
BOOST_FOREACH(const SyncConfig::ServerList::value_type &server,
servers) {
if (server.first == serverID) {
config = serverID;
break;
}
}
}
// pick "default" as configuration name if none matched
if (config.empty()) {
config = "default";
SE_LOG_DEBUG(NULL, NULL, "SAN Server ID '%s' unknown, falling back to 'default' config", serverID.c_str());
}
// TODO: create a suitable configuration automatically?!
SE_LOG_DEBUG(NULL, NULL, "SAN sync with config %s", config.c_str());
// 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");
// Synchronize all known sources with the selected 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 {
const SyncContext context(config);
std::list<std::string> sources = context.getSyncSources();
// check what the server wants us to synchronize
// and only synchronize that
m_syncMode = "disabled";
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);
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->getURI(), serverURI)) {
SE_LOG_DEBUG(NULL, NULL,
"SAN entry #%d = source %s with mode %s",
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",
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 = "";
}
}
}
// TODO: use the session ID set by the server if non-null
@ -1650,7 +1746,7 @@ void Connection::activate()
void Connection::ready()
{
// proceed with sync now that our session is ready
m_session->sync("", Session::SourceModes_t());
m_session->sync(m_syncMode, m_sourceModes);
}
/****************** DBusTransportAgent implementation **************/