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"
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
->GetDesktop();
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 // we reconnect to the device here, since dirty flags
320 // for records we've just touched do not show up until
321 // a disconnect... as far as I can tell.
322 env
->ReconnectForDirtyFlags();
324 // get the state table again, so we can update
325 // the cache properly
326 Barry::Mode::Desktop
&desktop
= *env
->GetDesktop();
327 desktop
.GetRecordStateTable(pSync
->m_dbId
, pSync
->m_Table
);
329 // clear all dirty flags in device
330 env
->ClearDirtyFlags(pSync
->m_Table
, pSync
->m_dbName
);
335 static bool barry_contact_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
337 Trace
trace("contact initialize");
339 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "contact");
342 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
346 trace
.log("contact enabled");
348 osync_objtype_sink_set_connect_func(sink
, connect
);
349 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
350 osync_objtype_sink_set_get_changes_func(sink
, contact_get_changes
);
351 osync_objtype_sink_set_commit_func(sink
, commit_change
);
352 osync_objtype_sink_set_sync_done_func(sink
, contact_sync_done
);
354 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
355 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "contact");
357 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
359 bool hasObjFormat
= false;
362 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
363 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
365 if(!strcmp("vcard30", osync_objformat_sink_get_objformat(objformatsink
))) {
366 trace
.log("vcard30 found in barry-sync");
376 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
378 // env->format = osync_format_env_find_objformat(formatenv, "vcard30");
379 env
->m_ContactsSync
.sink
= sink
;
381 osync_objtype_sink_set_userdata(sink
, env
);
383 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
385 trace
.log("contact initialize OK");
391 static bool barry_calendar_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
393 Trace
trace("calendar initialize");
395 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "event");
398 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
402 trace
.log("calendar enabled");
404 osync_objtype_sink_set_connect_func(sink
, connect
);
405 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
406 osync_objtype_sink_set_get_changes_func(sink
, event_get_changes
);
407 osync_objtype_sink_set_commit_func(sink
, commit_change
);
408 osync_objtype_sink_set_sync_done_func(sink
, event_sync_done
);
410 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
411 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "event");
413 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
415 bool hasObjFormat
= false;
418 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
419 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
421 if(!strcmp("vevent20", osync_objformat_sink_get_objformat(objformatsink
))) {
431 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
433 // env->format = osync_format_env_find_objformat(formatenv, "vevent20");
434 env
->m_CalendarSync
.sink
= sink
;
436 osync_objtype_sink_set_userdata(sink
, env
);
438 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
444 static bool barry_journal_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
446 Trace
trace("journal initialize");
448 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "note");
451 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
455 trace
.log("journal enabled");
457 osync_objtype_sink_set_connect_func(sink
, connect
);
458 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
459 osync_objtype_sink_set_get_changes_func(sink
, journal_get_changes
);
460 osync_objtype_sink_set_commit_func(sink
, commit_change
);
461 osync_objtype_sink_set_sync_done_func(sink
, journal_sync_done
);
463 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
464 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "note");
466 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
468 bool hasObjFormat
= false;
471 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
472 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
474 if(!strcmp("vjournal", osync_objformat_sink_get_objformat(objformatsink
))) {
484 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
486 // env->format = osync_format_env_find_objformat(formatenv, "vjournal");
487 env
->m_JournalSync
.sink
= sink
;
489 osync_objtype_sink_set_userdata(sink
, env
);
491 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
497 static bool barry_todo_initialize(BarryEnvironment
*env
, OSyncPluginInfo
*info
, OSyncError
**error
)
499 Trace
trace("todo initialize");
501 OSyncObjTypeSink
*sink
= osync_plugin_info_find_objtype(info
, "todo");
504 osync_bool sinkEnabled
= osync_objtype_sink_is_enabled(sink
);
508 trace
.log("todo enabled");
510 osync_objtype_sink_set_connect_func(sink
, connect
);
511 osync_objtype_sink_set_disconnect_func(sink
, disconnect
);
512 osync_objtype_sink_set_get_changes_func(sink
, todo_get_changes
);
513 osync_objtype_sink_set_commit_func(sink
, commit_change
);
514 osync_objtype_sink_set_sync_done_func(sink
, todo_sync_done
);
516 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
517 OSyncPluginResource
*resource
= osync_plugin_config_find_active_resource(config
, "todo");
519 AutoOSyncList objformatsinks
= osync_plugin_resource_get_objformat_sinks(resource
);
521 bool hasObjFormat
= false;
524 for(r
= objformatsinks
.Get();r
;r
= r
->next
) {
525 OSyncObjFormatSink
*objformatsink
= (OSyncObjFormatSink
*) r
->data
;
527 if(!strcmp("vtodo20", osync_objformat_sink_get_objformat(objformatsink
))) {
537 // OSyncFormatEnv *formatenv = osync_plugin_info_get_format_env(info);
539 // env->format = osync_format_env_find_objformat(formatenv, "vtodo20");
540 env
->m_TodoSync
.sink
= sink
;
542 osync_objtype_sink_set_userdata(sink
, env
);
544 osync_objtype_sink_enable_hashtable(sink
, TRUE
);
552 //////////////////////////////////////////////////////////////////////////////
557 static void *initialize(OSyncPlugin
*plugin
, OSyncPluginInfo
*info
, OSyncError
**error
)
559 Trace
trace("initialize");
561 BarryEnvironment
*env
= 0;
564 env
= new BarryEnvironment(info
);
569 OSyncPluginConfig
*config
= osync_plugin_info_get_config(info
);
572 osync_error_set(error
, OSYNC_ERROR_GENERIC
, "Unable to get config.");
580 * Process plugin specific advanced options
582 AutoOSyncList optslist
= osync_plugin_config_get_advancedoptions(config
);
583 for (OSyncList
*o
= optslist
.Get(); o
; o
= o
->next
) {
584 OSyncPluginAdvancedOption
*option
= (OSyncPluginAdvancedOption
*) o
->data
;
586 const char *val
= osync_plugin_advancedoption_get_value(option
);
587 const char *name
= osync_plugin_advancedoption_get_name(option
);
589 if (!strcmp(name
, "PinCode")) {
590 env
->m_pin
= strtol(val
, NULL
, 16);
592 else if (!strcmp(name
, "Debug")) {
593 env
->m_DebugMode
= (!strcmp(val
, "1")) ? true : false;
597 OSyncPluginAuthentication
*optauth
= osync_plugin_config_get_authentication(config
);
599 if (osync_plugin_authentication_option_is_supported(optauth
, OSYNC_PLUGIN_AUTHENTICATION_PASSWORD
)) {
600 const char *val
= osync_plugin_authentication_get_password(optauth
);
602 env
->SetPassword(val
);
606 // FIXME - near the end of release, do a run with
607 // this set to true, and look for USB protocol
609 Barry::Init(env
->m_DebugMode
);
613 * Process Ressource options
615 trace
.log("Process Ressource options...");
617 if (barry_calendar_initialize(env
, info
, error
)) {
618 env
->m_CalendarSync
.m_Sync
= true;
621 trace
.log("No sync Calendar");
622 env
->m_CalendarSync
.m_Sync
= false;
625 if (barry_contact_initialize(env
, info
, error
)) {
626 env
->m_ContactsSync
.m_Sync
= true;
629 trace
.log("No sync Contact");
630 env
->m_ContactsSync
.m_Sync
= false;
633 if (barry_journal_initialize(env
, info
, error
)) {
634 env
->m_JournalSync
.m_Sync
= true;
637 trace
.log("No sync Journal");
638 env
->m_JournalSync
.m_Sync
= false;
641 if (barry_todo_initialize(env
, info
, error
)) {
642 env
->m_TodoSync
.m_Sync
= true;
645 trace
.log("No sync Todo");
646 env
->m_TodoSync
.m_Sync
= false;
651 // Don't let exceptions escape to the C modules
652 catch( std::bad_alloc
&ba
) {
653 trace
.logf("Unable to allocate memory for controller: %s", ba
.what());
657 catch( std::exception
&e
) {
658 trace
.logf("exception: %s", e
.what());
665 static osync_bool
discover(OSyncPluginInfo
*info
, void *userdata
, OSyncError
**error
)
667 Trace
trace("discover");
669 AutoOSyncList sinks
= osync_plugin_info_get_objtype_sinks(info
);
670 for (OSyncList
*s
= sinks
.Get(); s
; s
= s
->next
) {
671 OSyncObjTypeSink
*sink
= (OSyncObjTypeSink
*) s
->data
;
673 osync_objtype_sink_set_available(sink
, true);
676 OSyncVersion
*version
= osync_version_new(error
);
677 osync_version_set_plugin(version
, "Barry");
678 osync_version_set_modelversion(version
, "1");
679 //osync_version_set_firmwareversion(version, "firmwareversion");
680 //osync_version_set_softwareversion(version, "softwareversion");
681 //osync_version_set_hardwareversion(version, "hardwareversion");
682 osync_plugin_info_set_version(info
, version
);
683 osync_version_unref(version
);
689 static void connect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
691 Trace
trace("connect");
693 trace
.logf("%s(%p, %p, %p, %p)\n", __func__
, sink
, info
, ctx
, userdata
);
696 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
698 // I have to test if the device is already connected.
699 // Indeed, if I sync both contact and event, the connect
700 // function is called two times.
701 if (!env
->isConnected()) {
702 // Probe for available devices
704 int nIndex
= probe
.FindActive(env
->m_pin
);
706 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
, "Unable to find PIN %x", env
->m_pin
);
710 trace
.log("connecting...");
712 env
->Connect(probe
.Get(nIndex
));
714 trace
.log("connected !");
718 osync_context_report_success(ctx
);
720 trace
.log("connect success");
722 // Don't let exceptions escape to the C modules
723 catch( std::bad_alloc
&ba
) {
724 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
,
725 "Unable to allocate memory for controller: %s", ba
.what());
727 catch( std::exception
&e
) {
728 osync_context_report_error(ctx
, OSYNC_ERROR_NO_CONNECTION
,
734 static void contact_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
736 Trace
trace("contact_get_changeinfo");
739 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
741 GetChanges(sink
, info
, ctx
, env
, &env
->m_ContactsSync
,
742 "Address Book", "contact", "vcard30",
743 &VCardConverter::GetRecordData
,
747 osync_context_report_success(ctx
);
750 // don't let exceptions escape to the C modules
751 catch( std::exception
&e
) {
752 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
756 static void event_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
758 Trace
trace("event_get_changeinfo");
761 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
763 GetChanges(sink
, info
, ctx
, env
, &env
->m_CalendarSync
,
764 "Calendar", "event", "vevent20",
765 &VEventConverter::GetRecordData
,
769 osync_context_report_success(ctx
);
771 // don't let exceptions escape to the C modules
772 catch( std::exception
&e
) {
773 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
778 static void journal_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
780 Trace
trace("journal_get_changeinfo");
783 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
785 GetChanges(sink
, info
, ctx
, env
, &env
->m_JournalSync
,
786 "Memos", "note", "vjournal",
787 &VJournalConverter::GetRecordData
,
791 osync_context_report_success(ctx
);
793 // don't let exceptions escape to the C modules
794 catch( std::exception
&e
) {
795 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
800 static void todo_get_changes(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, osync_bool slow_sync
, void *userdata
)
802 Trace
trace("todo_get_changeinfo");
805 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
807 GetChanges(sink
, info
, ctx
, env
, &env
->m_TodoSync
,
808 "Tasks", "todo", "vtodo20",
809 &VTodoConverter::GetRecordData
,
813 osync_context_report_success(ctx
);
815 // don't let exceptions escape to the C modules
816 catch( std::exception
&e
) {
817 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
822 static void commit_change(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, OSyncChange
*change
, void *userdata
)
824 Trace
trace("commit_change");
826 // We can rely on a valid record state table, since get_changeinfo()
827 // will be called first, and will fill the table.
831 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
833 OSyncHashTable
*hashtable
= osync_objtype_sink_get_hashtable(sink
);
835 // find the needed commit function, based on objtype of the change
836 CommitData_t CommitData
= GetCommitFunction(change
);
838 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
839 "unable to get commit function pointer");
843 // find the matching cache, state table, and id map for this change
844 DatabaseSyncState
*pSync
= env
->GetSyncObject(change
);
846 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
847 "unable to get sync object that matches change type");
851 // is syncing turned on for this type?
852 if( !pSync
->m_Sync
) {
853 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
854 "This object type is disabled in the barry-sync config");
858 // make references instead of pointers
859 Barry::RecordStateTable
&table
= pSync
->m_Table
;
860 Barry::Mode::Desktop
&desktop
= *env
->GetDesktop();
861 unsigned int dbId
= pSync
->m_dbId
;
864 // either generate or retrieve the record ID, based on type
865 Barry::RecordStateTable::IndexType StateIndex
;
866 unsigned long RecordId
= 0;
867 if( osync_change_get_changetype(change
) == OSYNC_CHANGE_TYPE_ADDED
) {
868 // create new ID for this record
869 RecordId
= table
.MakeNewRecordId();
871 // tell opensync to save our ID
872 char *puid
= g_strdup_printf("%lu", RecordId
);
873 osync_change_set_uid(change
, puid
);
877 // extract RecordId from change's UID,
878 const char *uid
= osync_change_get_uid(change
);
879 trace
.logf("uid from change: %s", uid
);
881 // convert existing UID string to RecordId
882 if( strlen(uid
) == 0 ||
883 sscanf(uid
, "%lu", &RecordId
) != 1 ||
886 trace
.logf("Unable to extract a valid record ID from: %s", uid
);
887 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "Unable to extract a valid record ID from: %s", uid
);
891 // search for the RecordId in the state table, to find the
892 // index... we only need the index if we are deleting or
894 if( !table
.GetIndex(RecordId
, &StateIndex
) ) {
895 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
,
896 "unable to get state table index for RecordId: %lu",
902 // if we get here, we are about to update the device,
903 // and dirty flags will change in such a way that a
904 // reconnect will be required later... so flag this state
905 env
->RequireDirtyReconnect();
911 OSyncData
*odata
= NULL
;
914 switch( osync_change_get_changetype(change
) )
916 case OSYNC_CHANGE_TYPE_DELETED
:
917 desktop
.DeleteRecord(dbId
, StateIndex
);
920 case OSYNC_CHANGE_TYPE_ADDED
:
921 odata
= osync_change_get_data(change
);
922 osync_data_get_data(odata
, &plain
, NULL
);
923 status
= (*CommitData
)(env
, dbId
, StateIndex
, RecordId
,
924 plain
, true, errmsg
);
926 trace
.logf("CommitData() for ADDED state returned false: %s", errmsg
.c_str());
927 osync_context_report_error(ctx
, OSYNC_ERROR_PARAMETER
, "%s", errmsg
.c_str());
930 osync_change_set_hash(change
, "0");
933 case OSYNC_CHANGE_TYPE_MODIFIED
:
934 odata
= osync_change_get_data(change
);
935 osync_data_get_data(odata
, &plain
, NULL
);
936 status
= (*CommitData
)(env
, dbId
, StateIndex
, RecordId
,
937 plain
, false, errmsg
);
939 trace
.logf("CommitData() for MODIFIED state returned false: %s", errmsg
.c_str());
940 osync_context_report_error(ctx
, OSYNC_ERROR_PARAMETER
, "%s", errmsg
.c_str());
943 osync_change_set_hash(change
, "0");
947 trace
.log("Unknown change type");
952 osync_hashtable_update_change(hashtable
, change
);
955 osync_context_report_success(ctx
);
960 catch( std::exception
&e
) {
961 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
967 static void contact_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
970 // This function will only be called if the sync was successfull
973 Trace
trace("contact_sync_done");
977 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
979 // do cleanup for each database
980 if( FinishSync(ctx
, env
, &env
->m_ContactsSync
) )
983 osync_context_report_success(ctx
);
987 catch( std::exception
&e
) {
988 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
993 static void event_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
996 // This function will only be called if the sync was successfull
999 Trace
trace("event_sync_done");
1003 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
1005 // do cleanup for each database
1006 if( FinishSync(ctx
, env
, &env
->m_CalendarSync
) )
1009 osync_context_report_success(ctx
);
1013 catch( std::exception
&e
) {
1014 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
1019 static void journal_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
1022 // This function will only be called if the sync was successfull
1025 Trace
trace("journal_sync_done");
1029 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
1031 // do cleanup for each database
1032 if( FinishSync(ctx
, env
, &env
->m_JournalSync
) )
1035 osync_context_report_success(ctx
);
1039 catch( std::exception
&e
) {
1040 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
1045 static void todo_sync_done(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
1048 // This function will only be called if the sync was successfull
1051 Trace
trace("todo_sync_done");
1055 BarryEnvironment
*env
= (BarryEnvironment
*) userdata
;
1057 // do cleanup for each database
1058 if( FinishSync(ctx
, env
, &env
->m_TodoSync
) )
1061 osync_context_report_success(ctx
);
1065 catch( std::exception
&e
) {
1066 osync_context_report_error(ctx
, OSYNC_ERROR_IO_ERROR
, "%s", e
.what());
1071 static void disconnect(OSyncObjTypeSink
*sink
, OSyncPluginInfo
*info
, OSyncContext
*ctx
, void *userdata
)
1073 Trace
trace("contact_disconnect");
1076 osync_context_report_success(ctx
);
1080 static void finalize(void *data
)
1082 Trace
trace("finalize");
1084 BarryEnvironment
*env
= (BarryEnvironment
*) data
;
1086 // Disconnect the controller, which closes our connection
1087 if (env
->isConnected())
1094 osync_bool
get_sync_info(OSyncPluginEnv
*env
, OSyncError
**error
)
1096 Trace
trace("get_sync_info");
1098 // Create a new OpenSync plugin
1099 OSyncPlugin
*plugin
= osync_plugin_new(error
);
1101 trace
.log(osync_error_print(error
));
1105 // Describe our plugin
1106 osync_plugin_set_name(plugin
, "barry-sync");
1107 osync_plugin_set_longname(plugin
, "Barry OpenSync plugin v0.18.0 for the Blackberry handheld");
1108 osync_plugin_set_description(plugin
, "Plugin to synchronize note, task, calendar and contact entries on USB Blackberry handhelds");
1110 // Set the callback functions
1111 osync_plugin_set_initialize_func(plugin
, initialize
);
1112 osync_plugin_set_finalize_func(plugin
, finalize
);
1113 osync_plugin_set_discover_func(plugin
, discover
);
1114 osync_plugin_set_start_type(plugin
, OSYNC_START_TYPE_PROCESS
);
1116 if( !osync_plugin_env_register_plugin(env
, plugin
, error
) ) {
1117 trace
.log(osync_error_print(error
));
1121 osync_plugin_unref(plugin
);
1127 int get_version(void)