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-2012, 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"
47 typedef Barry::vSmartPtr
<OSyncList
, OSyncList
, &osync_list_free
> AutoOSyncList
;
49 // All functions that are callable from outside must look like C
51 BXEXPORT
int get_version(void);
52 static void *initialize(OSyncPlugin
*plugin
, OSyncPluginInfo
*info
, OSyncError
**error
);
53 static osync_bool
discover(OSyncPluginInfo
*info
, void *userdata
, OSyncError
**error
);
55 static void contact_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
);
56 static void contact_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
58 static void event_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
);
59 static void event_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
61 static void journal_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
);
62 static void journal_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
64 static void todo_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
);
65 static void todo_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
67 static void connect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
68 static void disconnect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
);
69 static void commit_change(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, OSyncChange
*change
, void *userdata
);
70 static void finalize(void *userdata
);
71 BXEXPORT osync_bool
get_sync_info(OSyncPluginEnv
*env
, OSyncError
**error
);
76 //////////////////////////////////////////////////////////////////////////////
78 // Support functions and classes
81 // Generates a "hash" by grabbing the existing hash
82 // of the given uid, and adding 1 to it if dirty.
83 std::string
GenerateHash(OSyncHashTable
*hashtable
,
84 const std::string
&uid
,
87 unsigned long hashcount
= 0;
89 const char *hash
= osync_hashtable_get_hash(hashtable
, uid
.c_str());
92 hashcount
= strtoul(hash
, NULL
, 10);
94 throw std::runtime_error(_("Error converting string to unsigned long: ") + std::string(hash
));
97 hashcount
+= (dirty
? 1 : 0);
99 std::ostringstream oss
;
100 oss
<< std::dec
<< hashcount
;
104 void GetChanges(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
,
105 BarryEnvironment
*env
,
106 DatabaseSyncState
*pSync
,
107 const char *DBDBName
,
108 const char *ObjTypeName
, const char *FormatName
,
110 osync_bool slow_sync
)
112 Trace
trace("GetChanges");
114 OSyncError
*error
= NULL
;
116 // shortcut references
117 using namespace Barry
;
118 using Barry::RecordStateTable
;
119 Mode::Desktop
&desktop
= *env
->GetDesktop();
123 // Note: Since the Blackberry tracks dirty flags for us, we don't
124 // need the hash table to help determine what records have
125 // changed, and therefore we don't need to actually load
126 // all the record data across USB either.
128 // The hashtable only needs the hash to change when data
129 // has changed, so we set each change object's hash to:
130 // last_hash + (dirty ? 1 : 0)
132 OSyncHashTable
*hashtable
= osync_objtype_sink_get_hashtable(sink
);
134 // check if slow sync has been requested
136 trace
.log(_("GetChanges: slow sync request detected"));
138 if( !osync_hashtable_slowsync(hashtable
, &error
) ) {
139 std::ostringstream oss
;
140 oss
<< _("GetChanges: slow sync error: ") << osync_error_print(&error
);
141 osync_error_unref(&error
);
143 trace
.log(oss
.str().c_str());
144 throw std::runtime_error(oss
.str());
149 unsigned int dbId
= desktop
.GetDBID(DBDBName
);
150 RecordStateTable
&table
= pSync
->m_Table
;
151 desktop
.GetRecordStateTable(dbId
, table
);
153 OSyncFormatEnv
*formatenv
= osync_plugin_info_get_format_env(info
);
156 // cycle through the state table... for each record in the state
157 // table, register a change and the fake hash (see note above)
158 // and let the hash table determine what changetype it is
159 RecordStateTable::StateMapType::const_iterator i
= table
.StateMap
.begin();
160 for( ; i
!= table
.StateMap
.end(); ++i
) {
162 OSyncChange
*change
= 0;
163 const RecordStateTable::IndexType
&index
= i
->first
;
164 const RecordStateTable::State
&state
= i
->second
;
166 // create change to pass to hashtable
167 change
= osync_change_new(&error
);
169 osync_context_report_osyncwarning(ctx
, error
);
170 osync_error_unref(&error
);
174 // convert record ID to uid string
175 std::string uid
= pSync
->Map2Uid(state
.RecordId
);
177 // setup change, just enough for hashtable use
178 osync_change_set_uid(change
, uid
.c_str());
179 trace
.logf(_("change record ID: %s"), uid
.c_str());
180 std::string hash
= GenerateHash(hashtable
, uid
, state
.Dirty
);
181 osync_change_set_hash(change
, hash
.c_str());
184 // let hashtable determine what's going to happen
185 OSyncChangeType changetype
= osync_hashtable_get_changetype(hashtable
, change
);
186 osync_change_set_changetype(change
, changetype
);
188 // let hashtable know we've processed this change
189 osync_hashtable_update_change(hashtable
, change
);
192 // Decision time: if nothing has changed, skip
193 if( changetype
== OSYNC_CHANGE_TYPE_UNMODIFIED
) {
194 osync_change_unref(change
);
200 // finish filling out the change object
203 // Now you can set the data for the object
204 // Set the last argument to FALSE if the real data
205 // should be queried later in a "get_data" function
206 OSyncObjFormat
*format
= osync_format_env_find_objformat(formatenv
, FormatName
);
207 char *data
= (*getdata
)(env
, dbId
, index
);
208 OSyncData
*odata
= osync_data_new(data
, strlen(data
), format
, &error
);
211 osync_change_unref(change
);
212 osync_context_report_osyncwarning(ctx
, error
);
213 osync_error_unref(&error
);
217 // FIXME ? Is this line is usefull ?
218 // osync_data_set_objtype(odata, osync_objtype_sink_get_name(sink));
220 osync_change_set_data(change
, odata
);
221 osync_data_unref(odata
);
223 // just report the change via
224 osync_context_report_change(ctx
, change
);
226 osync_change_unref(change
);
229 // the hashtable can now give us a linked list of deleted
230 // entries, after the above processing
231 AutoOSyncList uids
= osync_hashtable_get_deleted(hashtable
);
232 for( OSyncList
*u
= uids
.Get(); u
; u
= u
->next
) {
234 const char *uid
= (const char*) u
->data
;
235 uint32_t recordId
= strtoul(uid
, NULL
, 10);
237 // search the state table
238 i
= table
.StateMap
.begin();
239 for( ; i
!= table
.StateMap
.end(); ++i
) {
241 if( i
->second
.RecordId
== recordId
) {
242 throw std::runtime_error(_("Found deleted record ID in state map! ") + std::string(uid
));
246 // register a DELETE, no data
247 trace
.log(_("found DELETE change"));
249 OSyncChange
*change
= osync_change_new(&error
);
251 osync_context_report_osyncwarning(ctx
, error
);
252 osync_error_unref(&error
);
256 osync_change_set_uid(change
, uid
);
258 osync_change_set_changetype(change
, OSYNC_CHANGE_TYPE_DELETED
);
260 // osync_change_set_objformat_string(change, FormatName);
262 OSyncObjFormat
*format
= osync_format_env_find_objformat(formatenv
, FormatName
);
263 OSyncData
*odata
= osync_data_new(NULL
, 0, format
, &error
);
265 osync_change_unref(change
);
266 osync_context_report_osyncwarning(ctx
, error
);
267 osync_error_unref(&error
);
271 osync_data_set_objtype(odata
, osync_objtype_sink_get_name(sink
));
273 osync_change_set_data(change
, odata
);
274 osync_data_unref(odata
);
277 osync_context_report_change(ctx
, change
);
279 // tell hashtable we've processed this item
280 osync_hashtable_update_change(hashtable
, change
);
282 osync_change_unref(change
);
286 CommitData_t
GetCommitFunction(OSyncChange
*change
)
288 Trace
trace("GetCommitFunction()");
290 const char *name
= osync_change_get_objtype(change
);
292 if( strcmp(name
, "event") == 0 ) {
293 return &VEventConverter::CommitRecordData
;
295 else if( strcmp(name
, "contact") == 0 ) {
296 return &VCardConverter::CommitRecordData
;
298 else if( strcmp(name
, "note") == 0 ) {
299 return &VJournalConverter::CommitRecordData
;
301 else if( strcmp(name
, "todo") == 0 ) {
302 return &VTodoConverter::CommitRecordData
;
305 trace
.log("unknown !");
312 bool FinishSync(OSyncContext
*ctx
, BarryEnvironment
*env
, DatabaseSyncState
*pSync
)
314 Trace
trace("FinishSync()");
316 if( !pSync
->m_Sync
) {
317 // this mode is disabled in config, skip
321 // we reconnect to the device here, since dirty flags
322 // for records we've just touched do not show up until
323 // a disconnect... as far as I can tell.
324 env
->ReconnectForDirtyFlags();
326 // get the state table again, so we can update
327 // the cache properly
328 Barry::Mode::Desktop
&desktop
= *env
->GetDesktop();
329 desktop
.GetRecordStateTable(pSync
->m_dbId
, pSync
->m_Table
);
331 // clear all dirty flags in device
332 env
->ClearDirtyFlags(pSync
->m_Table
, pSync
->m_dbName
);
337 static bool barry_contact_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
339 Trace
trace("contact initialize");
341 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "contact");
344 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
348 trace
.log("contact enabled");
350 osync_objtype_sink_set_connect_func(sink
, connect
);
351 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
352 osync_objtype_sink_set_get_changes_func(sink
, contact_get_changes
);
353 osync_objtype_sink_set_commit_func(sink
, commit_change
);
354 osync_objtype_sink_set_sync_done_func(sink
, contact_sync_done
);
356 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
357 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "contact");
359 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
361 bool hasObjFormat
= false;
364 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
365 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
367 if(!strcmp("vcard30", osync_objformat_sink_get_objformat(objformatsink
))) {
368 trace
.log(_("vcard30 found in barry-sync"));
378 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
380 // env->format = osync_format_env_find_objformat(formatenv, "vcard30");
381 env
->m_ContactsSync
.sink
= sink
;
383 osync_objtype_sink_set_userdata(sink
, env
);
385 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
387 trace
.log(_("contact initialize OK"));
393 static bool barry_calendar_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
395 Trace
trace("calendar initialize");
397 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "event");
400 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
404 trace
.log("calendar enabled");
406 osync_objtype_sink_set_connect_func(sink
, connect
);
407 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
408 osync_objtype_sink_set_get_changes_func(sink
, event_get_changes
);
409 osync_objtype_sink_set_commit_func(sink
, commit_change
);
410 osync_objtype_sink_set_sync_done_func(sink
, event_sync_done
);
412 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
413 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "event");
415 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
417 bool hasObjFormat
= false;
420 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
421 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
423 if(!strcmp("vevent20", osync_objformat_sink_get_objformat(objformatsink
))) {
433 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
435 // env->format = osync_format_env_find_objformat(formatenv, "vevent20");
436 env
->m_CalendarSync
.sink
= sink
;
438 osync_objtype_sink_set_userdata(sink
, env
);
440 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
446 static bool barry_journal_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
448 Trace
trace("journal initialize");
450 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "note");
453 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
457 trace
.log("journal enabled");
459 osync_objtype_sink_set_connect_func(sink
, connect
);
460 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
461 osync_objtype_sink_set_get_changes_func(sink
, journal_get_changes
);
462 osync_objtype_sink_set_commit_func(sink
, commit_change
);
463 osync_objtype_sink_set_sync_done_func(sink
, journal_sync_done
);
465 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
466 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "note");
468 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
470 bool hasObjFormat
= false;
473 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
474 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
476 if(!strcmp("vjournal", osync_objformat_sink_get_objformat(objformatsink
))) {
486 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
488 // env->format = osync_format_env_find_objformat(formatenv, "vjournal");
489 env
->m_JournalSync
.sink
= sink
;
491 osync_objtype_sink_set_userdata(sink
, env
);
493 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
499 static bool barry_todo_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
501 Trace
trace("todo initialize");
503 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "todo");
506 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
510 trace
.log("todo enabled");
512 osync_objtype_sink_set_connect_func(sink
, connect
);
513 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
514 osync_objtype_sink_set_get_changes_func(sink
, todo_get_changes
);
515 osync_objtype_sink_set_commit_func(sink
, commit_change
);
516 osync_objtype_sink_set_sync_done_func(sink
, todo_sync_done
);
518 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
519 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "todo");
521 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
523 bool hasObjFormat
= false;
526 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
527 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
529 if(!strcmp("vtodo20", osync_objformat_sink_get_objformat(objformatsink
))) {
539 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
541 // env->format = osync_format_env_find_objformat(formatenv, "vtodo20");
542 env
->m_TodoSync
.sink
= sink
;
544 osync_objtype_sink_set_userdata(sink
, env
);
546 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
554 //////////////////////////////////////////////////////////////////////////////
559 static void *initialize(OSyncPlugin
*plugin
, OSyncPluginInfo
*info
, OSyncError
**error
)
561 Trace
trace("initialize");
563 BarryEnvironment
*env
= 0;
566 env
= new BarryEnvironment(info
);
571 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
574 osync_error_set(error
, OSYNC_ERROR_GENERIC
, _("Unable to get config."));
582 * Process plugin specific advanced options
584 AutoOSyncList optslist
= osync_plugin_config_get_advancedoptions(config
);
585 for (OSyncList
*o
= optslist
.Get(); o
; o
= o
->next
) {
586 OSyncPluginAdvancedOption
*option
= (OSyncPluginAdvancedOption
*) o
->data
;
588 const char *val
= osync_plugin_advancedoption_get_value(option
);
589 const char *name
= osync_plugin_advancedoption_get_name(option
);
591 if (!strcmp(name
, "PinCode")) {
592 env
->m_pin
= strtol(val
, NULL
, 16);
594 else if (!strcmp(name
, "Debug")) {
595 env
->m_DebugMode
= (!strcmp(val
, "1")) ? true : false;
599 OSyncPluginAuthentication
*optauth
= osync_plugin_config_get_authentication(config
);
601 if (osync_plugin_authentication_option_is_supported(optauth
, OSYNC_PLUGIN_AUTHENTICATION_PASSWORD
)) {
602 const char *val
= osync_plugin_authentication_get_password(optauth
);
604 env
->SetPassword(val
);
608 // FIXME - near the end of release, do a run with
609 // this set to true, and look for USB protocol
611 Barry::Init(env
->m_DebugMode
);
615 * Process Resource options
617 trace
.log(_("Process Resource options..."));
619 if (barry_calendar_initialize(env
, info
, error
)) {
620 env
->m_CalendarSync
.m_Sync
= true;
623 trace
.log(_("No sync Calendar"));
624 env
->m_CalendarSync
.m_Sync
= false;
627 if (barry_contact_initialize(env
, info
, error
)) {
628 env
->m_ContactsSync
.m_Sync
= true;
631 trace
.log(_("No sync Contact"));
632 env
->m_ContactsSync
.m_Sync
= false;
635 if (barry_journal_initialize(env
, info
, error
)) {
636 env
->m_JournalSync
.m_Sync
= true;
639 trace
.log(_("No sync Journal"));
640 env
->m_JournalSync
.m_Sync
= false;
643 if (barry_todo_initialize(env
, info
, error
)) {
644 env
->m_TodoSync
.m_Sync
= true;
647 trace
.log(_("No sync Todo"));
648 env
->m_TodoSync
.m_Sync
= false;
653 // Don't let exceptions escape to the C modules
654 catch( std::bad_alloc
&ba
) {
655 trace
.logf(_("Unable to allocate memory for controller: %s"), ba
.what());
659 catch( std::exception
&e
) {
660 trace
.logf(_("exception: %s"), e
.what());
667 static osync_bool
discover(OSyncPluginInfo
*info
, void *userdata
, OSyncError
**error
)
669 Trace
trace("discover");
671 AutoOSyncList sinks
= osync_plugin_info_get_objtype_sinks(info
);
672 for (OSyncList
*s
= sinks
.Get(); s
; s
= s
->next
) {
673 OSyncObjTypeSink
*sink
= (OSyncObjTypeSink
*) s
->data
;
675 osync_objtype_sink_set_available(sink
, true);
678 OSyncVersion
*version
= osync_version_new(error
);
679 osync_version_set_plugin(version
, "Barry");
680 osync_version_set_modelversion(version
, "1");
681 //osync_version_set_firmwareversion(version, "firmwareversion");
682 //osync_version_set_softwareversion(version, "softwareversion");
683 //osync_version_set_hardwareversion(version, "hardwareversion");
684 osync_plugin_info_set_version(info
, version
);
685 osync_version_unref(version
);
691 static void connect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
693 Trace
trace("connect");
695 trace
.logf("%s(%p, %p, %p, %p)\n", __func__
, sink
, info
, ctx
, userdata
);
698 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
700 // I have to test if the device is already connected.
701 // Indeed, if I sync both contact and event, the connect
702 // function is called two times.
703 if (!env
->isConnected()) {
704 // Probe for available devices
706 int nIndex
= probe
.FindActive(env
->m_pin
);
708 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
, _("Unable to find PIN %x"), env
->m_pin
);
712 trace
.log(_("connecting..."));
714 env
->Connect(probe
.Get(nIndex
));
716 trace
.log(_("connected !"));
720 osync_context_report_success(ctx
);
722 trace
.log(_("connect success"));
724 // Don't let exceptions escape to the C modules
725 catch( std::bad_alloc
&ba
) {
726 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
,
727 _("Unable to allocate memory for controller: %s"), ba
.what());
729 catch( std::exception
&e
) {
730 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
,
736 static void contact_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
738 Trace
trace("contact_get_changeinfo");
741 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
743 GetChanges(sink
, info
, ctx
, env
, &env
->m_ContactsSync
,
744 "Address Book", "contact", "vcard30",
745 &VCardConverter::GetRecordData
,
749 osync_context_report_success(ctx
);
752 // don't let exceptions escape to the C modules
753 catch( std::exception
&e
) {
754 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
758 static void event_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
760 Trace
trace("event_get_changeinfo");
763 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
765 GetChanges(sink
, info
, ctx
, env
, &env
->m_CalendarSync
,
766 "Calendar", "event", "vevent20",
767 &VEventConverter::GetRecordData
,
771 osync_context_report_success(ctx
);
773 // don't let exceptions escape to the C modules
774 catch( std::exception
&e
) {
775 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
780 static void journal_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
782 Trace
trace("journal_get_changeinfo");
785 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
787 GetChanges(sink
, info
, ctx
, env
, &env
->m_JournalSync
,
788 "Memos", "note", "vjournal",
789 &VJournalConverter::GetRecordData
,
793 osync_context_report_success(ctx
);
795 // don't let exceptions escape to the C modules
796 catch( std::exception
&e
) {
797 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
802 static void todo_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
804 Trace
trace("todo_get_changeinfo");
807 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
809 GetChanges(sink
, info
, ctx
, env
, &env
->m_TodoSync
,
810 "Tasks", "todo", "vtodo20",
811 &VTodoConverter::GetRecordData
,
815 osync_context_report_success(ctx
);
817 // don't let exceptions escape to the C modules
818 catch( std::exception
&e
) {
819 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
824 static void commit_change(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, OSyncChange
*change
, void *userdata
)
826 Trace
trace("commit_change");
828 // We can rely on a valid record state table, since get_changeinfo()
829 // will be called first, and will fill the table.
833 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
835 OSyncHashTable
*hashtable
= osync_objtype_sink_get_hashtable(sink
);
837 // find the needed commit function, based on objtype of the change
838 CommitData_t CommitData
= GetCommitFunction(change
);
840 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
841 _("unable to get commit function pointer"));
845 // find the matching cache, state table, and id map for this change
846 DatabaseSyncState
*pSync
= env
->GetSyncObject(change
);
848 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
849 _("unable to get sync object that matches change type"));
853 // is syncing turned on for this type?
854 if( !pSync
->m_Sync
) {
855 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
856 _("This object type is disabled in the barry-sync config"));
860 // make references instead of pointers
861 Barry::RecordStateTable
&table
= pSync
->m_Table
;
862 Barry::Mode::Desktop
&desktop
= *env
->GetDesktop();
863 unsigned int dbId
= pSync
->m_dbId
;
866 // either generate or retrieve the record ID, based on type
867 Barry::RecordStateTable::IndexType StateIndex
;
868 unsigned long RecordId
= 0;
869 if( osync_change_get_changetype(change
) == OSYNC_CHANGE_TYPE_ADDED
) {
870 // create new ID for this record
871 RecordId
= table
.MakeNewRecordId();
873 // tell opensync to save our ID
874 char *puid
= g_strdup_printf("%lu", RecordId
);
875 osync_change_set_uid(change
, puid
);
879 // extract RecordId from change's UID,
880 const char *uid
= osync_change_get_uid(change
);
881 trace
.logf(_("uid from change: %s"), uid
);
883 // convert existing UID string to RecordId
884 if( strlen(uid
) == 0 ||
885 sscanf(uid
, "%lu", &RecordId
) != 1 ||
888 trace
.logf(_("Unable to extract a valid record ID from: %s"), uid
);
889 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, _("Unable to extract a valid record ID from: %s"), uid
);
893 // search for the RecordId in the state table, to find the
894 // index... we only need the index if we are deleting or
896 if( !table
.GetIndex(RecordId
, &StateIndex
) ) {
897 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
898 _("unable to get state table index for RecordId: %lu"),
904 // if we get here, we are about to update the device,
905 // and dirty flags will change in such a way that a
906 // reconnect will be required later... so flag this state
907 env
->RequireDirtyReconnect();
913 OSyncData
*odata
= NULL
;
916 switch( osync_change_get_changetype(change
) )
918 case OSYNC_CHANGE_TYPE_DELETED
:
919 desktop
.DeleteRecord(dbId
, StateIndex
);
922 case OSYNC_CHANGE_TYPE_ADDED
:
923 odata
= osync_change_get_data(change
);
924 osync_data_get_data(odata
, &plain
, NULL
);
925 status
= (*CommitData
)(env
, dbId
, StateIndex
, RecordId
,
926 plain
, true, errmsg
);
928 trace
.logf(_("CommitData() for ADDED state returned false: %s"), errmsg
.c_str());
929 osync_context_report_error(ctx
, OSYNC_ERROR_PARAMETER
, "%s", errmsg
.c_str());
932 osync_change_set_hash(change
, "0");
935 case OSYNC_CHANGE_TYPE_MODIFIED
:
936 odata
= osync_change_get_data(change
);
937 osync_data_get_data(odata
, &plain
, NULL
);
938 status
= (*CommitData
)(env
, dbId
, StateIndex
, RecordId
,
939 plain
, false, errmsg
);
941 trace
.logf(_("CommitData() for MODIFIED state returned false: %s"), errmsg
.c_str());
942 osync_context_report_error(ctx
, OSYNC_ERROR_PARAMETER
, "%s", errmsg
.c_str());
945 osync_change_set_hash(change
, "0");
949 trace
.log(_("Unknown change type"));
954 osync_hashtable_update_change(hashtable
, change
);
957 osync_context_report_success(ctx
);
962 catch( std::exception
&e
) {
963 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
969 static void contact_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
972 // This function will only be called if the sync was successfull
975 Trace
trace("contact_sync_done");
979 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
981 // do cleanup for each database
982 if( FinishSync(ctx
, env
, &env
->m_ContactsSync
) )
985 osync_context_report_success(ctx
);
989 catch( std::exception
&e
) {
990 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
995 static void event_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
998 // This function will only be called if the sync was successfull
1001 Trace
trace("event_sync_done");
1005 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
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 // do cleanup for each database
1034 if( FinishSync(ctx
, env
, &env
->m_JournalSync
) )
1037 osync_context_report_success(ctx
);
1041 catch( std::exception
&e
) {
1042 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
1047 static void todo_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
1050 // This function will only be called if the sync was successfull
1053 Trace
trace("todo_sync_done");
1057 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
1059 // do cleanup for each database
1060 if( FinishSync(ctx
, env
, &env
->m_TodoSync
) )
1063 osync_context_report_success(ctx
);
1067 catch( std::exception
&e
) {
1068 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
1073 static void disconnect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
1075 Trace
trace("contact_disconnect");
1078 osync_context_report_success(ctx
);
1082 static void finalize(void *data
)
1084 Trace
trace("finalize");
1086 BarryEnvironment
*env
= (BarryEnvironment
*) data
;
1088 // Disconnect the controller, which closes our connection
1089 if (env
->isConnected())
1096 osync_bool
get_sync_info(OSyncPluginEnv
*env
, OSyncError
**error
)
1098 Trace
trace("get_sync_info");
1100 static bool i18n_initialized
= false;
1101 if( !i18n_initialized
) {
1102 // initialize i18n gettext directory
1103 // the rest is done in i18n.h
1104 bindtextdomain(PACKAGE
, LOCALEDIR
);
1106 i18n_initialized
= true;
1109 // Create a new OpenSync plugin
1110 OSyncPlugin
*plugin
= osync_plugin_new(error
);
1112 trace
.log(osync_error_print(error
));
1116 // Describe our plugin
1117 osync_plugin_set_name(plugin
, "barry-sync");
1118 osync_plugin_set_longname(plugin
, Barry::string_vprintf(_("Barry OpenSync plugin v%s for the Blackberry handheld"), PACKAGE_VERSION
).c_str());
1119 osync_plugin_set_description(plugin
, _("Plugin to synchronize note, task, calendar and contact entries on USB Blackberry handhelds"));
1121 // Set the callback functions
1122 osync_plugin_set_initialize_func(plugin
, initialize
);
1123 osync_plugin_set_finalize_func(plugin
, finalize
);
1124 osync_plugin_set_discover_func(plugin
, discover
);
1125 osync_plugin_set_start_type(plugin
, OSYNC_START_TYPE_PROCESS
);
1127 if( !osync_plugin_env_register_plugin(env
, plugin
, error
) ) {
1128 trace
.log(osync_error_print(error
));
1132 osync_plugin_unref(plugin
);
1138 int get_version(void)