/* * Copyright (C) 2008 Patrick Ohly */ #ifndef INCL_TRACKINGSYNCSOURCE #define INCL_TRACKINGSYNCSOURCE #include "EvolutionSyncSource.h" #include "ConfigNode.h" #include #include #include using namespace std; /** * This class implements change tracking. Data sources which want to use * this functionality have to provide the following functionality * by implementing the pure virtual functions below: * - open() the data * - enumerate all existing items * - provide UID and "revision string": * The UID must remain *constant* when the user edits an item (it * may change when SyncEvolution changes an item), whereas the * revision string must *change* each time the item is changed * by anyone. * Both can be arbitrary strings, but keeping them simple (printable * ASCII, no white spaces, no equal sign) makes debugging simpler * because they can be stored as they are as key/value pairs in the * sync source's change tracking config node (the .other.ini files when * using file-based configuration). More complex strings use escape * sequences introduced with an exclamation mark for unsafe characters. * - import/export/update single items * - persistently store all changes in flush() * - clean up in close() * * A derived class may (but doesn't have to) override additional * functions to modify or replace the default implementations, e.g.: * - dumping the complete database (export()) * * Potential implementations of the revision string are: * - a modification time stamp * - a hash value of a textual representation of the item * (beware, such a hash might change as the textual representation * changes even though the item is unchanged) */ class TrackingSyncSource : public EvolutionSyncSource { public: /** * Creates a new tracking sync source. */ TrackingSyncSource(const EvolutionSyncSourceParams ¶ms); /** * returns a list of all know sources for the kind of items * supported by this sync source */ virtual Databases getDatabases() = 0; /** * Actually opens the data source specified in the constructor, * will throw the normal exceptions if that fails. Should * not modify the state of the sync source: that can be deferred * until the server is also ready and beginSync() is called. */ virtual void open() = 0; /** * exports all items one after the other, separated by blank line; * if that format is not suitable, then the derived class must * override this call */ virtual void exportData(ostream &out); typedef map RevisionMap_t; /** * fills the complete mapping from UID to revision string of all * currently existing items * * Usually both UID and revision string must be non-empty. The * only exception is a refresh-from-client: in that case the * revision string may be empty. The implementor of this call * cannot know whether empty strings are allowed, therefore it * should not throw errors when it cannot create a non-empty * string. The caller of this method will detect situations where * a non-empty string is necessary and none was provided. */ virtual void listAllItems(RevisionMap_t &revisions) = 0; class InsertItemResult { public: /** * @param uid the uid after the operation; during an update the uid must * not be changed, so return the original one here * @param revision the revision string after the operation * @param merged set this to true if an existing item was updated instead of adding it */ InsertItemResult(const string &uid, const string &revision, bool merged) : m_uid(uid), m_revision(revision), m_merged(merged) {} const string m_uid; const string m_revision; const bool m_merged; }; /** * Create or modify an item. * * The sync source should be flexible: if the UID is non-empty, it * shall modify the item referenced by the UID. If the UID is * empty, the normal operation is to add it. But if the item * already exists (e.g., a calendar event which was imported * by the user manually), then the existing item should be * updated also in the second case. * * Passing a UID of an item which does not exist is an error. * This error should be reported instead of covering it up by * (re)creating the item. * * Errors are signalled by throwing an exception. Returning empty * strings in the result is an error which triggers an "item could * not be stored" error. * * @param uid identifies the item to be modified, empty for creating * @param item contains the new content of the item and its MIME type * @return the result of inserting the item */ virtual InsertItemResult insertItem(const string &uid, const SyncItem &item) = 0; /** * Extract information for the item identified by UID * and store it in a new SyncItem. The caller must * free that item. May throw exceptions. * * @param uid identifies the item */ virtual SyncItem *createItem(const string &uid) = 0; /** * removes and item */ virtual void deleteItem(const string &uid) = 0; /** * optional: write all changes, throw error if that fails * * This is called while the sync is still active whereas * close() is called afterwards. Reporting problems * as early as possible may be useful at some point, * but currently doesn't make a relevant difference. */ virtual void flush() {} /** * closes the data source so that it can be reopened * * Just as open() it should not affect the state of * the database unless some previous action requires * it. */ virtual void close() = 0; /** * file suffix for database files */ virtual string fileSuffix() const = 0; /** * Returns the preferred mime type of the items handled by the sync source. * Example: "text/x-vcard" */ virtual const char *getMimeType() const = 0; /** * Returns the version of the mime type used by client. * Example: "2.1" */ virtual const char *getMimeVersion() const = 0; /** * A string representing the source types (with versions) supported by the SyncSource. * The string must be formatted as a sequence of "type:version" separated by commas ','. * For example: "text/x-vcard:2.1,text/vcard:3.0". * The version can be left empty, for example: "text/x-s4j-sifc:". * Supported types will be sent as part of the DevInf. */ virtual const char* getSupportedTypes() const = 0; protected: /** log a one-line info about an item */ virtual void logItem(const string &uid, const string &info, bool debug = false) = 0; virtual void logItem(const SyncItem &item, const string &info, bool debug = false) = 0; virtual void setItemStatusThrow(const char *key, int status); private: /* implementations of EvolutionSyncSource callbacks */ virtual void beginSyncThrow(bool needAll, bool needPartial, bool deleteLocal); virtual void endSyncThrow(); virtual int addItemThrow(SyncItem& item); virtual int updateItemThrow(SyncItem& item); virtual int deleteItemThrow(SyncItem& item); boost::shared_ptr m_trackingNode; }; #endif // INCL_TRACKINGSYNCSOURCE