lib: added implicit ctor converter from DatabaseDatabase to DBListType
[barry/progweb.git] / desktop / src / os22.cc
blobb6899c84370841bc7e58be47ec24c0ec33d5ff67
1 ///
2 /// \file os22.cc
3 /// Wrapper class for opensync 0.22 syncing behaviour
4 ///
6 /*
7 Copyright (C) 2009-2012, Net Direct Inc. (http://www.netdirect.ca/)
9 Used code from msynctool (GPL v2+) as a guide to the API,
10 and copied some of its status messages and one function directly:
11 static const char *OSyncChangeType2String(OSyncChangeType c);
12 Copyright (C) 2004-2005 Armin Bauer <armin.bauer@opensync.org>
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 See the GNU General Public License in the COPYING file at the
24 root directory of this project for more details.
27 #include "os22.h"
28 #include "osprivatebase.h"
29 #include "osconv22.h"
30 #include <barry/vsmartptr.h>
31 #include <iostream>
32 #include <sstream>
33 #include <memory>
34 #include <glib.h>
36 // use relative paths to backtrack enough to specify only 0.22 includes
37 #include <../opensync-1.0/opensync/opensync.h>
38 #include <../opensync-1.0/osengine/engine.h>
40 using namespace std;
42 namespace OpenSync {
44 typedef Barry::vLateSmartPtr<OSyncEngine, void(*)(OSyncEngine*)> EngineHandle;
46 class OpenSync22Private
48 public:
49 // function pointers
50 const char* (*osync_get_version)();
51 OSyncEnv* (*osync_env_new)();
52 void (*osync_env_free)(OSyncEnv *env);
53 void (*osync_env_set_option)(OSyncEnv *env,
54 const char *name, const char *value);
55 osync_bool (*osync_env_finalize)(OSyncEnv *env,
56 OSyncError **error);
57 int (*osync_env_num_plugins)(OSyncEnv *env);
58 OSyncPlugin* (*osync_env_nth_plugin)(OSyncEnv *env, int nth);
59 const char* (*osync_plugin_get_name)(OSyncPlugin *plugin);
60 void (*osync_error_free)(OSyncError **error);
61 const char* (*osync_error_print)(OSyncError **error);
62 osync_bool (*osync_env_initialize)(OSyncEnv *env,
63 OSyncError **error);
64 int (*osync_env_num_groups)(OSyncEnv *env);
65 OSyncGroup* (*osync_env_nth_group)(OSyncEnv *env, int nth);
66 const char* (*osync_group_get_name)(OSyncGroup *group);
67 OSyncGroup* (*osync_env_find_group)(OSyncEnv *env,
68 const char *name);
69 int (*osync_group_num_members)(OSyncGroup *group);
70 OSyncMember* (*osync_group_nth_member)(OSyncGroup *group,
71 int nth);
72 long long int (*osync_member_get_id)(OSyncMember *member);
73 const char* (*osync_member_get_pluginname)(
74 OSyncMember *member);
75 OSyncFormatEnv* (*osync_conv_env_new)(OSyncEnv *env);
76 void (*osync_conv_env_free)(OSyncFormatEnv *env);
77 int (*osync_conv_num_objtypes)(OSyncFormatEnv *env);
78 OSyncObjType* (*osync_conv_nth_objtype)(OSyncFormatEnv *env,
79 int nth);
80 int (*osync_conv_num_objformats)(
81 OSyncObjType *type);
82 OSyncObjFormat* (*osync_conv_nth_objformat)(OSyncObjType *type,
83 int nth);
84 const char* (*osync_objformat_get_name)(
85 OSyncObjFormat *format);
86 const char* (*osync_objtype_get_name)(OSyncObjType *type);
87 OSyncGroup* (*osync_group_new)(OSyncEnv *env);
88 void (*osync_group_set_name)(OSyncGroup *group,
89 const char *name);
90 osync_bool (*osync_group_save)(OSyncGroup *group,
91 OSyncError **error);
92 osync_bool (*osync_group_delete)(OSyncGroup *group,
93 OSyncError **error);
94 OSyncMember* (*osync_member_new)(OSyncGroup *group);
95 osync_bool (*osync_member_instance_plugin)(
96 OSyncMember *member,
97 const char *pluginname,
98 OSyncError **error);
99 osync_bool (*osync_member_save)(OSyncMember *member,
100 OSyncError **error);
101 OSyncMember* (*osync_member_from_id)(OSyncGroup *group,
102 int id);
103 osync_bool (*osync_member_need_config)(OSyncMember *member,
104 OSyncConfigurationTypes *type,
105 OSyncError **error);
106 osync_bool (*osync_member_get_config_or_default)(
107 OSyncMember *member,
108 char **data, int *size,
109 OSyncError **error);
110 void (*osync_member_set_config)(OSyncMember *member,
111 const char *data, int size);
112 osync_bool (*osengine_mapping_ignore_supported)(
113 OSyncEngine *engine,
114 OSyncMapping *mapping);
115 osync_bool (*osengine_mapping_check_timestamps)(
116 OSyncEngine *engine,
117 OSyncMapping *mapping,
118 OSyncError **error);
119 OSyncChange* (*osengine_mapping_nth_change)(
120 OSyncMapping *mapping, int nth);
121 void (*osengine_mapping_solve)(OSyncEngine *engine,
122 OSyncMapping *mapping,
123 OSyncChange *change);
124 void (*osengine_mapping_duplicate)(
125 OSyncEngine *engine,
126 OSyncMapping *dupe_mapping);
127 osync_bool (*osengine_mapping_ignore_conflict)(
128 OSyncEngine *engine,
129 OSyncMapping *mapping,
130 OSyncError **error);
131 osync_bool (*osengine_mapping_solve_latest)(
132 OSyncEngine *engine,
133 OSyncMapping *mapping,
134 OSyncError **error);
135 const char* (*osync_change_get_uid)(OSyncChange *change);
136 osync_bool (*osengine_init)(OSyncEngine *engine,
137 OSyncError **error);
138 OSyncMember* (*osync_change_get_member)(OSyncChange *change);
139 int (*osync_change_get_datasize)(
140 OSyncChange *change);
141 OSyncEngine* (*osengine_new)(OSyncGroup *group,
142 OSyncError **error);
143 void (*osengine_free)(OSyncEngine *engine);
144 void (*osengine_finalize)(OSyncEngine *engine);
145 osync_bool (*osengine_sync_and_block)(OSyncEngine *engine,
146 OSyncError **error);
147 void (*osengine_set_memberstatus_callback)(
148 OSyncEngine *engine,
149 void (* function) (OSyncMemberUpdate *,
150 void *),
151 void *user_data);
152 void (*osengine_set_changestatus_callback)(
153 OSyncEngine *engine,
154 void (* function) (OSyncEngine *,
155 OSyncChangeUpdate *,
156 void *),
157 void *user_data);
158 void (*osengine_set_enginestatus_callback)(
159 OSyncEngine *engine,
160 void (* function) (OSyncEngine *,
161 OSyncEngineUpdate *,
162 void *),
163 void *user_data);
164 void (*osengine_set_mappingstatus_callback)(
165 OSyncEngine *engine,
166 void (* function) (OSyncMappingUpdate *,
167 void *),
168 void *user_data);
169 void (*osengine_set_conflict_callback)(
170 OSyncEngine *engine,
171 void (* function) (OSyncEngine *,
172 OSyncMapping *,
173 void *),
174 void *user_data);
175 int (*osengine_mapping_num_changes)(
176 OSyncMapping *mapping);
177 OSyncChangeType (*osync_change_get_changetype)(
178 OSyncChange *change);
179 char* (*osync_change_get_printable)(
180 OSyncChange *change);
181 void (*osync_group_set_objtype_enabled)(
182 OSyncGroup *group,
183 const char *objtypestr,
184 osync_bool enabled);
186 // data pointers
187 OSyncEnv *env;
189 Converter22 converter;
191 OpenSync22Private(OpenSync22 &api)
192 : env(0)
193 , converter(api)
198 class SyncConflict22Private : public SyncConflictPrivateBase
200 OpenSync22Private *m_priv;
201 OSyncEngine *m_engine;
202 OSyncMapping *m_mapping;
204 public:
205 SyncConflict22Private(OpenSync22Private *priv,
206 OSyncEngine *engine, OSyncMapping *mapping);
207 ~SyncConflict22Private();
209 virtual bool IsAbortSupported() const;
210 virtual bool IsIgnoreSupported() const;
211 virtual bool IsKeepNewerSupported() const;
213 virtual void Select(int change_id); // takes id of SyncChange object
214 virtual void Abort(); // not supported in 0.22
215 virtual void Duplicate();
216 virtual void Ignore();
217 virtual void KeepNewer();
219 void AppendChanges(std::vector<SyncChange> &list);
222 struct CallbackBundle22
224 OpenSync22Private *m_priv;
225 SyncStatus *m_status;
227 CallbackBundle22(OpenSync22Private *priv, SyncStatus &status)
228 : m_priv(priv)
229 , m_status(&status)
234 void member_status(OSyncMemberUpdate *, void *);
235 void entry_status(OSyncEngine *, OSyncChangeUpdate *, void *);
236 void engine_status(OSyncEngine *, OSyncEngineUpdate *,void *);
237 void mapping_status(OSyncMappingUpdate *, void *);
238 void conflict_handler(OSyncEngine *, OSyncMapping *, void *);
241 /////////////////////////////////////////////////////////////////////////////
242 // Static helper functions
244 static const char *OSyncChangeType2String(OSyncChangeType c)
246 switch (c) {
247 case CHANGE_ADDED: return "ADDED";
248 case CHANGE_UNMODIFIED: return "UNMODIFIED";
249 case CHANGE_DELETED: return "DELETED";
250 case CHANGE_MODIFIED: return "MODIFIED";
251 default:
252 case CHANGE_UNKNOWN: return "?";
256 /////////////////////////////////////////////////////////////////////////////
257 // SyncConflict22Private member functions
259 SyncConflict22Private::SyncConflict22Private(OpenSync22Private *priv,
260 OSyncEngine *engine, OSyncMapping *mapping)
261 : m_priv(priv)
262 , m_engine(engine)
263 , m_mapping(mapping)
267 SyncConflict22Private::~SyncConflict22Private()
271 bool SyncConflict22Private::IsAbortSupported() const
273 return false; // Abort not explicitly supported in 0.22
276 bool SyncConflict22Private::IsIgnoreSupported() const
278 return m_priv->osengine_mapping_ignore_supported(m_engine, m_mapping);
281 bool SyncConflict22Private::IsKeepNewerSupported() const
283 return m_priv->osengine_mapping_check_timestamps(m_engine, m_mapping, NULL);
286 void SyncConflict22Private::Select(int change_id)
288 OSyncChange *change = m_priv->osengine_mapping_nth_change(m_mapping, change_id);
289 if( !change ) {
290 throw std::runtime_error("Bad change_id, or error getting nth change object.");
293 m_priv->osengine_mapping_solve(m_engine, m_mapping, change);
296 void SyncConflict22Private::Abort()
298 throw std::logic_error("Conflict::Abort() not supported in 0.22");
301 void SyncConflict22Private::Duplicate()
303 m_priv->osengine_mapping_duplicate(m_engine, m_mapping);
306 void SyncConflict22Private::Ignore()
308 if( !IsIgnoreSupported() )
309 throw std::logic_error("Ignore not supported, yet Ignore() called.");
311 OSyncError *error = NULL;
312 if( !m_priv->osengine_mapping_ignore_conflict(m_engine, m_mapping, &error)) {
313 ostringstream oss;
314 oss << "Conflict not ignored: "
315 << m_priv->osync_error_print(&error);
316 m_priv->osync_error_free(&error);
317 throw std::runtime_error(oss.str());
321 void SyncConflict22Private::KeepNewer()
323 if( !IsKeepNewerSupported() )
324 throw std::logic_error("Keep Newer not supported, yet KeepNewer() called.");
326 OSyncError *error = NULL;
327 if( !m_priv->osengine_mapping_solve_latest(m_engine, m_mapping, &error)) {
328 ostringstream oss;
329 oss << "Conflict not resolved: "
330 << m_priv->osync_error_print(&error);
331 m_priv->osync_error_free(&error);
332 throw std::runtime_error(oss.str());
336 void SyncConflict22Private::AppendChanges(std::vector<SyncChange> &list)
338 for( int i = 0; i < m_priv->osengine_mapping_num_changes(m_mapping); i++ ) {
339 OSyncChange *change = m_priv->osengine_mapping_nth_change(m_mapping, i);
340 if( m_priv->osync_change_get_changetype(change) != CHANGE_UNKNOWN ) {
342 SyncChange entry;
344 char *printable = m_priv->osync_change_get_printable(change);
345 if( printable ) {
346 entry.printable_data = printable;
347 g_free(printable);
350 OSyncMember *member = m_priv->osync_change_get_member(change);
352 entry.id = i;
353 entry.member_id = m_priv->osync_member_get_id(member);
354 entry.plugin_name = m_priv->osync_member_get_pluginname(member);
355 entry.uid = m_priv->osync_change_get_uid(change);
357 // add to list
358 list.push_back(entry);
364 /////////////////////////////////////////////////////////////////////////////
365 // Callback functions
367 void member_status(OSyncMemberUpdate *status, void *cbdata)
369 CallbackBundle22 *cb = (CallbackBundle22*) cbdata;
371 try {
372 ostringstream oss;
373 bool error_event = false;
374 bool valid = true;
376 oss << "Member "
377 << cb->m_priv->osync_member_get_id(status->member)
378 << " ("
379 << cb->m_priv->osync_member_get_pluginname(status->member)
380 << ")";
382 switch( status->type )
384 case MEMBER_CONNECTED:
385 oss << " just connected";
386 break;
387 case MEMBER_DISCONNECTED:
388 oss << " just disconnected";
389 break;
390 case MEMBER_SENT_CHANGES:
391 oss << " just sent all changes";
392 break;
393 case MEMBER_COMMITTED_ALL:
394 oss << " committed all changes";
395 break;
396 case MEMBER_CONNECT_ERROR:
397 oss << " had an error while connecting: "
398 << cb->m_priv->osync_error_print(&status->error);
399 break;
400 case MEMBER_GET_CHANGES_ERROR:
401 oss << " had an error while getting changes: "
402 << cb->m_priv->osync_error_print(&status->error);
403 error_event = true;
404 break;
405 case MEMBER_SYNC_DONE_ERROR:
406 oss << " had an error while calling sync done: "
407 << cb->m_priv->osync_error_print(&status->error);
408 error_event = true;
409 break;
410 case MEMBER_DISCONNECT_ERROR:
411 oss << " had an error while disconnecting: "
412 << cb->m_priv->osync_error_print(&status->error);
413 error_event = true;
414 break;
415 case MEMBER_COMMITTED_ALL_ERROR:
416 oss << " had an error while commiting changes: "
417 << cb->m_priv->osync_error_print(&status->error);
418 error_event = true;
419 break;
420 default:
421 valid = false;
422 break;
425 // call the status handler
426 if( oss.str().size() && valid ) {
427 cb->m_status->MemberStatus(
428 cb->m_priv->osync_member_get_id(status->member),
429 cb->m_priv->osync_member_get_pluginname(status->member),
430 oss.str(), error_event);
433 catch( std::exception &e ) {
434 cb->m_status->ReportError(
435 string("member_status error: ") + e.what());
437 catch( ... ) {
438 cb->m_status->ReportError(
439 "Unknown exception caught in member_status()");
444 void entry_status(OSyncEngine *engine, OSyncChangeUpdate *status, void *cbdata)
446 CallbackBundle22 *cb = (CallbackBundle22*) cbdata;
448 try {
449 ostringstream oss;
451 OSyncMember *member = cb->m_priv->osync_change_get_member(status->change);
452 bool error_event = false;
454 switch( status->type )
456 case CHANGE_RECEIVED_INFO:
457 oss << "Received an entry "
458 << cb->m_priv->osync_change_get_uid(status->change)
459 << " without data from member "
460 << status->member_id
461 << " ("
462 << cb->m_priv->osync_member_get_pluginname(member)
463 << "). "
464 << "Changetype "
465 << OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change));
466 break;
467 case CHANGE_RECEIVED:
468 oss << "Received an entry "
469 << cb->m_priv->osync_change_get_uid(status->change)
470 << " with data of size "
471 << cb->m_priv->osync_change_get_datasize(status->change)
472 << " from member "
473 << status->member_id
474 << " ("
475 << cb->m_priv->osync_member_get_pluginname(member)
476 << "). Changetype "
477 << OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change));
478 break;
479 case CHANGE_SENT:
480 oss << "Sent an entry "
481 << cb->m_priv->osync_change_get_uid(status->change)
482 << " of size "
483 << cb->m_priv->osync_change_get_datasize(status->change)
484 << " to member "
485 << status->member_id
486 << " ("
487 << cb->m_priv->osync_member_get_pluginname(member)
488 << "). Changetype "
489 << OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change));
490 break;
491 case CHANGE_WRITE_ERROR:
492 error_event = true;
493 oss << "Error writing entry "
494 << cb->m_priv->osync_change_get_uid(status->change)
495 << " to member "
496 << status->member_id
497 << " ("
498 << cb->m_priv->osync_member_get_pluginname(member)
499 << "): "
500 << cb->m_priv->osync_error_print(&status->error);
501 break;
502 case CHANGE_RECV_ERROR:
503 error_event = true;
504 oss << "Error reading entry "
505 << cb->m_priv->osync_change_get_uid(status->change)
506 << " from member "
507 << status->member_id
508 << " ("
509 << cb->m_priv->osync_member_get_pluginname(member)
510 << "): "
511 << cb->m_priv->osync_error_print(&(status->error));
512 break;
515 // call the status handler
516 if( oss.str().size() ) {
517 cb->m_status->EntryStatus(oss.str(), error_event);
520 catch( std::exception &e ) {
521 cb->m_status->ReportError(
522 string("entry_status error:") + e.what());
524 catch( ... ) {
525 cb->m_status->ReportError(
526 "Unknown exception caught in entry_status()");
530 void engine_status(OSyncEngine *engine, OSyncEngineUpdate *status, void *cbdata)
532 CallbackBundle22 *cb = (CallbackBundle22*) cbdata;
534 try {
535 ostringstream oss;
536 bool error_event = false;
538 switch( status->type )
540 case ENG_PREV_UNCLEAN:
541 oss << "The previous synchronization was unclean. Slow-syncing.";
542 break;
543 case ENG_ENDPHASE_CON:
544 oss << "All clients connected or error";
545 break;
546 case ENG_END_CONFLICTS:
547 oss << "All conflicts have been reported";
548 break;
549 case ENG_ENDPHASE_READ:
550 oss << "All clients sent changes or error";
551 break;
552 case ENG_ENDPHASE_WRITE:
553 oss << "All clients have written";
554 break;
555 case ENG_ENDPHASE_DISCON:
556 oss << "All clients have disconnected";
557 break;
558 case ENG_SYNC_SUCCESSFULL:
559 oss << "The sync was successful";
560 break;
561 case ENG_ERROR:
562 oss << "The sync failed: "
563 << cb->m_priv->osync_error_print(&status->error);
564 error_event = true;
565 break;
568 // call the status handler
569 if( oss.str().size() )
570 cb->m_status->EngineStatus(oss.str(),
571 error_event,
572 status->type == ENG_PREV_UNCLEAN);
574 catch( std::exception &e ) {
575 cb->m_status->ReportError(
576 string("engine_status error: ") + e.what());
578 catch( ... ) {
579 cb->m_status->ReportError(
580 "Unknown exception caught in engine_status()");
584 void mapping_status(OSyncMappingUpdate *status, void *cbdata)
586 CallbackBundle22 *cb = (CallbackBundle22*) cbdata;
588 try {
589 ostringstream oss;
590 bool error_event = false;
592 switch( status->type )
594 case MAPPING_SOLVED:
595 oss << "Mapping solved";
596 break;
597 case MAPPING_SYNCED:
598 oss << "Mapping Synced";
599 break;
600 case MAPPING_WRITE_ERROR:
601 error_event = true;
602 oss << "Mapping Write Error: "
603 << cb->m_priv->osync_error_print(&status->error);
604 break;
607 // call the status handler
608 if( oss.str().size() )
609 cb->m_status->MappingStatus(oss.str(), error_event);
611 catch( std::exception &e ) {
612 cb->m_status->ReportError(
613 string("mapping_status error: ") + e.what());
615 catch( ... ) {
616 cb->m_status->ReportError(
617 "Unknown exception caught in mapping_status()");
621 void conflict_handler(OSyncEngine *engine, OSyncMapping *mapping, void *cbdata)
623 CallbackBundle22 *cb = (CallbackBundle22*) cbdata;
625 try {
626 // build the SyncConflict object
627 SyncConflict22Private scp(cb->m_priv, engine, mapping);
628 SyncConflict conflict(scp);
630 // append all conflicting changes as vector objects in the same
631 // order as the opensync library mapping
632 scp.AppendChanges(conflict);
634 // call the status handler
635 cb->m_status->HandleConflict(conflict);
637 catch( std::exception &e ) {
638 cb->m_status->ReportError(
639 string("Conflict not resolved. ") + e.what());
641 catch( ... ) {
642 cb->m_status->ReportError(
643 "Unknown exception caught in conflict_handler()");
648 /////////////////////////////////////////////////////////////////////////////
649 // OpenSync22 - public members
651 bool OpenSync22::symbols_loaded = false;
653 OpenSync22::OpenSync22()
655 if( !Open("libosengine.so.0") )
656 throw DlError("Can't dlopen libosengine.so.0");
658 // the symbol table is now thoroughly polluted...
659 symbols_loaded = true;
661 // store locally in case of constructor exception in LoadSym
662 std::auto_ptr<OpenSync22Private> p(new OpenSync22Private(*this));
664 // load all required symbols...
665 // we don't need to use try/catch here, since the base
666 // class destructor will clean up for us if LoadSym() throws
667 LoadSym(p->osync_get_version, "osync_get_version");
668 LoadSym(p->osync_env_new, "osync_env_new");
669 LoadSym(p->osync_env_free, "osync_env_free");
670 LoadSym(p->osync_env_set_option, "osync_env_set_option");
671 LoadSym(p->osync_env_finalize, "osync_env_finalize");
672 LoadSym(p->osync_env_num_plugins, "osync_env_num_plugins");
673 LoadSym(p->osync_env_nth_plugin, "osync_env_nth_plugin");
674 LoadSym(p->osync_plugin_get_name, "osync_plugin_get_name");
675 LoadSym(p->osync_error_free, "osync_error_free");
676 LoadSym(p->osync_error_print, "osync_error_print");
677 LoadSym(p->osync_env_initialize, "osync_env_initialize");
678 LoadSym(p->osync_env_num_groups, "osync_env_num_groups");
679 LoadSym(p->osync_env_nth_group, "osync_env_nth_group");
680 LoadSym(p->osync_group_get_name, "osync_group_get_name");
681 LoadSym(p->osync_env_find_group, "osync_env_find_group");
682 LoadSym(p->osync_group_num_members, "osync_group_num_members");
683 LoadSym(p->osync_group_nth_member, "osync_group_nth_member");
684 LoadSym(p->osync_member_get_id, "osync_member_get_id");
685 LoadSym(p->osync_member_get_pluginname, "osync_member_get_pluginname");
686 LoadSym(p->osync_conv_env_new, "osync_conv_env_new");
687 LoadSym(p->osync_conv_env_free, "osync_conv_env_free");
688 LoadSym(p->osync_conv_num_objtypes, "osync_conv_num_objtypes");
689 LoadSym(p->osync_conv_nth_objtype, "osync_conv_nth_objtype");
690 LoadSym(p->osync_conv_num_objformats, "osync_conv_num_objformats");
691 LoadSym(p->osync_conv_nth_objformat, "osync_conv_nth_objformat");
692 LoadSym(p->osync_objformat_get_name, "osync_objformat_get_name");
693 LoadSym(p->osync_objtype_get_name, "osync_objtype_get_name");
694 LoadSym(p->osync_group_new, "osync_group_new");
695 LoadSym(p->osync_group_set_name, "osync_group_set_name");
696 LoadSym(p->osync_group_save, "osync_group_save");
697 LoadSym(p->osync_group_delete, "osync_group_delete");
698 LoadSym(p->osync_member_new, "osync_member_new");
699 LoadSym(p->osync_member_instance_plugin,"osync_member_instance_plugin");
700 LoadSym(p->osync_member_save, "osync_member_save");
701 LoadSym(p->osync_member_from_id, "osync_member_from_id");
702 LoadSym(p->osync_member_need_config, "osync_member_need_config");
703 LoadSym(p->osync_member_get_config_or_default,
704 "osync_member_get_config_or_default");
705 LoadSym(p->osync_member_set_config, "osync_member_set_config");
706 LoadSym(p->osengine_mapping_ignore_supported,
707 "osengine_mapping_ignore_supported");
708 LoadSym(p->osengine_mapping_check_timestamps,
709 "osengine_mapping_check_timestamps");
710 LoadSym(p->osengine_mapping_nth_change, "osengine_mapping_nth_change");
711 LoadSym(p->osengine_mapping_solve, "osengine_mapping_solve");
712 LoadSym(p->osengine_mapping_duplicate, "osengine_mapping_duplicate");
713 LoadSym(p->osengine_mapping_ignore_conflict,
714 "osengine_mapping_ignore_conflict");
715 LoadSym(p->osengine_mapping_solve_latest,
716 "osengine_mapping_solve_latest");
717 LoadSym(p->osync_change_get_uid, "osync_change_get_uid");
718 LoadSym(p->osengine_init, "osengine_init");
719 LoadSym(p->osync_change_get_member, "osync_change_get_member");
720 LoadSym(p->osync_change_get_datasize, "osync_change_get_datasize");
721 LoadSym(p->osengine_new, "osengine_new");
722 LoadSym(p->osengine_free, "osengine_free");
723 LoadSym(p->osengine_finalize, "osengine_finalize");
724 LoadSym(p->osengine_sync_and_block, "osengine_sync_and_block");
725 LoadSym(p->osengine_set_memberstatus_callback,
726 "osengine_set_memberstatus_callback");
727 LoadSym(p->osengine_set_changestatus_callback,
728 "osengine_set_changestatus_callback");
729 LoadSym(p->osengine_set_enginestatus_callback,
730 "osengine_set_enginestatus_callback");
731 LoadSym(p->osengine_set_mappingstatus_callback,
732 "osengine_set_mappingstatus_callback");
733 LoadSym(p->osengine_set_conflict_callback,
734 "osengine_set_conflict_callback");
735 LoadSym(p->osengine_mapping_num_changes,
736 "osengine_mapping_num_changes");
737 LoadSym(p->osync_change_get_changetype, "osync_change_get_changetype");
738 LoadSym(p->osync_change_get_printable, "osync_change_get_printable");
739 LoadSym(p->osync_group_set_objtype_enabled,
740 "osync_group_set_objtype_enabled");
742 // do common initialization of opensync environment
743 SetupEnvironment(p.get());
745 // this pointer is ours now
746 m_priv = p.release();
749 OpenSync22::~OpenSync22()
751 // clean up opensync environment, closing plugins, etc.
752 if( m_priv->env ) {
753 m_priv->osync_env_finalize(m_priv->env, NULL);
754 m_priv->osync_env_free(m_priv->env);
757 // free private class data
758 delete m_priv;
759 m_priv = 0;
762 void OpenSync22::SetupEnvironment(OpenSync22Private *p)
764 // we are fully responsible for this pointer, since
765 // we run inside the constructor... only on success
766 // will responsibility be transferred to the destructor
767 p->env = p->osync_env_new();
768 if( !p->env )
769 throw std::runtime_error("Error allocating opensync 0.22 environment");
771 p->osync_env_set_option(p->env, "GROUPS_DIRECTORY", NULL);
772 p->osync_env_set_option(p->env, "LOAD_GROUPS", "TRUE");
773 p->osync_env_set_option(p->env, "LOAD_PLUGINS", "TRUE");
774 p->osync_env_set_option(p->env, "LOAD_FORMATS", "TRUE");
776 OSyncError *error = NULL;
777 if( !p->osync_env_initialize(p->env, &error) ) {
778 // grab error message
779 std::runtime_error err(m_priv->osync_error_print(&error));
781 // cleanup
782 p->osync_error_free(&error);
783 p->osync_env_free(m_priv->env);
785 // throw
786 throw err;
790 const char* OpenSync22::GetVersion() const
792 return m_priv->osync_get_version();
795 const char* OpenSync22::GetEngineName() const
797 return "0.22";
800 void OpenSync22::GetPluginNames(string_list_type &plugins)
802 // start fresh
803 plugins.clear();
805 OSyncPlugin *p;
806 for( int i = 0; i < m_priv->osync_env_num_plugins(m_priv->env); i++) {
807 p = m_priv->osync_env_nth_plugin(m_priv->env, i);
808 plugins.push_back(m_priv->osync_plugin_get_name(p));
812 void OpenSync22::GetFormats(format_list_type &formats)
814 // start fresh
815 formats.clear();
817 // cycle through all object types and simulate a 0.4x-like
818 // list based on the attached formats
820 OSyncFormatEnv *fenv = m_priv->osync_conv_env_new(m_priv->env);
821 if( !fenv ) {
822 throw std::runtime_error("GetFormats(): Unable to load format environment in GetFormats (22)");
825 for( int i = 0; i < m_priv->osync_conv_num_objtypes(fenv); i++ ) {
826 OSyncObjType *type = m_priv->osync_conv_nth_objtype(fenv, i);
828 for( int i = 0; i < m_priv->osync_conv_num_objformats(type); i++ ) {
829 OSyncObjFormat *format = m_priv->osync_conv_nth_objformat(type, i);
830 const char *objformat_name = m_priv->osync_objformat_get_name(format);
832 if( !formats.Find(objformat_name) ) {
833 Format new_format;
834 new_format.name = objformat_name;
835 new_format.object_type = m_priv->osync_objtype_get_name(type);
836 formats.push_back(new_format);
841 m_priv->osync_conv_env_free(fenv);
844 void OpenSync22::GetGroupNames(string_list_type &groups)
846 // start fresh
847 groups.clear();
849 OSyncGroup *g;
850 for( int i = 0; i < m_priv->osync_env_num_groups(m_priv->env); i++ ) {
851 g = m_priv->osync_env_nth_group(m_priv->env, i);
852 groups.push_back(m_priv->osync_group_get_name(g));
856 void OpenSync22::GetMembers(const std::string &group_name,
857 member_list_type &members)
859 // start fresh
860 members.clear();
862 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
863 if( !group ) {
864 throw std::runtime_error("GetMembers(): Unable to find group with name: " + group_name);
867 for( int i = 0; i < m_priv->osync_group_num_members(group); i++ ) {
868 OSyncMember *member = m_priv->osync_group_nth_member(group, i);
870 Member new_member;
872 new_member.group_name = group_name;
873 new_member.id = m_priv->osync_member_get_id(member);
874 new_member.plugin_name = m_priv->osync_member_get_pluginname(member);
876 // we are switching opensync's long long int ID to
877 // our long... to double check they are equal after
878 // the conversion
879 if( new_member.id != m_priv->osync_member_get_id(member) ) {
880 throw std::logic_error("GetMembers(): OpenSync's member ID is too large to fit in OpenSyncAPI (22)");
883 // add to member list
884 members.push_back(new_member);
888 void OpenSync22::AddGroup(const std::string &group_name)
890 if( m_priv->osync_env_find_group(m_priv->env, group_name.c_str()) )
891 throw std::runtime_error("AddGroup(): Group already exists: " + group_name);
893 OSyncGroup *group = m_priv->osync_group_new(m_priv->env);
894 m_priv->osync_group_set_name(group, group_name.c_str());
896 OSyncError *error = NULL;
897 if( !m_priv->osync_group_save(group, &error) ) {
898 // grab error message
899 std::runtime_error err(string("AddGroup(): Unable to save group: ") + m_priv->osync_error_print(&error));
901 // cleanup
902 m_priv->osync_error_free(&error);
904 throw err;
908 void OpenSync22::DeleteGroup(const std::string &group_name)
910 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
911 if( !group )
912 throw std::runtime_error("DeleteGroup(): Group not found: " + group_name);
914 OSyncError *error = NULL;
915 if( !m_priv->osync_group_delete(group, &error) ) {
916 std::runtime_error err(string("DeleteGroup(): Unable to delete group: ") + m_priv->osync_error_print(&error));
917 m_priv->osync_error_free(&error);
918 throw err;
922 Converter& OpenSync22::GetConverter()
924 return m_priv->converter;
927 long OpenSync22::AddMember(const std::string &group_name,
928 const std::string &plugin_name,
929 const std::string &member_name)
931 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
932 if( !group )
933 throw std::runtime_error("AddMember(): Group not found: " + group_name);
935 OSyncMember *member = m_priv->osync_member_new(group);
937 OSyncError *error = NULL;
938 if( !m_priv->osync_member_instance_plugin(member, plugin_name.c_str(), &error) ) {
939 std::runtime_error err(string("AddMember(): Unable to connect plugin with member ") + member_name + "/" + plugin_name + ": " + m_priv->osync_error_print(&error));
940 m_priv->osync_error_free(&error);
941 throw err;
944 if( !m_priv->osync_member_save(member, &error) ) {
945 std::runtime_error err(string("AddMember(): Unable to save member ") + member_name + "/" + plugin_name + ": " + m_priv->osync_error_print(&error));
946 m_priv->osync_error_free(&error);
947 throw err;
950 return m_priv->osync_member_get_id(member);
953 bool OpenSync22::IsConfigurable(const std::string &group_name,
954 long member_id)
956 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
957 if( !group )
958 throw std::runtime_error("Group not found: " + group_name);
960 OSyncMember *member = m_priv->osync_member_from_id(group, member_id);
961 if( !member ) {
962 ostringstream oss;
963 oss << "IsConfigurable(): Member " << member_id << " not found.";
964 throw std::runtime_error(oss.str());
967 OSyncConfigurationTypes type = NO_CONFIGURATION;
968 OSyncError *error = NULL;
969 if( !m_priv->osync_member_need_config(member, &type, &error) ) {
970 std::runtime_error err(string("Unable to determine needed config: ") + m_priv->osync_error_print(&error));
971 m_priv->osync_error_free(&error);
972 throw err;
975 return type != NO_CONFIGURATION;
978 std::string OpenSync22::GetConfiguration(const std::string &group_name,
979 long member_id)
981 if( !IsConfigurable(group_name, member_id) ) {
982 ostringstream oss;
983 oss << "GetConfiguration(): Member " << member_id << " of group '" << group_name << "' does not accept configuration.";
984 throw std::runtime_error(oss.str());
987 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
988 if( !group )
989 throw std::runtime_error("GetConfiguration(): Group not found: " + group_name);
991 OSyncMember *member = m_priv->osync_member_from_id(group, member_id);
992 if( !member ) {
993 ostringstream oss;
994 oss << "GetConfiguration(): Member " << member_id << " not found.";
995 throw std::runtime_error(oss.str());
998 OSyncError *error = NULL;
999 char *data = NULL;
1000 int size = 0;
1001 if( !m_priv->osync_member_get_config_or_default(member, &data, &size, &error)) {
1002 std::runtime_error err(string("GetConfiguration(): Unable to retrieve config: ") + m_priv->osync_error_print(&error));
1003 m_priv->osync_error_free(&error);
1004 throw err;
1007 std::string config(data, size);
1008 g_free(data);
1010 return config;
1013 void OpenSync22::SetConfiguration(const std::string &group_name,
1014 long member_id,
1015 const std::string &config_data)
1017 if( !IsConfigurable(group_name, member_id) ) {
1018 ostringstream oss;
1019 oss << "SetConfiguration(): Member " << member_id << " of group '" << group_name << "' does not accept configuration.";
1020 throw std::runtime_error(oss.str());
1023 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
1024 if( !group )
1025 throw std::runtime_error("SetConfiguration(): Group not found: " + group_name);
1027 OSyncMember *member = m_priv->osync_member_from_id(group, member_id);
1028 if( !member ) {
1029 ostringstream oss;
1030 oss << "SetConfiguration(): Member " << member_id << " not found.";
1031 throw std::runtime_error(oss.str());
1034 m_priv->osync_member_set_config(member, config_data.c_str(), config_data.size());
1036 OSyncError *error = NULL;
1037 if( !m_priv->osync_member_save(member, &error) ) {
1038 std::runtime_error err(string("SetConfiguration(): Unable to save member's config: ") + m_priv->osync_error_print(&error));
1039 m_priv->osync_error_free(&error);
1040 throw err;
1044 void OpenSync22::Discover(const std::string &group_name)
1046 // Discover is a successful noop on 0.22
1049 void OpenSync22::Sync(const std::string &group_name,
1050 SyncStatus &status_callback,
1051 Config::pst_type sync_types)
1053 OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str());
1054 if( !group )
1055 throw std::runtime_error("Sync(): Group not found: " + group_name);
1057 // enable/disable each objtype, as per sync_types
1058 if( !(sync_types & PST_DO_NOT_SET) ) {
1059 cerr << "enabling objtypes: " << sync_types << endl;
1060 m_priv->osync_group_set_objtype_enabled(group, "contact",
1061 (sync_types & PST_CONTACTS) ? TRUE : FALSE);
1062 m_priv->osync_group_set_objtype_enabled(group, "event",
1063 (sync_types & PST_EVENTS) ? TRUE : FALSE);
1064 m_priv->osync_group_set_objtype_enabled(group, "note",
1065 (sync_types & PST_NOTES) ? TRUE : FALSE);
1066 m_priv->osync_group_set_objtype_enabled(group, "todo",
1067 (sync_types & PST_TODOS) ? TRUE : FALSE);
1070 OSyncError *error = NULL;
1071 EngineHandle engine(m_priv->osengine_free);
1072 engine = m_priv->osengine_new(group, &error);
1073 if( !engine.get() ) {
1074 std::ostringstream oss;
1075 oss << "Error while synchronizing: "
1076 << m_priv->osync_error_print(&error);
1077 m_priv->osync_error_free(&error);
1078 throw std::runtime_error(oss.str());
1081 CallbackBundle22 cbdata(m_priv, status_callback);
1083 m_priv->osengine_set_memberstatus_callback(engine.get(),
1084 &member_status, &cbdata);
1085 m_priv->osengine_set_changestatus_callback(engine.get(),
1086 &entry_status, &cbdata);
1087 m_priv->osengine_set_enginestatus_callback(engine.get(),
1088 &engine_status, &cbdata);
1089 m_priv->osengine_set_mappingstatus_callback(engine.get(),
1090 &mapping_status, &cbdata);
1091 m_priv->osengine_set_conflict_callback(engine.get(),
1092 &conflict_handler, &cbdata);
1094 if( !m_priv->osengine_init(engine.get(), &error) ) {
1095 ostringstream oss;
1096 oss << "Error initializing osengine: "
1097 << m_priv->osync_error_print(&error);
1098 m_priv->osync_error_free(&error);
1099 throw std::runtime_error(oss.str());
1102 // successfully initialized, so finalize must be called
1103 EngineHandle initialized_engine(m_priv->osengine_finalize);
1104 initialized_engine = engine.get();
1106 if( !m_priv->osengine_sync_and_block(engine.get(), &error) ) {
1107 ostringstream oss;
1108 oss << "Error during sync: "
1109 << m_priv->osync_error_print(&error);
1110 m_priv->osync_error_free(&error);
1111 throw std::runtime_error(oss.str());
1115 } // namespace OpenSync