syncevolution/src/async.patch
2007-02-22 19:33:21 +00:00

532 lines
18 KiB
Diff

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 <libebook/e-book-view.h>
#include <common/base/Log.h>
#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<EBookQuery> 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<EBookQuery> 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<EBookQuery> 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<char> 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<char> 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<EBookQuery> 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<EBookView, GObject> 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 <set>
/**
+ * 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<char> 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<char> tmp(syncMLNode.readPropertyValue("deviceId"));
deviceConfig.setDevID(tmp);
return res;
***************
*** 482,489 ****
// redirect logging as soon as possible
SourceList sourceList(m_server, m_doLogging);
! eptr<char> logdir(config.getSyncMLNode()->readPropertyValue("logdir"));
! eptr<char> 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<char> logdir(config.getSyncMLNode()->readPropertyValue("logdir"));
! arrayptr<char> 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 <spdm/ManagementNode.h>
#include <base/Log.h>
+ #include <EvolutionSmartPtr.h>
+
/**
* 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<GMainLoop> m_loop;
+ };
+
#endif // INCL_EVOLUTIONSYNCSOURCE