From 7e0e61d87cad631380fcd6e32772ae66a5cc23f6 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Thu, 22 Feb 2007 19:33:21 +0000 Subject: [PATCH] patch switches to async version of the Evolution API git-svn-id: https://zeitsenke.de/svn/SyncEvolution/trunk@314 15ad00c4-1369-45f4-8270-35d70d36bdcd --- src/async.patch | 532 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 src/async.patch diff --git a/src/async.patch b/src/async.patch new file mode 100644 index 00000000..196ff767 --- /dev/null +++ b/src/async.patch @@ -0,0 +1,532 @@ +This patch demonstrates how switching from the current, synchronous +to the corresponding asynchronous API could work. This helps to +avoid some timeouts with EDS-DBus, but not all: the e_book_async_get_changes() +call still times out. + +Index: src/EvolutionContactSource.cpp +=================================================================== +RCS file: /cvsroot/sync4jevolution/sync4jevolution/src/EvolutionContactSource.cpp,v +retrieving revision 1.50 +diff -c -r1.50 EvolutionContactSource.cpp +*** src/EvolutionContactSource.cpp 3 Jan 2007 20:58:41 -0000 1.50 +--- src/EvolutionContactSource.cpp 22 Feb 2007 19:27:50 -0000 +*************** +*** 27,32 **** +--- 27,33 ---- + #ifdef ENABLE_EBOOK + + #include "EvolutionContactSource.h" ++ #include + + #include + #include "vocl/VConverter.h" +*************** +*** 154,159 **** +--- 155,207 ---- + } + } + ++ void EvolutionContactSource::addContacts(void *custom, GList *nextItem) ++ { ++ EvolutionContactSource *source = (EvolutionContactSource *)custom; ++ ++ while (nextItem) { ++ const char *uid = (const char *)e_contact_get_const(E_CONTACT(nextItem->data), ++ E_CONTACT_UID); ++ source->m_allItems.addItem(uid); ++ nextItem = nextItem->next; ++ } ++ } ++ ++ void EvolutionContactSource::addChanges(EBook *book, ++ EBookStatus status, ++ GList *nextItem, ++ gpointer custom) ++ { ++ EvolutionContactSource *source = (EvolutionContactSource *)custom; ++ source->m_status = status; ++ ++ while (nextItem) { ++ EBookChange *ebc = (EBookChange *)nextItem->data; ++ ++ if (ebc->contact) { ++ const char *uid = (const char *)e_contact_get_const( ebc->contact, E_CONTACT_UID ); ++ ++ if (uid) { ++ switch (ebc->change_type) { ++ case E_BOOK_CHANGE_CARD_ADDED: ++ source->m_newItems.addItem(uid); ++ break; ++ case E_BOOK_CHANGE_CARD_MODIFIED: ++ source->m_updatedItems.addItem(uid); ++ break; ++ case E_BOOK_CHANGE_CARD_DELETED: ++ source->m_deletedItems.addItem(uid); ++ break; ++ } ++ } ++ } ++ nextItem = nextItem->next; ++ } ++ ++ source->m_loop.quit(); ++ } ++ ++ + void EvolutionContactSource::beginSyncThrow(bool needAll, + bool needPartial, + bool deleteLocal) +*************** +*** 161,234 **** + GError *gerror = NULL; + + if (deleteLocal) { +! eptr allItemsQuery( e_book_query_any_field_contains(""), "query" ); +! GList *nextItem; +! if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) { +! throwError( "reading all items", gerror ); +! } +! while (nextItem) { +! const char *uid = (const char *)e_contact_get_const(E_CONTACT(nextItem->data), +! E_CONTACT_UID); +! if (!e_book_remove_contact( m_addressbook, uid, &gerror ) ) { +! throwError( string( "deleting contact " ) + uid, + gerror ); + } +- nextItem = nextItem->next; + } + } + + if (needAll) { +! eptr allItemsQuery( e_book_query_any_field_contains(""), "query" ); +! GList *nextItem; +! if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) { +! throwError( "reading all items", gerror ); +! } +! while (nextItem) { +! const char *uid = (const char *)e_contact_get_const(E_CONTACT(nextItem->data), +! E_CONTACT_UID); +! m_allItems.addItem(uid); +! nextItem = nextItem->next; +! } + } + + if (needPartial) { + GList *nextItem; + if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) { + throwError( "reading changes", gerror ); + } +! while (nextItem) { +! EBookChange *ebc = (EBookChange *)nextItem->data; +! +! if (ebc->contact) { +! const char *uid = (const char *)e_contact_get_const( ebc->contact, E_CONTACT_UID ); +! +! if (uid) { +! switch (ebc->change_type) { +! case E_BOOK_CHANGE_CARD_ADDED: +! m_newItems.addItem(uid); +! break; +! case E_BOOK_CHANGE_CARD_MODIFIED: +! m_updatedItems.addItem(uid); +! break; +! case E_BOOK_CHANGE_CARD_DELETED: +! m_deletedItems.addItem(uid); +! break; +! } +! } +! } +! nextItem = nextItem->next; + } + } + } + + void EvolutionContactSource::endSyncThrow() + { + if (m_isModified) { +- GError *gerror = NULL; +- GList *nextItem; + // move change_id forward so that our own changes are not listed the next time +! if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) { +! throwError( "reading changes", gerror ); + } + } + resetItems(); +--- 209,264 ---- + GError *gerror = NULL; + + if (deleteLocal) { +! m_allItems.clear(); +! listAllContacts(addContacts, this); +! +! EvolutionSyncSource::itemList::const_iterator it; +! for (it = m_allItems.begin(); +! it != m_allItems.end(); +! ++it) { +! if (!e_book_remove_contact( m_addressbook, it->c_str(), &gerror ) ) { +! throwError( string( "deleting contact " ) + *it, + gerror ); + } + } ++ m_allItems.clear(); + } + + if (needAll) { +! listAllContacts(addContacts, this); + } + + if (needPartial) { ++ #if 0 ++ // times out on N770 ++ GError *gerror = NULL; + GList *nextItem; + if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) { + throwError( "reading changes", gerror ); + } +! addChanges(m_addressbook, E_BOOK_ERROR_OK, nextItem, (gpointer)this); +! #else +! if (e_book_async_get_changes(m_addressbook, (char *)m_changeId.c_str(), addChanges, this)) { +! throwError( "reading changes", gerror ); + } ++ m_loop.run(); ++ if (m_status != E_BOOK_ERROR_OK) { ++ throw runtime_error("reading changes stopped with an error"); ++ } ++ #endif + } + } + + void EvolutionContactSource::endSyncThrow() + { + if (m_isModified) { + // move change_id forward so that our own changes are not listed the next time +! if (e_book_async_get_changes(m_addressbook, (char *)m_changeId.c_str(), addChanges, this)) { +! throw runtime_error("reading changes"); +! } +! m_loop.run(); +! if (m_status != E_BOOK_ERROR_OK) { +! throw runtime_error("reading changes stopped with an error"); + } + } + resetItems(); +*************** +*** 241,263 **** + m_addressbook = NULL; + } + +! void EvolutionContactSource::exportData(ostream &out) + { +! eptr allItemsQuery( e_book_query_any_field_contains(""), "query" ); +! GList *nextItem; +! GError *gerror = NULL; +! if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) { +! throwError( "reading all items", gerror ); +! } + while (nextItem) { + eptr vcardstr(e_vcard_to_string(&E_CONTACT(nextItem->data)->parent, + EVC_FORMAT_VCARD_30)); + +! out << (const char *)vcardstr << "\r\n\r\n"; + nextItem = nextItem->next; + } + } + + SyncItem *EvolutionContactSource::createItem( const string &uid, SyncState state ) + { + logItem( uid, "extracting from EV" ); +--- 271,296 ---- + m_addressbook = NULL; + } + +! +! static void dumpContacts(void *custom, GList *nextItem) + { +! ostream *out = (ostream *)custom; +! + while (nextItem) { + eptr vcardstr(e_vcard_to_string(&E_CONTACT(nextItem->data)->parent, + EVC_FORMAT_VCARD_30)); + +! *out << (const char *)vcardstr << "\r\n\r\n"; +! + nextItem = nextItem->next; + } + } + ++ void EvolutionContactSource::exportData(ostream &out) ++ { ++ listAllContacts(dumpContacts, (void *)&out); ++ } ++ + SyncItem *EvolutionContactSource::createItem( const string &uid, SyncState state ) + { + logItem( uid, "extracting from EV" ); +*************** +*** 773,776 **** +--- 806,876 ---- + } + } + ++ class EvolutionContactListAll { ++ public: ++ EvolutionContactListAll(void (*processList)(void *custom, GList *list), void *custom, EvolutionContactSource &source): ++ m_processList(processList), ++ m_custom(custom), ++ m_source(source), ++ m_status(E_BOOK_VIEW_STATUS_OK) ++ {} ++ ++ static void contactsAdded(EBookView *ebookview, ++ gpointer arg1, ++ gpointer user_data) { ++ EvolutionContactListAll *listAll = (EvolutionContactListAll *)user_data; ++ listAll->m_processList(listAll->m_custom, (GList *)arg1); ++ } ++ ++ static void sequenceDone(EBookView *ebookview, ++ gint arg1, ++ gpointer user_data) { ++ EvolutionContactListAll *listAll = (EvolutionContactListAll *)user_data; ++ listAll->m_status = (EBookViewStatus)arg1; ++ listAll->m_source.m_loop.quit(); ++ } ++ ++ /** throw an error exception if an error occurred */ ++ void checkStatus() { ++ if (m_status != E_BOOK_VIEW_STATUS_OK) { ++ throw runtime_error("iterating over all contacts failed"); ++ } ++ } ++ ++ private: ++ void (*m_processList)(void *custom, GList *list); ++ void *m_custom; ++ EvolutionContactSource &m_source; ++ EBookViewStatus m_status; ++ }; ++ ++ ++ ++ ++ ++ void EvolutionContactSource::listAllContacts(void (*processList)(void *custom, GList *list), void *custom) ++ { ++ eptr allItemsQuery( e_book_query_any_field_contains(""), "query" ); ++ GError *gerror = NULL; ++ EBookView *viewptr; ++ ++ if (e_book_get_book_view(m_addressbook, allItemsQuery, NULL, -1, &viewptr, &gerror)) { ++ eptr view(viewptr); ++ EvolutionContactListAll listAll(processList, custom, *this); ++ ++ g_signal_connect(viewptr, "contacts-added", G_CALLBACK(listAll.contactsAdded), &listAll); ++ g_signal_connect(viewptr, "sequence-complete", G_CALLBACK(listAll.sequenceDone), &listAll); ++ e_book_view_start(view); ++ m_loop.run(); ++ e_book_view_stop(view); ++ // workaround for http://bugzilla.gnome.org/show_bug.cgi?id=399011 ++ // Without the sleep() EDS often (but not always) crashes in e_book_backend_get_book_views() ++ // during one of the following calls. ++ sleep(1); ++ listAll.checkStatus(); ++ } else { ++ throwError( "getting view on addressbook", gerror ); ++ } ++ } ++ + #endif /* ENABLE_EBOOK */ +Index: src/EvolutionContactSource.h +=================================================================== +RCS file: /cvsroot/sync4jevolution/sync4jevolution/src/EvolutionContactSource.h,v +retrieving revision 1.22 +diff -c -r1.22 EvolutionContactSource.h +*** src/EvolutionContactSource.h 10 Dec 2006 17:35:18 -0000 1.22 +--- src/EvolutionContactSource.h 22 Feb 2007 19:27:50 -0000 +*************** +*** 32,37 **** +--- 32,49 ---- + #include + + /** ++ * callback used by EvolutionContactSource::listAll() and ++ */ ++ class EvolutionCallback ++ { ++ public: ++ /** ++ * Called to iterate over data. Content of list depends on context. ++ */ ++ virtual void processList(GList *list) = 0; ++ }; ++ ++ /** + * Implements access to Evolution address books. + */ + class EvolutionContactSource : public EvolutionSyncSource +*************** +*** 81,87 **** + // implementation of SyncSource + // + virtual ArrayElement *clone() { return new EvolutionContactSource(*this); } +! + protected: + // + // implementation of EvolutionSyncSource callbacks +--- 93,102 ---- + // implementation of SyncSource + // + virtual ArrayElement *clone() { return new EvolutionContactSource(*this); } +! +! /** start and stop event processing on this source */ +! EvolutionAsync m_loop; +! + protected: + // + // implementation of EvolutionSyncSource callbacks +*************** +*** 142,149 **** +--- 157,191 ---- + insert("CALURI"); + } + } m_uniqueProperties; ++ ++ /** ++ * extracts all contacts ++ * ++ * @param processList is fed the contacts, possibly in multiple chunks ++ * @param custom pointer passed through to processList ++ */ ++ void listAllContacts(void (*processList)(void *custom, GList *list), void *custom); ++ ++ /** ++ * callback for listAllContacts() which adds all contacts to m_allItems ++ */ ++ static void addContacts(void *custom, GList *nextItem); ++ ++ /** ++ * EBookListCallback for beginSyncThrow()'s e_book_async_get_changes () ++ */ ++ static void addChanges(EBook *book, ++ EBookStatus status, ++ GList *nextItem, ++ gpointer custom); ++ /** ++ * status passed to addChanges() ++ */ ++ EBookStatus m_status; + }; + ++ ++ + #endif // ENABLE_EBOOK + + #endif // INCL_EVOLUTIONCONTACTSOURCE +Index: src/EvolutionSmartPtr.h +=================================================================== +RCS file: /cvsroot/sync4jevolution/sync4jevolution/src/EvolutionSmartPtr.h,v +retrieving revision 1.8 +diff -c -r1.8 EvolutionSmartPtr.h +*** src/EvolutionSmartPtr.h 10 Dec 2006 17:35:19 -0000 1.8 +--- src/EvolutionSmartPtr.h 22 Feb 2007 19:27:50 -0000 +*************** +*** 34,39 **** +--- 34,40 ---- + + void inline unref( char *pointer ) { free( pointer ); } + void inline unref( GObject *pointer ) { g_object_unref( pointer ); } ++ void inline unref( GMainLoop *pointer ) { g_main_loop_unref( pointer ); } + #ifdef ENABLE_EBOOK + void inline unref( EBookQuery *pointer ) { e_book_query_unref( pointer ); } + #endif +Index: src/EvolutionSyncClient.cpp +=================================================================== +RCS file: /cvsroot/sync4jevolution/sync4jevolution/src/EvolutionSyncClient.cpp,v +retrieving revision 1.24 +diff -c -r1.24 EvolutionSyncClient.cpp +*** src/EvolutionSyncClient.cpp 17 Dec 2006 16:33:45 -0000 1.24 +--- src/EvolutionSyncClient.cpp 22 Feb 2007 19:27:50 -0000 +*************** +*** 432,438 **** + int res = DMTClientConfig::readDevInfoConfig(syncMLNode, syncMLNode); + + // always read device ID from the traditional property "deviceId" +! eptr tmp(syncMLNode.readPropertyValue("deviceId")); + deviceConfig.setDevID(tmp); + + return res; +--- 432,438 ---- + int res = DMTClientConfig::readDevInfoConfig(syncMLNode, syncMLNode); + + // always read device ID from the traditional property "deviceId" +! arrayptr tmp(syncMLNode.readPropertyValue("deviceId")); + deviceConfig.setDevID(tmp); + + return res; +*************** +*** 482,489 **** + // redirect logging as soon as possible + SourceList sourceList(m_server, m_doLogging); + +! eptr logdir(config.getSyncMLNode()->readPropertyValue("logdir")); +! eptr maxlogdirs(config.getSyncMLNode()->readPropertyValue("maxlogdirs")); + sourceList.setLogdir(logdir, atoi(maxlogdirs)); + + SyncSourceConfig *sourceconfigs = config.getSyncSourceConfigs(); +--- 482,489 ---- + // redirect logging as soon as possible + SourceList sourceList(m_server, m_doLogging); + +! arrayptr logdir(config.getSyncMLNode()->readPropertyValue("logdir")); +! arrayptr maxlogdirs(config.getSyncMLNode()->readPropertyValue("maxlogdirs")); + sourceList.setLogdir(logdir, atoi(maxlogdirs)); + + SyncSourceConfig *sourceconfigs = config.getSyncSourceConfigs(); +Index: src/EvolutionSyncSource.h +=================================================================== +RCS file: /cvsroot/sync4jevolution/sync4jevolution/src/EvolutionSyncSource.h,v +retrieving revision 1.24 +diff -c -r1.24 EvolutionSyncSource.h +*** src/EvolutionSyncSource.h 10 Dec 2006 17:35:19 -0000 1.24 +--- src/EvolutionSyncSource.h 22 Feb 2007 19:27:51 -0000 +*************** +*** 33,38 **** +--- 33,40 ---- + #include + #include + ++ #include ++ + /** + * This class implements the functionality shared by + * both EvolutionCalenderSource and EvolutionContactSource: +*************** +*** 371,374 **** +--- 373,400 ---- + string m_user, m_passwd; + }; + ++ /** ++ * Utility class which hides the mechanisms needed to handle events ++ * during asynchronous calls. ++ */ ++ class EvolutionAsync { ++ public: ++ EvolutionAsync() : ++ m_loop(g_main_loop_new(NULL, FALSE), "main loop") ++ {} ++ ++ /** start processing events */ ++ void run() { ++ g_main_loop_run(m_loop); ++ } ++ ++ /** stop processing events, to be called inside run() by callback */ ++ void quit() { ++ g_main_loop_quit(m_loop); ++ } ++ ++ private: ++ eptr m_loop; ++ }; ++ + #endif // INCL_EVOLUTIONSYNCSOURCE