Revert "os4x: undo run-as-process setting, due to sync timeouts"
[barry.git] / opensync-plugin-0.4x / src / barry_sync.cc
blobd1434bdbef89bdfa7b9a3bba6b9571c05a445cd8
1 //
2 // \file barry_sync.cc
3 // Opensync module for the USB Blackberry handheld
4 //
6 /*
7 Copyright (C) 2009, Nicolas VIVIEN (opensync plugin porting on opensync 0.4x ; Task & Memo support)
8 Copyright (C) 2006-2010, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include <opensync/opensync.h>
24 #include <opensync/opensync-data.h>
25 #include <opensync/opensync-format.h>
26 #include <opensync/opensync-plugin.h>
27 #include <opensync/opensync-helper.h>
28 #include <opensync/opensync-version.h>
30 #include <barry/barry.h>
31 #include <barry/dll.h>
32 #include "barry_sync.h"
33 #include "environment.h"
34 #include "vtodo.h"
35 #include "vjournal.h"
36 #include "vevent.h"
37 #include "vcard.h"
38 #include "trace.h"
39 #include <string>
40 #include <glib.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <errno.h>
45 typedef Barry::vSmartPtr<OSyncList, OSyncList, &osync_list_free> AutoOSyncList;
47 // All functions that are callable from outside must look like C
48 extern "C" {
49 BXEXPORT int get_version(void);
50 static void *initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error);
51 static osync_bool discover(OSyncPluginInfo *info, void *userdata, OSyncError **error);
53 static void contact_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata);
54 static void contact_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
56 static void event_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata);
57 static void event_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
59 static void journal_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata);
60 static void journal_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
62 static void todo_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata);
63 static void todo_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
65 static void connect(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
66 static void disconnect(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata);
67 static void commit_change(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *change, void *userdata);
68 static void finalize(void *userdata);
69 BXEXPORT osync_bool get_sync_info(OSyncPluginEnv *env, OSyncError **error);
74 //////////////////////////////////////////////////////////////////////////////
76 // Support functions and classes
79 // Generates a "hash" by grabbing the existing hash
80 // of the given uid, and adding 1 to it if dirty.
81 std::string GenerateHash(OSyncHashTable *hashtable,
82 const std::string &uid,
83 bool dirty)
85 unsigned long hashcount = 0;
87 const char *hash = osync_hashtable_get_hash(hashtable, uid.c_str());
88 if( hash ) {
89 errno = 0;
90 hashcount = strtoul(hash, NULL, 10);
91 if( errno )
92 throw std::runtime_error("Error converting string to unsigned long: " + std::string(hash));
95 hashcount += (dirty ? 1 : 0);
97 std::ostringstream oss;
98 oss << std::dec << hashcount;
99 return oss.str();
102 void GetChanges(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx,
103 BarryEnvironment *env,
104 DatabaseSyncState *pSync,
105 const char *DBDBName,
106 const char *ObjTypeName, const char *FormatName,
107 GetData_t getdata,
108 osync_bool slow_sync)
110 Trace trace("GetChanges");
112 OSyncError *error = NULL;
114 // shortcut references
115 using namespace Barry;
116 using Barry::RecordStateTable;
117 Mode::Desktop &desktop = *env->m_pDesktop;
119 // find hash table
121 // Note: Since the Blackberry tracks dirty flags for us, we don't
122 // need the hash table to help determine what records have
123 // changed, and therefore we don't need to actually load
124 // all the record data across USB either.
126 // The hashtable only needs the hash to change when data
127 // has changed, so we set each change object's hash to:
128 // last_hash + (dirty ? 1 : 0)
130 OSyncHashTable *hashtable = osync_objtype_sink_get_hashtable(sink);
132 // check if slow sync has been requested
133 if (slow_sync) {
134 trace.log("GetChanges: slow sync request detected");
136 if( !osync_hashtable_slowsync(hashtable, &error) ) {
137 std::ostringstream oss;
138 oss << "GetChanges: slow sync error: " << osync_error_print(&error);
139 osync_error_unref(&error);
141 trace.log(oss.str().c_str());
142 throw std::runtime_error(oss.str());
146 // fetch state table
147 unsigned int dbId = desktop.GetDBID(DBDBName);
148 RecordStateTable &table = pSync->m_Table;
149 desktop.GetRecordStateTable(dbId, table);
151 OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
154 // cycle through the state table... for each record in the state
155 // table, register a change and the fake hash (see note above)
156 // and let the hash table determine what changetype it is
157 RecordStateTable::StateMapType::const_iterator i = table.StateMap.begin();
158 for( ; i != table.StateMap.end(); ++i ) {
160 OSyncChange *change = 0;
161 const RecordStateTable::IndexType &index = i->first;
162 const RecordStateTable::State &state = i->second;
164 // create change to pass to hashtable
165 change = osync_change_new(&error);
166 if( !change ) {
167 osync_context_report_osyncwarning(ctx, error);
168 osync_error_unref(&error);
169 continue;
172 // convert record ID to uid string
173 std::string uid = pSync->Map2Uid(state.RecordId);
175 // setup change, just enough for hashtable use
176 osync_change_set_uid(change, uid.c_str());
177 trace.logf("change record ID: %s", uid.c_str());
178 std::string hash = GenerateHash(hashtable, uid, state.Dirty);
179 osync_change_set_hash(change, hash.c_str());
182 // let hashtable determine what's going to happen
183 OSyncChangeType changetype = osync_hashtable_get_changetype(hashtable, change);
184 osync_change_set_changetype(change, changetype);
186 // let hashtable know we've processed this change
187 osync_hashtable_update_change(hashtable, change);
190 // Decision time: if nothing has changed, skip
191 if( changetype == OSYNC_CHANGE_TYPE_UNMODIFIED ) {
192 osync_change_unref(change);
193 continue;
198 // finish filling out the change object
201 // Now you can set the data for the object
202 // Set the last argument to FALSE if the real data
203 // should be queried later in a "get_data" function
204 OSyncObjFormat *format = osync_format_env_find_objformat(formatenv, FormatName);
205 char *data = (*getdata)(env, dbId, index);
206 OSyncData *odata = osync_data_new(data, strlen(data), format, &error);
208 if (!odata) {
209 osync_change_unref(change);
210 osync_context_report_osyncwarning(ctx, error);
211 osync_error_unref(&error);
212 continue;
215 // FIXME ? Is this line is usefull ?
216 // osync_data_set_objtype(odata, osync_objtype_sink_get_name(sink));
218 osync_change_set_data(change, odata);
219 osync_data_unref(odata);
221 // just report the change via
222 osync_context_report_change(ctx, change);
224 osync_change_unref(change);
227 // the hashtable can now give us a linked list of deleted
228 // entries, after the above processing
229 AutoOSyncList uids = osync_hashtable_get_deleted(hashtable);
230 for( OSyncList *u = uids.Get(); u; u = u->next) {
232 const char *uid = (const char*) u->data;
233 uint32_t recordId = strtoul(uid, NULL, 10);
235 // search the state table
236 i = table.StateMap.begin();
237 for( ; i != table.StateMap.end(); ++i ) {
239 if( i->second.RecordId == recordId ) {
240 throw std::runtime_error("Found deleted record ID in state map! " + std::string(uid));
244 // register a DELETE, no data
245 trace.log("found DELETE change");
247 OSyncChange *change = osync_change_new(&error);
248 if( !change ) {
249 osync_context_report_osyncwarning(ctx, error);
250 osync_error_unref(&error);
251 continue;
254 osync_change_set_uid(change, uid);
255 trace.log(uid);
256 osync_change_set_changetype(change, OSYNC_CHANGE_TYPE_DELETED);
258 // osync_change_set_objformat_string(change, FormatName);
260 OSyncObjFormat *format = osync_format_env_find_objformat(formatenv, FormatName);
261 OSyncData *odata = osync_data_new(NULL, 0, format, &error);
262 if( !odata ) {
263 osync_change_unref(change);
264 osync_context_report_osyncwarning(ctx, error);
265 osync_error_unref(&error);
266 continue;
269 osync_data_set_objtype(odata, osync_objtype_sink_get_name(sink));
271 osync_change_set_data(change, odata);
272 osync_data_unref(odata);
274 // report the change
275 osync_context_report_change(ctx, change);
277 // tell hashtable we've processed this item
278 osync_hashtable_update_change(hashtable, change);
280 osync_change_unref(change);
284 CommitData_t GetCommitFunction(OSyncChange *change)
286 Trace trace("GetCommitFunction()");
288 const char *name = osync_change_get_objtype(change);
290 if( strcmp(name, "event") == 0 ) {
291 return &VEventConverter::CommitRecordData;
293 else if( strcmp(name, "contact") == 0 ) {
294 return &VCardConverter::CommitRecordData;
296 else if( strcmp(name, "note") == 0 ) {
297 return &VJournalConverter::CommitRecordData;
299 else if( strcmp(name, "todo") == 0 ) {
300 return &VTodoConverter::CommitRecordData;
302 else {
303 trace.log("unknown !");
304 trace.log(name);
306 return 0;
310 bool FinishSync(OSyncContext *ctx, BarryEnvironment *env, DatabaseSyncState *pSync)
312 Trace trace("FinishSync()");
314 if( !pSync->m_Sync ) {
315 // this mode is disabled in config, skip
316 return true;
319 Barry::Mode::Desktop &desktop = *env->m_pDesktop;
321 // get the state table again, so we can update
322 // the cache properly
323 desktop.GetRecordStateTable(pSync->m_dbId, pSync->m_Table);
325 // clear all dirty flags in device
326 env->ClearDirtyFlags(pSync->m_Table, pSync->m_dbName);
327 return true;
331 static bool barry_contact_initialize(BarryEnvironment *env, OSyncPluginInfo *info, OSyncError **error)
333 Trace trace("contact initialize");
335 OSyncObjTypeSink *sink = osync_plugin_info_find_objtype(info, "contact");
336 if (!sink)
337 return false;
338 osync_bool sinkEnabled = osync_objtype_sink_is_enabled(sink);
339 if (!sinkEnabled)
340 return false;
342 trace.log("contact enabled");
344 osync_objtype_sink_set_connect_func(sink, connect);
345 osync_objtype_sink_set_disconnect_func(sink, disconnect);
346 osync_objtype_sink_set_get_changes_func(sink, contact_get_changes);
347 osync_objtype_sink_set_commit_func(sink, commit_change);
348 osync_objtype_sink_set_sync_done_func(sink, contact_sync_done);
350 OSyncPluginConfig *config = osync_plugin_info_get_config(info);
351 OSyncPluginResource *resource = osync_plugin_config_find_active_resource(config, "contact");
353 AutoOSyncList objformatsinks = osync_plugin_resource_get_objformat_sinks(resource);
355 bool hasObjFormat = false;
357 OSyncList *r;
358 for(r = objformatsinks.Get();r;r = r->next) {
359 OSyncObjFormatSink *objformatsink = (OSyncObjFormatSink *) r->data;
361 if(!strcmp("vcard30", osync_objformat_sink_get_objformat(objformatsink))) {
362 trace.log("vcard30 found in barry-sync");
363 hasObjFormat = true;
364 break;
368 if (!hasObjFormat) {
369 return false;
372 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
374 // env->format = osync_format_env_find_objformat(formatenv, "vcard30");
375 env->m_ContactsSync.sink = sink;
377 osync_objtype_sink_set_userdata(sink, env);
379 osync_objtype_sink_enable_hashtable(sink, TRUE);
381 trace.log("contact initialize OK");
383 return true;
387 static bool barry_calendar_initialize(BarryEnvironment *env, OSyncPluginInfo *info, OSyncError **error)
389 Trace trace("calendar initialize");
391 OSyncObjTypeSink *sink = osync_plugin_info_find_objtype(info, "event");
392 if (!sink)
393 return false;
394 osync_bool sinkEnabled = osync_objtype_sink_is_enabled(sink);
395 if (!sinkEnabled)
396 return false;
398 trace.log("calendar enabled");
400 osync_objtype_sink_set_connect_func(sink, connect);
401 osync_objtype_sink_set_disconnect_func(sink, disconnect);
402 osync_objtype_sink_set_get_changes_func(sink, event_get_changes);
403 osync_objtype_sink_set_commit_func(sink, commit_change);
404 osync_objtype_sink_set_sync_done_func(sink, event_sync_done);
406 OSyncPluginConfig *config = osync_plugin_info_get_config(info);
407 OSyncPluginResource *resource = osync_plugin_config_find_active_resource(config, "event");
409 AutoOSyncList objformatsinks = osync_plugin_resource_get_objformat_sinks(resource);
411 bool hasObjFormat = false;
413 OSyncList *r;
414 for(r = objformatsinks.Get();r;r = r->next) {
415 OSyncObjFormatSink *objformatsink = (OSyncObjFormatSink *) r->data;
417 if(!strcmp("vevent20", osync_objformat_sink_get_objformat(objformatsink))) {
418 hasObjFormat = true;
419 break;
423 if (!hasObjFormat) {
424 return false;
427 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
429 // env->format = osync_format_env_find_objformat(formatenv, "vevent20");
430 env->m_CalendarSync.sink = sink;
432 osync_objtype_sink_set_userdata(sink, env);
434 osync_objtype_sink_enable_hashtable(sink, TRUE);
436 return true;
440 static bool barry_journal_initialize(BarryEnvironment *env, OSyncPluginInfo *info, OSyncError **error)
442 Trace trace("journal initialize");
444 OSyncObjTypeSink *sink = osync_plugin_info_find_objtype(info, "note");
445 if (!sink)
446 return false;
447 osync_bool sinkEnabled = osync_objtype_sink_is_enabled(sink);
448 if (!sinkEnabled)
449 return false;
451 trace.log("journal enabled");
453 osync_objtype_sink_set_connect_func(sink, connect);
454 osync_objtype_sink_set_disconnect_func(sink, disconnect);
455 osync_objtype_sink_set_get_changes_func(sink, journal_get_changes);
456 osync_objtype_sink_set_commit_func(sink, commit_change);
457 osync_objtype_sink_set_sync_done_func(sink, journal_sync_done);
459 OSyncPluginConfig *config = osync_plugin_info_get_config(info);
460 OSyncPluginResource *resource = osync_plugin_config_find_active_resource(config, "note");
462 AutoOSyncList objformatsinks = osync_plugin_resource_get_objformat_sinks(resource);
464 bool hasObjFormat = false;
466 OSyncList *r;
467 for(r = objformatsinks.Get();r;r = r->next) {
468 OSyncObjFormatSink *objformatsink = (OSyncObjFormatSink *) r->data;
470 if(!strcmp("vjournal", osync_objformat_sink_get_objformat(objformatsink))) {
471 hasObjFormat = true;
472 break;
476 if (!hasObjFormat) {
477 return false;
480 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
482 // env->format = osync_format_env_find_objformat(formatenv, "vjournal");
483 env->m_JournalSync.sink = sink;
485 osync_objtype_sink_set_userdata(sink, env);
487 osync_objtype_sink_enable_hashtable(sink, TRUE);
489 return true;
493 static bool barry_todo_initialize(BarryEnvironment *env, OSyncPluginInfo *info, OSyncError **error)
495 Trace trace("todo initialize");
497 OSyncObjTypeSink *sink = osync_plugin_info_find_objtype(info, "todo");
498 if (!sink)
499 return false;
500 osync_bool sinkEnabled = osync_objtype_sink_is_enabled(sink);
501 if (!sinkEnabled)
502 return false;
504 trace.log("todo enabled");
506 osync_objtype_sink_set_connect_func(sink, connect);
507 osync_objtype_sink_set_disconnect_func(sink, disconnect);
508 osync_objtype_sink_set_get_changes_func(sink, todo_get_changes);
509 osync_objtype_sink_set_commit_func(sink, commit_change);
510 osync_objtype_sink_set_sync_done_func(sink, todo_sync_done);
512 OSyncPluginConfig *config = osync_plugin_info_get_config(info);
513 OSyncPluginResource *resource = osync_plugin_config_find_active_resource(config, "todo");
515 AutoOSyncList objformatsinks = osync_plugin_resource_get_objformat_sinks(resource);
517 bool hasObjFormat = false;
519 OSyncList *r;
520 for(r = objformatsinks.Get();r;r = r->next) {
521 OSyncObjFormatSink *objformatsink = (OSyncObjFormatSink *) r->data;
523 if(!strcmp("vtodo20", osync_objformat_sink_get_objformat(objformatsink))) {
524 hasObjFormat = true;
525 break;
529 if (!hasObjFormat) {
530 return false;
533 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
535 // env->format = osync_format_env_find_objformat(formatenv, "vtodo20");
536 env->m_TodoSync.sink = sink;
538 osync_objtype_sink_set_userdata(sink, env);
540 osync_objtype_sink_enable_hashtable(sink, TRUE);
542 return true;
548 //////////////////////////////////////////////////////////////////////////////
550 // OpenSync API
553 static void *initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
555 Trace trace("initialize");
557 BarryEnvironment *env = 0;
559 try {
560 env = new BarryEnvironment(info);
563 * Read plugin config
565 OSyncPluginConfig *config = osync_plugin_info_get_config(info);
567 if (!config) {
568 osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to get config.");
570 delete env;
572 return NULL;
576 * Process plugin specific advanced options
578 AutoOSyncList optslist = osync_plugin_config_get_advancedoptions(config);
579 for (OSyncList *o = optslist.Get(); o; o = o->next) {
580 OSyncPluginAdvancedOption *option = (OSyncPluginAdvancedOption *) o->data;
582 const char *val = osync_plugin_advancedoption_get_value(option);
583 const char *name = osync_plugin_advancedoption_get_name(option);
585 if (!strcmp(name, "PinCode")) {
586 env->m_pin = strtol(val, NULL, 16);
588 else if (!strcmp(name, "Debug")) {
589 env->m_DebugMode = (!strcmp(val, "1")) ? true : false;
593 OSyncPluginAuthentication *optauth = osync_plugin_config_get_authentication(config);
595 if (osync_plugin_authentication_option_is_supported(optauth, OSYNC_PLUGIN_AUTHENTICATION_PASSWORD)) {
596 const char *val = osync_plugin_authentication_get_password(optauth);
598 env->m_password = val;
602 // FIXME - near the end of release, do a run with
603 // this set to true, and look for USB protocol
604 // inefficiencies.
605 Barry::Init(env->m_DebugMode);
609 * Process Ressource options
611 trace.log("Process Ressource options...");
613 if (barry_calendar_initialize(env, info, error)) {
614 env->m_CalendarSync.m_Sync = true;
616 else {
617 trace.log("No sync Calendar");
618 env->m_CalendarSync.m_Sync = false;
621 if (barry_contact_initialize(env, info, error)) {
622 env->m_ContactsSync.m_Sync = true;
624 else {
625 trace.log("No sync Contact");
626 env->m_ContactsSync.m_Sync = false;
629 if (barry_journal_initialize(env, info, error)) {
630 env->m_JournalSync.m_Sync = true;
632 else {
633 trace.log("No sync Journal");
634 env->m_JournalSync.m_Sync = false;
637 if (barry_todo_initialize(env, info, error)) {
638 env->m_TodoSync.m_Sync = true;
640 else {
641 trace.log("No sync Todo");
642 env->m_TodoSync.m_Sync = false;
645 return (void *) env;
647 // Don't let exceptions escape to the C modules
648 catch( std::bad_alloc &ba ) {
649 trace.logf("Unable to allocate memory for controller: %s", ba.what());
650 delete env;
651 return NULL;
653 catch( std::exception &e ) {
654 trace.logf("exception: %s", e.what());
655 delete env;
656 return NULL;
661 static osync_bool discover(OSyncPluginInfo *info, void *userdata, OSyncError **error)
663 Trace trace("discover");
665 AutoOSyncList sinks = osync_plugin_info_get_objtype_sinks(info);
666 for (OSyncList *s = sinks.Get(); s; s = s->next) {
667 OSyncObjTypeSink *sink = (OSyncObjTypeSink*) s->data;
669 osync_objtype_sink_set_available(sink, true);
672 OSyncVersion *version = osync_version_new(error);
673 osync_version_set_plugin(version, "Barry");
674 osync_version_set_modelversion(version, "1");
675 //osync_version_set_firmwareversion(version, "firmwareversion");
676 //osync_version_set_softwareversion(version, "softwareversion");
677 //osync_version_set_hardwareversion(version, "hardwareversion");
678 osync_plugin_info_set_version(info, version);
679 osync_version_unref(version);
681 return true;
685 static void connect(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
687 Trace trace("connect");
689 trace.logf("%s(%p, %p, %p, %p)\n", __func__, sink, info, ctx, userdata);
691 try {
692 BarryEnvironment *env = (BarryEnvironment *) userdata;
694 // I have to test if the device is already connected.
695 // Indeed, if I sync both contact and event, the connect
696 // function is called two times.
697 if (!env->isConnected()) {
698 // Probe for available devices
699 Barry::Probe probe;
700 int nIndex = probe.FindActive(env->m_pin);
701 if( nIndex == -1 ) {
702 osync_context_report_error(ctx, OSYNC_ERROR_NO_CONNECTION, "Unable to find PIN %x", env->m_pin);
703 return;
705 env->m_ProbeResult = probe.Get(nIndex);
707 trace.log("connecting...");
709 env->Connect(probe.Get(nIndex));
711 trace.log("connected !");
714 // Success!
715 osync_context_report_success(ctx);
717 trace.log("connect success");
719 // Don't let exceptions escape to the C modules
720 catch( std::bad_alloc &ba ) {
721 osync_context_report_error(ctx, OSYNC_ERROR_NO_CONNECTION,
722 "Unable to allocate memory for controller: %s", ba.what());
724 catch( std::exception &e ) {
725 osync_context_report_error(ctx, OSYNC_ERROR_NO_CONNECTION,
726 "%s", e.what());
731 static void contact_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata)
733 Trace trace("contact_get_changeinfo");
735 try {
736 BarryEnvironment *env = (BarryEnvironment *) userdata;
738 GetChanges(sink, info, ctx, env, &env->m_ContactsSync,
739 "Address Book", "contact", "vcard30",
740 &VCardConverter::GetRecordData,
741 slow_sync);
743 // Success!
744 osync_context_report_success(ctx);
747 // don't let exceptions escape to the C modules
748 catch( std::exception &e ) {
749 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
753 static void event_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata)
755 Trace trace("event_get_changeinfo");
757 try {
758 BarryEnvironment *env = (BarryEnvironment *) userdata;
760 GetChanges(sink, info, ctx, env, &env->m_CalendarSync,
761 "Calendar", "event", "vevent20",
762 &VEventConverter::GetRecordData,
763 slow_sync);
765 // Success!
766 osync_context_report_success(ctx);
768 // don't let exceptions escape to the C modules
769 catch( std::exception &e ) {
770 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
775 static void journal_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata)
777 Trace trace("journal_get_changeinfo");
779 try {
780 BarryEnvironment *env = (BarryEnvironment *) userdata;
782 GetChanges(sink, info, ctx, env, &env->m_JournalSync,
783 "Memos", "note", "vjournal",
784 &VJournalConverter::GetRecordData,
785 slow_sync);
787 // Success!
788 osync_context_report_success(ctx);
790 // don't let exceptions escape to the C modules
791 catch( std::exception &e ) {
792 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
797 static void todo_get_changes(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, osync_bool slow_sync, void *userdata)
799 Trace trace("todo_get_changeinfo");
801 try {
802 BarryEnvironment *env = (BarryEnvironment *) userdata;
804 GetChanges(sink, info, ctx, env, &env->m_TodoSync,
805 "Tasks", "todo", "vtodo20",
806 &VTodoConverter::GetRecordData,
807 slow_sync);
809 // Success!
810 osync_context_report_success(ctx);
812 // don't let exceptions escape to the C modules
813 catch( std::exception &e ) {
814 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
819 static void commit_change(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *change, void *userdata)
821 Trace trace("commit_change");
823 // We can rely on a valid record state table, since get_changeinfo()
824 // will be called first, and will fill the table.
826 try {
828 BarryEnvironment *env = (BarryEnvironment *) userdata;
830 OSyncHashTable *hashtable = osync_objtype_sink_get_hashtable(sink);
832 // find the needed commit function, based on objtype of the change
833 CommitData_t CommitData = GetCommitFunction(change);
834 if( !CommitData ) {
835 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC,
836 "unable to get commit function pointer");
837 return;
840 // find the matching cache, state table, and id map for this change
841 DatabaseSyncState *pSync = env->GetSyncObject(change);
842 if( !pSync ) {
843 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC,
844 "unable to get sync object that matches change type");
845 return;
848 // is syncing turned on for this type?
849 if( !pSync->m_Sync ) {
850 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC,
851 "This object type is disabled in the barry-sync config");
852 return;
855 // make references instead of pointers
856 Barry::RecordStateTable &table = pSync->m_Table;
857 Barry::Mode::Desktop &desktop = *env->m_pDesktop;
858 unsigned int dbId = pSync->m_dbId;
861 // either generate or retrieve the record ID, based on type
862 Barry::RecordStateTable::IndexType StateIndex;
863 unsigned long RecordId = 0;
864 if( osync_change_get_changetype(change) == OSYNC_CHANGE_TYPE_ADDED ) {
865 // create new ID for this record
866 RecordId = table.MakeNewRecordId();
868 // tell opensync to save our ID
869 char *puid = g_strdup_printf("%lu", RecordId);
870 osync_change_set_uid(change, puid);
871 g_free(puid);
873 else {
874 // extract RecordId from change's UID,
875 const char *uid = osync_change_get_uid(change);
876 trace.logf("uid from change: %s", uid);
878 // convert existing UID string to RecordId
879 if( strlen(uid) == 0 ||
880 sscanf(uid, "%lu", &RecordId) != 1 ||
881 RecordId == 0)
883 trace.logf("Unable to extract a valid record ID from: %s", uid);
884 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "Unable to extract a valid record ID from: %s", uid);
885 return;
888 // search for the RecordId in the state table, to find the
889 // index... we only need the index if we are deleting or
890 // modifying
891 if( !table.GetIndex(RecordId, &StateIndex) ) {
892 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC,
893 "unable to get state table index for RecordId: %lu",
894 RecordId);
895 return;
900 std::string errmsg;
901 bool status;
903 OSyncData *odata = NULL;
904 char *plain = NULL;
906 switch( osync_change_get_changetype(change) )
908 case OSYNC_CHANGE_TYPE_DELETED:
909 desktop.DeleteRecord(dbId, StateIndex);
910 break;
912 case OSYNC_CHANGE_TYPE_ADDED:
913 odata = osync_change_get_data(change);
914 osync_data_get_data(odata, &plain, NULL);
915 status = (*CommitData)(env, dbId, StateIndex, RecordId,
916 plain, true, errmsg);
917 if( !status ) {
918 trace.logf("CommitData() for ADDED state returned false: %s", errmsg.c_str());
919 osync_context_report_error(ctx, OSYNC_ERROR_PARAMETER, "%s", errmsg.c_str());
920 return;
922 osync_change_set_hash(change, "0");
923 break;
925 case OSYNC_CHANGE_TYPE_MODIFIED:
926 odata = osync_change_get_data(change);
927 osync_data_get_data(odata, &plain, NULL);
928 status = (*CommitData)(env, dbId, StateIndex, RecordId,
929 plain, false, errmsg);
930 if( !status ) {
931 trace.logf("CommitData() for MODIFIED state returned false: %s", errmsg.c_str());
932 osync_context_report_error(ctx, OSYNC_ERROR_PARAMETER, "%s", errmsg.c_str());
933 return;
935 osync_change_set_hash(change, "0");
936 break;
938 default:
939 trace.log("Unknown change type");
940 break;
943 // Update hashtable
944 osync_hashtable_update_change(hashtable, change);
946 // Answer the call
947 osync_context_report_success(ctx);
948 return;
952 catch( std::exception &e ) {
953 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
954 return;
959 static void contact_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
962 // This function will only be called if the sync was successfull
965 Trace trace("contact_sync_done");
967 try {
969 BarryEnvironment *env = (BarryEnvironment *) userdata;
971 // we reconnect to the device here, since dirty flags
972 // for records we've just touched do not show up until
973 // a disconnect... as far as I can tell.
974 env->Reconnect();
976 // do cleanup for each database
977 if( FinishSync(ctx, env, &env->m_ContactsSync) )
979 // Success
980 osync_context_report_success(ctx);
984 catch( std::exception &e ) {
985 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
990 static void event_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
993 // This function will only be called if the sync was successfull
996 Trace trace("event_sync_done");
998 try {
1000 BarryEnvironment *env = (BarryEnvironment *) userdata;
1002 // we reconnect to the device here, since dirty flags
1003 // for records we've just touched do not show up until
1004 // a disconnect... as far as I can tell.
1005 env->Reconnect();
1007 // do cleanup for each database
1008 if( FinishSync(ctx, env, &env->m_CalendarSync) )
1010 // Success
1011 osync_context_report_success(ctx);
1015 catch( std::exception &e ) {
1016 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
1021 static void journal_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
1024 // This function will only be called if the sync was successfull
1027 Trace trace("journal_sync_done");
1029 try {
1031 BarryEnvironment *env = (BarryEnvironment *) userdata;
1033 // we reconnect to the device here, since dirty flags
1034 // for records we've just touched do not show up until
1035 // a disconnect... as far as I can tell.
1036 env->Reconnect();
1038 // do cleanup for each database
1039 if( FinishSync(ctx, env, &env->m_JournalSync) )
1041 // Success
1042 osync_context_report_success(ctx);
1046 catch( std::exception &e ) {
1047 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
1052 static void todo_sync_done(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
1055 // This function will only be called if the sync was successfull
1058 Trace trace("todo_sync_done");
1060 try {
1062 BarryEnvironment *env = (BarryEnvironment *) userdata;
1064 // we reconnect to the device here, since dirty flags
1065 // for records we've just touched do not show up until
1066 // a disconnect... as far as I can tell.
1067 env->Reconnect();
1069 // do cleanup for each database
1070 if( FinishSync(ctx, env, &env->m_TodoSync) )
1072 // Success
1073 osync_context_report_success(ctx);
1077 catch( std::exception &e ) {
1078 osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what());
1083 static void disconnect(OSyncObjTypeSink *sink, OSyncPluginInfo *info, OSyncContext *ctx, void *userdata)
1085 Trace trace("contact_disconnect");
1087 // Done!
1088 osync_context_report_success(ctx);
1092 static void finalize(void *data)
1094 Trace trace("finalize");
1096 BarryEnvironment *env = (BarryEnvironment *) data;
1098 // Disconnect the controller, which closes our connection
1099 if (env->isConnected())
1100 env->Disconnect();
1102 delete env;
1106 osync_bool get_sync_info(OSyncPluginEnv *env, OSyncError **error)
1108 Trace trace("get_sync_info");
1110 // Create a new OpenSync plugin
1111 OSyncPlugin *plugin = osync_plugin_new(error);
1112 if( !plugin ) {
1113 trace.log(osync_error_print(error));
1114 return false;
1117 // Describe our plugin
1118 osync_plugin_set_name(plugin, "barry-sync");
1119 osync_plugin_set_longname(plugin, "Barry OpenSync plugin v0.17 for the Blackberry handheld");
1120 osync_plugin_set_description(plugin, "Plugin to synchronize note, task, calendar and contact entries on USB Blackberry handhelds");
1122 // Set the callback functions
1123 osync_plugin_set_initialize(plugin, initialize);
1124 osync_plugin_set_finalize(plugin, finalize);
1125 osync_plugin_set_discover(plugin, discover);
1126 osync_plugin_set_start_type(plugin, OSYNC_START_TYPE_PROCESS);
1128 if( !osync_plugin_env_register_plugin(env, plugin, error) ) {
1129 trace.log(osync_error_print(error));
1130 return false;
1133 osync_plugin_unref(plugin);
1135 return true;
1139 int get_version(void)
1141 return 1;