Yes, you can help. Given the lack of documentation for writing plugins (at least none that I could find) I have had to make a few educated guesses about plugin behaviour.
I have taken the time to write up my "findings" as a how-to document. However, parts of it could be mistaken. So I'd like the multi-sync dev team to review my document and make comments. This has two benefits: (1) I get assurance my plugin is designed correctly (or not). (2) the multisync project gains a peer-reviewed how-to document. The document is attached. Stewart On Sat, 1 May 2004 06:27 am, Tom Foottit wrote: > Ok, please let us know if we can help. If you can get things into a > useable state we can arrange putting the plugin into our CVS tree, etc. > > Also a reminder if you are using our CVS then do your development off of > branch_08X. > > Tom > > On Tue, 2004-04-27 at 03:04, Stewart Heitmann wrote: > > OK, I'll keep working on my KDE plugin then. > > I'll post a follow up to multisync-devel when I get > > it into a useful state. > > > > As for the Gnome framework, I can live with that. > > I have already had some success talking to the KDE > > addressbook back-end from within a Multisync plugin. > > So I think the two should work together ok. > > > > As for kitchensync, I tried it once but couldnt get it > > to compile on my system (FreeBSD) so I gave up. > > Then I tried multisync, and it worked fine. > > Hence my preference for multisync. > > > > Stewart > > > > On Tue, 27 Apr 2004 10:41 am, Tom Foottit wrote: > > > Nobody is working on a KDE PIM plugin currently. > > > > > > Multisync has a lot of Gnome dependencies in its current incarnation. > > > Work on a new version (0.90) will break the UI and sync engine > > > dependencies, but that is some time away. In the meantime you would > > > have to live in the Gnome framework. > > > > > > You should be aware of Kitchensync as well, which is a KDE project > > > similar to Mulitsync. > > > > > > Tom > > > > > > On Fri, 2004-04-23 at 02:12, Stewart Heitmann wrote: > > > > I just discovered multisync recently and was impressed > > > > by the application, but dismayed by its lack of a KDE plugin. > > > > > > > > I really want to use it to sync my KDE addresss book to > > > > my mobile phone (Siemens ME45). > > > > So I am considering writing a KDE plugin myself. > > > > Before I get too far into it I'd like to know if anybody else > > > > is working on a KDE plugin at the moment? > > > > I'd prefer to avoid duplication of effort.
Multisync Plugin How-to ----------------------- The Multisync sync-engine manages the comparison and merging of PIM objects (VCARDS, VCALENDARS, etc) between pairs of external devices and/or applications that each contain an internal store of PIM entries. The internal stores are referred to as "databases", and the external devices and applications are collectively termed as "devices". Each pair of devices being synchronized is known as a "sync pair", and a single device may belong to multiple sync pairs simultaneously. About plugins ------------- Every type of "device" requires its own multisync plugin to act as interface between the sync-engine and the device's internal PIM database. Note that each plugin may be required to service multiple instances of identical devices or even multiple instance of the same physical device so it should not rely on global static data in its implementation. About UIDs ---------- Each device usually (but not always) assigns a unique identifier (UID) for each object in its database. The sync-engine uses these UIDs to match PIM objects during the synchronization process. If the device does not natively support UIDs then the multisync plugin should generate a UID for each database object as it deems fit. The sync-engine maintains its own internal mappings of the UIDs between the plugins of each sync pair. It ensures that each plugin is only ever presented with its own UIDs (not the UIDs of other plugins). The only exception is for new PIM objects, which the sync-engine presents to the plugin with a NULL UID. The plugin is expected to assign its own UID to these objects and report the new UID back to the sync-engine. In short, the sync-engine isolates the plugin from issues of UID uniqueness across devices. Plugin data structure --------------------- Each plugin defines a struct of the form: typedef struct { client_connection commondata; <private data goes here> } myplugin_connection; This structure is returned by the plugin's sync_connect() function which is called by the sync-engine whenever the device is added to a new sync-pair (or whenever a device in a sync-pair is re-connected). It must be allocated using g_malloc() as the sync-engine will use g_free() to de-allocate it later. The sync-engine expects the "client_connection" data member to be the first element of the struct so be sure not to put anything before it. The rest of the struct should be used to store all data pertinent to this instance of the plugin. The sync-engine will pass a pointer to this structure in all subsequent callbacks to the plugin. For instance, some of the more interesting callbacks are: void sync_disconnect(myplugin_connection *conn); void get_changes(myplugin_connection *conn, sync_object_type newdbs); void syncobj_modify_list(myplugin_connection *conn, GList *changes); void sync_done(myplugin_connection *conn, gboolean success); Note the "myplugin_connection *conn" parameters are actually passed by the sync-engine as "void *" but we pre-cast them in the function declarations for our own convenience. See the plugin-API.c file supplied with multisync for the full list of plugin callbacks. The get_changes() callback -------------------------- When the sync-engine wishes to synchronize the devices of a sync-pair, it first calls the get_changes() callback of each plugin to ascertain which objects in the device's database have been altered. void get_changes(myplugin_connection *conn, sync_object_type newdbs); The plugin should respond with a list containing copies of those database objects that have been modified, added, or deleted since the last time the database was synchronized. That is, since the last time the sync-engine called the plugin's sync_done() callback. Alternatively, the sync-engine will set the appropriate bit (SYNC_OBJECT_TYPE_CALENDAR, SYNC_OBJECT_TYPE_PHONEBOOK, SYNC_OBJECT_TYPE_TODO) in the "newdbs" parameter if it wishes the plugin to return all objects in its database rather than only those that have changed. This will happen when the other device in the sync-pair has lost all of its data and needs to be refreshed from scratch. The list of changes must be accumulated as GList of changed_object structs typedef struct { char *comp; // The PIM object data in VCARD or VCALENDAR string format. char *uid; // The plugins unique ID for this PIM object. char *removepriority; // Word to sort on for removal when database is full. int change_type; // One of SYNC_OBJ_MODIFIED, SYNC_OBJ_ADDED, etc sync_object_type object_type; //The data type of this object } changed_object; each one allocated with g_malloc(). Furthermore, this list must be encapsulated in a change_info struct, which incidentally must also be allocated using g_malloc(). typedef struct { GList *changes; // List of changed_object's sync_object_type newdbs; // Set the bit for the corresponding type // if the database is not recognized or has been reset. } change_info; Once the change_info structure is complete, it is returned to the sync-engine using sync_set_requestdata() function. When constructing changed_object structs for ADDED and MODIFIED database objects, the "changed_object.comp" data member should point to a newly gmalloc'ed string containing the data for the object. The sync-engine uses this data when comparing and merging modified objects from either device in the sync-pair. The string should be formatted as a VCARD or VCALENDAR string as appropriate to its object type. For example, a vcard would appear as "BEGIN:VCARD\nEMAIL;TYPE=PREF:[EMAIL PROTECTED]:Foo Bar\nN:Bar;Foo;;;\n VERSION:3.0\nEND:VCARD\n" Objects marked as DELETE however may have "changed_object.comp" set to NULL. The "changed_object.uid" data member should always point to a newly gmalloc'ed string containing the UID assigned to that object by the device. This is regardless of whether the object is marked as ADDED, MODIFIED, or DELETE. QUESTION TO THE MULTI-SYNC DEVELOPMENT TEAM: How can a plugin know the state (MODIFIED,ADDED,DELETED) of each object on the device unless the plugin keeps its own persistent record of each object stored on the device at the time of the previous synchronisation? The device's per-object revision dates (if it supports them) can only assist with identifying MODIFIED and ADDED records but they can never identify DELETED records because they don't exist anymore! The only way is if each plugin maintains its own persistent database of the objects stored on the device (or their UIDs at very least). Is this true or have I misunderstood? If true, it seems a rather onerous task to expect of each plugin developer. Especially since it is a job which could be easily done by the sync engine as it already maintains persistent stores of the UIDs in each syncpair's ids file. The syncobj_modify_list() callback ---------------------------------- Once the sync-engine has determined the differences between the two devices of a sync pair it calls syncobj_modify_list() with a list of changes for the plugin to replicate on the device. void syncobj_modify_list(kdepim_connection *conn, GList *changes) Each item in the "changes" list is a "changed_object" struct (as seen above). As the plugin applies these changes to the device it should accumulate a list of "syncobj_modify_result" structs in which to record the success of each change. This list is returned to the sync-engine with the sync_set_requestdata() function upon completion of all modifications. typedef struct { sync_msg_type result; // The result of the operation char *returnuid; // Returns UID for a new entry as a gmalloc'ed string. } syncobj_modify_result; Each object in the "changes" list whose "change_type" is SYNC_OBJ_HARDDELETED or SYNC_OBJ_SOFTDELETED can simply be deleted from the device. For those objects whose "change_type" is SYNC_OBJ_MODIFIED, the corresponding object (according to UID) on the device should have their contents replaced with the contents of the changed_object's "comp" string. Similarly, those objects whose "change_type" is SYNC_OBJ_ADDED use the data in the "comp" string as the new record, however in this case the device will generate a UID for the new object. The plugin should inform the sync-engine of the new UID by returning a gmalloc'ed copy of it in the changed_object's "returnuid" variable. The "returnuid" variable should be set to NULL for other types of changes.