adapted to official DevInf API with one patch: config passed to SyncClient::conf()

git-svn-id: https://zeitsenke.de/svn/SyncEvolution/trunk@237 15ad00c4-1369-45f4-8270-35d70d36bdcd
This commit is contained in:
Patrick Ohly 2006-09-07 19:47:29 +00:00
parent f7d31296cc
commit 168dd2b911
6 changed files with 180 additions and 167 deletions

View File

@ -58,6 +58,8 @@ class EvolutionCalendarSource : public EvolutionSyncSource
virtual void close();
virtual void exportData(ostream &out);
virtual string fileSuffix() { return "ics"; }
virtual const char *getMimeType() { return "text/calendar"; }
virtual const char *getMimeVersion() { return "2.0"; }
virtual SyncItem *createItem( const string &uid, SyncState state );
@ -65,17 +67,7 @@ class EvolutionCalendarSource : public EvolutionSyncSource
// implementation of SyncSource
//
virtual ArrayElement *clone() { return new EvolutionCalendarSource(*this); }
void getPreferredTypes(const char*& recvType,
const char*& recvVersion,
const char*& sendType,
const char*& sendVersion) {
// these might be the preferred types, but in the end
// the configured type is used
recvType = "text/calendar";
recvVersion = "2.0";
sendType = "text/calendar";
sendVersion = "2.0";
}
const char **getSendTypes() {
static const char *types[] = { "text/calendar", "2.0",
NULL };

View File

@ -543,6 +543,19 @@ const char *EvolutionContactSource::getMimeType()
}
}
const char *EvolutionContactSource::getMimeVersion()
{
switch( m_vcardFormat ) {
case EVC_FORMAT_VCARD_21:
return "2.1";
break;
case EVC_FORMAT_VCARD_30:
default:
return "3.0";
break;
}
}
void EvolutionContactSource::logItem( const string &uid, const string &info )
{
if (LOG.getLevel() >= LOG_LEVEL_INFO) {

View File

@ -69,6 +69,9 @@ class EvolutionContactSource : public EvolutionSyncSource
virtual void close();
virtual void exportData(ostream &out);
virtual string fileSuffix() { return "vcf"; }
virtual const char *getMimeType();
virtual const char *getMimeVersion();
virtual SyncItem *createItem( const string &uid, SyncState state );
@ -76,25 +79,7 @@ class EvolutionContactSource : public EvolutionSyncSource
// implementation of SyncSource
//
virtual ArrayElement *clone() { return new EvolutionContactSource(*this); }
void getPreferredTypes(const char*& recvType,
const char*& recvVersion,
const char*& sendType,
const char*& sendVersion) {
// use the configured type also as the preferred one,
// some servers get confused when sending something different
// than announced here
if (m_vcardFormat == EVC_FORMAT_VCARD_21) {
recvType = "text/x-vcard";
recvVersion = "2.1";
sendType = "text/x-vcard";
sendVersion = "2.1";
} else {
recvType = "text/vcard";
recvVersion = "3.0";
sendType = "text/vcard";
sendVersion = "3.0";
}
}
const char **getSendTypes() {
static const char *types[] = { "text/vcard", "3.0",
"text/x-vcard", "2.1",
@ -103,7 +88,7 @@ class EvolutionContactSource : public EvolutionSyncSource
return types;
}
const char **getRecvTypes() { return getSendTypes(); }
protected:
//
// implementation of EvolutionSyncSource callbacks
@ -118,7 +103,7 @@ class EvolutionContactSource : public EvolutionSyncSource
virtual int deleteItemThrow(SyncItem& item);
virtual void logItem(const string &uid, const string &info);
virtual void logItem(SyncItem &item, const string &info);
private:
/** valid after open(): the address book that this source references */
eptr<EBook, GObject> m_addressbook;
@ -164,9 +149,6 @@ class EvolutionContactSource : public EvolutionSyncSource
insert("CALURI");
}
} m_uniqueProperties;
/** the mime type which corresponds to m_vcardFormat */
const char *getMimeType();
};
#endif // ENABLE_EBOOK

View File

@ -19,7 +19,7 @@
#include "EvolutionSyncClient.h"
#include "EvolutionSyncSource.h"
#include <spdm/DMTree.h>
#include <client/DMTClientConfig.h>
#include <posix/base/posixlog.h>
#include <list>
@ -46,7 +46,6 @@ EvolutionSyncClient::EvolutionSyncClient(const string &server, SyncMode syncMode
m_doLogging(doLogging),
m_configPath(string("evolution/") + server)
{
setDMConfig(m_configPath.c_str());
}
EvolutionSyncClient::~EvolutionSyncClient()
@ -244,6 +243,7 @@ class SourceList : public list<EvolutionSyncSource *> {
LogDir m_logdir; /**< our logging directory */
bool m_doLogging; /**< true iff additional files are to be written during sync */
bool m_reportTodo; /**< true if syncDone() shall print a final report */
arrayptr<SyncSource *> m_sourceArray; /** owns the array that is expected by SyncClient::sync() */
string databaseName(EvolutionSyncSource &source, const string suffix) {
return m_logdir.getLogdir() + "/" +
@ -355,7 +355,22 @@ public:
}
}
}
/** returns current sources as array as expected by SyncClient::sync(), memory owned by this class */
SyncSource **getSourceArray() {
m_sourceArray = new SyncSource *[size() + 1];
int index = 0;
for (iterator it = begin();
it != end();
++it) {
((SyncSource **)m_sourceArray)[index] = *it;
index++;
}
((SyncSource **)m_sourceArray)[index] = 0;
return m_sourceArray;
}
~SourceList() {
// if we get here without a previous report,
// something went wrong
@ -377,86 +392,105 @@ void unref(SourceList *sourceList)
int EvolutionSyncClient::sync()
{
// this will trigger the prepareSync(), createSyncSource(), beginSource() callbacks
int res = SyncClient::sync();
class EvolutionClientConfig : public DMTClientConfig {
public:
EvolutionClientConfig(const char *root) :
DMTClientConfig(root) {}
#if 0
// Change of policy: even if a sync source failed allow
// the next sync to proceed normally. The rationale is
// that novice users then do not have to care about deleting
// "bad" items because the next two-way sync will not stumble
// over them.
//
// Force slow sync in case of failed Evolution source
// by overwriting the last sync time stamp;
// don't do it if only the general result is a failure
// because in that case it is not obvious which source
// failed.
for ( index = 0; index < m_sourceList->size(); index++ ) {
EvolutionSyncSource *source = (*m_sourceList)[index];
if (source->hasFailed()) {
string sourcePath(sourcesPath + "/" + sourceArray[index]->getName());
auto_ptr<ManagementNode> sourceNode(config.getManagementNode(sourcePath.c_str()));
sourceNode->setPropertyValue("last", "0");
protected:
/*
* tweak the base class in two ways:
* - continue to use the "syncml" node for all non-source properties, as in previous versions
* - do not save properties which cannot be configured
*/
virtual int readAuthConfig(ManagementNode& syncMLNode,
ManagementNode& authNode) {
return DMTClientConfig::readAuthConfig(syncMLNode, syncMLNode);
}
}
#endif
if (res) {
if (lastErrorCode && lastErrorMsg[0]) {
throw runtime_error(lastErrorMsg);
virtual void saveAuthConfig(ManagementNode& syncMLNode,
ManagementNode& authNode) {
DMTClientConfig::saveAuthConfig(syncMLNode, syncMLNode);
}
// no error code/description?!
throw runtime_error("sync failed without an error description, check log");
}
// all went well: print final report before cleaning up
m_sourceList->syncDone(true);
m_sourceList = NULL;
}
int EvolutionSyncClient::prepareSync(const AccessConfig &config,
ManagementNode &node)
{
try {
// remember for use by sync sources
m_url = config.getSyncURL() ? config.getSyncURL() : "";
if (!m_url.size()) {
LOG.error("no syncURL configured - perhaps the server name \"%s\" is wrong?",
m_server.c_str());
throw runtime_error("cannot proceed without configuration");
virtual int readConnConfig(ManagementNode& syncMLNode,
ManagementNode& connNode) {
return DMTClientConfig::readConnConfig(syncMLNode, syncMLNode);
}
virtual void saveConnConfig(ManagementNode& syncMLNode,
ManagementNode& connNode) {
DMTClientConfig::saveConnConfig(syncMLNode, syncMLNode);
}
virtual int readExtAccessConfig(ManagementNode& syncMLNode,
ManagementNode& extNode) {
return DMTClientConfig::readExtAccessConfig(syncMLNode, syncMLNode);
}
virtual void saveExtAccessConfig(ManagementNode& syncMLNode,
ManagementNode& extNode) {
DMTClientConfig::saveExtAccessConfig(syncMLNode, syncMLNode);
}
virtual int readDevInfoConfig(ManagementNode& syncMLNode,
ManagementNode& devInfoNode) {
return DMTClientConfig::readDevInfoConfig(syncMLNode, syncMLNode);
}
virtual void saveDevInfoConfig(ManagementNode& syncMLNode,
ManagementNode& devInfoNode) {
// these properties are always set by the code, don't save them
}
virtual int readDevDetailConfig(ManagementNode& syncMLNode,
ManagementNode& devDetailNode) {
return DMTClientConfig::readDevDetailConfig(syncMLNode, syncMLNode);
}
virtual void saveDevDetailConfig(ManagementNode& syncMLNode,
ManagementNode& devDetailNode) {
// these properties are always set by the code, don't save them
}
virtual int readExtDevConfig(ManagementNode& syncMLNode,
ManagementNode& extNode) {
return DMTClientConfig::readExtDevConfig(syncMLNode, syncMLNode);
}
virtual void saveExtDevConfig(ManagementNode& syncMLNode,
ManagementNode& extNode) {
// these properties are always set by the code, don't save them
}
// redirect logging as soon as possible
m_sourceList = new SourceList(m_server, m_doLogging);
m_sourceList->setLogdir(node.getPropertyValue("logdir"),
atoi(node.getPropertyValue("maxlogdirs")));
} catch(...) {
EvolutionSyncSource::handleException();
return ERR_UNSPECIFIED;
virtual void saveSourceConfig(int i,
ManagementNode& sourcesNode,
ManagementNode& sourceNode) {
// no, don't overwrite config, in particular not the "type"
}
} config(m_configPath.c_str());
if (!config.read() || !config.open()) {
throw runtime_error("reading configuration failed");
}
return ERR_NONE;
}
// remember for use by sync sources
string url = config.getAccessConfig().getSyncURL() ? config.getAccessConfig().getSyncURL() : "";
int EvolutionSyncClient::createSyncSource(const char *name,
const SyncSourceConfig &config,
ManagementNode &node,
SyncSource **source)
{
try {
// by default no source for this name
*source = NULL;
if (!url.size()) {
LOG.error("no syncURL configured - perhaps the server name \"%s\" is wrong?",
m_server.c_str());
throw runtime_error("cannot proceed without configuration");
}
// redirect logging as soon as possible
SourceList sourceList(m_server, m_doLogging);
sourceList.setLogdir(config.getSyncMLNode()->getPropertyValue("logdir"),
atoi(config.getSyncMLNode()->getPropertyValue("maxlogdirs")));
SyncSourceConfig *sourceconfigs = config.getSyncSourceConfigs();
for (int index = 0; index < config.getNumSources(); index++) {
ManagementNode &node(*config.getSyncSourceNode(index));
SyncSourceConfig &sc(sourceconfigs[index]);
// is the source enabled?
string sync = config.getSync() ? config.getSync() : "";
string sync = sc.getSync() ? sc.getSync() : "";
bool enabled = sync != "none";
SyncMode overrideMode = SYNC_NONE;
// override state?
if (m_sources.size()) {
if (m_sources.find(name) != m_sources.end()) {
if (m_sources.find(sc.getName()) != m_sources.end()) {
if (!enabled) {
overrideMode = SYNC_TWO_WAY;
enabled = true;
@ -468,23 +502,27 @@ int EvolutionSyncClient::createSyncSource(const char *name,
if (enabled) {
// create it
string type = config.getType() ? config.getType() : "";
string type = sc.getType() ? sc.getType() : "";
EvolutionSyncSource *syncSource =
EvolutionSyncSource::createSource(
name,
string("sync4jevolution:") + m_url + "/" + name,
sc.getName(),
string("sync4jevolution:") + url + "/" + sc.getName(),
EvolutionSyncSource::getPropertyValue(node, "evolutionsource"),
type
);
if (!syncSource) {
throw runtime_error(string(name) + ": type " +
throw runtime_error(string(sc.getName()) + ": type " +
( type.size() ? string("not configured") :
string("'") + type + "' empty or unknown" ));
}
m_sourceList->push_back(syncSource);
sourceList.push_back(syncSource);
// configure it: type must be a valid mime type in the backend
// storage because SyncManager will overwrite the source's settings
sc.setType(syncSource->getMimeType());
sc.setVersion(syncSource->getMimeVersion());
syncSource->setConfig(sc);
// configure it
syncSource->setConfig(config);
if (m_syncMode != SYNC_NONE) {
// caller overrides mode
syncSource->setPreferredSyncMode(m_syncMode);
@ -497,28 +535,39 @@ int EvolutionSyncClient::createSyncSource(const char *name,
syncSource->setAuthentication(user, passwd);
// also open it; failing now is still safe
syncSource->open();
// success!
*source = syncSource;
syncSource->open();
}
} catch(...) {
EvolutionSyncSource::handleException();
return ERR_UNSPECIFIED;
}
return ERR_NONE;
}
int EvolutionSyncClient::beginSync()
{
try {
// ready to go: dump initial databases and prepare for final report
m_sourceList->syncPrepare();
} catch(...) {
EvolutionSyncSource::handleException();
return ERR_UNSPECIFIED;
}
return ERR_NONE;
// reconfigure with our fixed properties
DeviceConfig &dc(config.getDeviceConfig());
dc.setMod("SyncEvolution");
dc.setSwv(VERSION);
dc.setMan("Patrick Ohly");
dc.setDevType("workstation");
dc.setUtc(1);
dc.setOem("Open Source");
dc.setFwv("unknown");
dc.setHwv("unknown");
dc.setDevID("unknown");
// ready to go: dump initial databases and prepare for final report
sourceList.syncPrepare();
// do it
int res = SyncClient::sync(config, sourceList.getSourceArray());
if (res) {
if (lastErrorCode && lastErrorMsg[0]) {
throw runtime_error(lastErrorMsg);
}
// no error code/description?!
throw runtime_error("sync failed without an error description, check log");
}
// store modified properties
config.save();
// all went well: print final report before cleaning up
sourceList.syncDone(true);
}

View File

@ -20,37 +20,26 @@
#define INCL_EVOLUTIONSYNCCLIENT
#include <config.h>
#include <common/client/Sync4jClient.h>
#include "EvolutionSmartPtr.h"
#include <client/SyncClient.h>
#include <string>
#include <set>
using namespace std;
class SourceList;
/*
* This is the main class inside sync4jevolution which
* looks at the configuration, activates all enabled
* sources and executes the synchronization.
*
*/
class EvolutionSyncClient : private SyncClient {
class EvolutionSyncClient : public SyncClient {
const string m_server;
const set<string> m_sources;
const SyncMode m_syncMode;
const bool m_doLogging;
const string m_configPath;
string m_url;
/*
* Variable shared by sync() and prepareSync():
* stores active sync sources and handles reporting.
* Not a smart pointer to avoid the need to make SourceList
* public.
*/
eptr<SourceList> m_sourceList;
public:
/**
@ -69,26 +58,6 @@ class EvolutionSyncClient : private SyncClient {
* Handles automatic backups and report generation.
*/
int sync();
/**************************************************/
/************ override SyncClient interface *******/
/**************************************************/
const char *getClientID() const { return "SyncEvolution"; }
const char *getClientVersion() const { return VERSION; }
const char *getManufacturer() const { return "Patrick Ohly"; }
const char *getClientType() const { return "workstation"; }
int isUTC() const { return true; }
protected:
/* Sync4jClient callbacks */
int prepareSync(const AccessConfig &config,
ManagementNode &node);
int createSyncSource(const char *name,
const SyncSourceConfig &config,
ManagementNode &node,
SyncSource **source);
int beginSync();
};
#endif // INCL_EVOLUTIONSYNCCLIENT

View File

@ -145,6 +145,16 @@ class EvolutionSyncSource : public SyncSource
*/
virtual string fileSuffix() = 0;
/**
* the actual type used by the source for items
*/
virtual const char *getMimeType() = 0;
/**
* the actual version of the mime specification
*/
virtual const char *getMimeVersion() = 0;
/**
* resets the lists of all/new/updated/deleted items
*/
@ -292,9 +302,7 @@ class EvolutionSyncSource : public SyncSource
// just tell caller the uid of the deleted item
// and the type that it probably had
SyncItem *item = new SyncItem( uid.c_str() );
const char *recvType, *recvVersion, *sendType, *sendVersion;
m_source.getPreferredTypes( recvType, recvVersion, sendType, sendVersion );
item->setDataType( sendType );
item->setDataType(m_source.getMimeType());
return item;
} else {
// retrieve item with all its data