3 // Opensync module for the USB Blackberry handheld
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"
45 typedef Barry::vSmartPtr
<OSyncList
, OSyncList
, &osync_list_free
> AutoOSyncList
;
47 // All functions that are callable from outside must look like 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
,
85 unsigned long hashcount
= 0;
87 const char *hash
= osync_hashtable_get_hash(hashtable
, uid
.c_str());
90 hashcount
= strtoul(hash
, NULL
, 10);
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
;
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
,
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
;
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
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());
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
);
167 osync_context_report_osyncwarning(ctx
, error
);
168 osync_error_unref(&error
);
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
);
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
);
209 osync_change_unref(change
);
210 osync_context_report_osyncwarning(ctx
, error
);
211 osync_error_unref(&error
);
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
);
249 osync_context_report_osyncwarning(ctx
, error
);
250 osync_error_unref(&error
);
254 osync_change_set_uid(change
, 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
);
263 osync_change_unref(change
);
264 osync_context_report_osyncwarning(ctx
, error
);
265 osync_error_unref(&error
);
269 osync_data_set_objtype(odata
, osync_objtype_sink_get_name(sink
));
271 osync_change_set_data(change
, odata
);
272 osync_data_unref(odata
);
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
;
303 trace
.log("unknown !");
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
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
);
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");
338 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
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;
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");
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");
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");
394 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
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;
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
))) {
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
);
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");
447 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
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;
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
))) {
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
);
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");
500 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
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;
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
))) {
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
);
548 //////////////////////////////////////////////////////////////////////////////
553 static void *initialize(OSyncPlugin
*plugin
, OSyncPluginInfo
*info
, OSyncError
**error
)
555 Trace
trace("initialize");
557 BarryEnvironment
*env
= 0;
560 env
= new BarryEnvironment(info
);
565 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
568 osync_error_set(error
, OSYNC_ERROR_GENERIC
, "Unable to get config.");
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
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;
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;
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;
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;
641 trace
.log("No sync Todo");
642 env
->m_TodoSync
.m_Sync
= false;
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());
653 catch( std::exception
&e
) {
654 trace
.logf("exception: %s", e
.what());
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
);
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
);
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
700 int nIndex
= probe
.FindActive(env
->m_pin
);
702 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
, "Unable to find PIN %x", env
->m_pin
);
705 env
->m_ProbeResult
= probe
.Get(nIndex
);
707 trace
.log("connecting...");
709 env
->Connect(probe
.Get(nIndex
));
711 trace
.log("connected !");
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
,
731 static void contact_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
733 Trace
trace("contact_get_changeinfo");
736 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
738 GetChanges(sink
, info
, ctx
, env
, &env
->m_ContactsSync
,
739 "Address Book", "contact", "vcard30",
740 &VCardConverter::GetRecordData
,
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");
758 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
760 GetChanges(sink
, info
, ctx
, env
, &env
->m_CalendarSync
,
761 "Calendar", "event", "vevent20",
762 &VEventConverter::GetRecordData
,
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");
780 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
782 GetChanges(sink
, info
, ctx
, env
, &env
->m_JournalSync
,
783 "Memos", "note", "vjournal",
784 &VJournalConverter::GetRecordData
,
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");
802 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
804 GetChanges(sink
, info
, ctx
, env
, &env
->m_TodoSync
,
805 "Tasks", "todo", "vtodo20",
806 &VTodoConverter::GetRecordData
,
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.
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
);
835 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
836 "unable to get commit function pointer");
840 // find the matching cache, state table, and id map for this change
841 DatabaseSyncState
*pSync
= env
->GetSyncObject(change
);
843 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
844 "unable to get sync object that matches change type");
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");
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
);
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 ||
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
);
888 // search for the RecordId in the state table, to find the
889 // index... we only need the index if we are deleting or
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",
903 OSyncData
*odata
= NULL
;
906 switch( osync_change_get_changetype(change
) )
908 case OSYNC_CHANGE_TYPE_DELETED
:
909 desktop
.DeleteRecord(dbId
, StateIndex
);
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
);
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());
922 osync_change_set_hash(change
, "0");
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
);
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());
935 osync_change_set_hash(change
, "0");
939 trace
.log("Unknown change type");
944 osync_hashtable_update_change(hashtable
, change
);
947 osync_context_report_success(ctx
);
952 catch( std::exception
&e
) {
953 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
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");
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.
976 // do cleanup for each database
977 if( FinishSync(ctx
, env
, &env
->m_ContactsSync
) )
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");
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.
1007 // do cleanup for each database
1008 if( FinishSync(ctx
, env
, &env
->m_CalendarSync
) )
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");
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.
1038 // do cleanup for each database
1039 if( FinishSync(ctx
, env
, &env
->m_JournalSync
) )
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");
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.
1069 // do cleanup for each database
1070 if( FinishSync(ctx
, env
, &env
->m_TodoSync
) )
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");
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())
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
);
1113 trace
.log(osync_error_print(error
));
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
));
1133 osync_plugin_unref(plugin
);
1139 int get_version(void)