syncevolution/src/async.patch

533 lines
18 KiB
Diff
Raw Normal View History

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