Resending due to mailing list size restriction and wrong email in the patch.
--- Hi, Please find attached an improved version of the patch. I improved the code related to the synchronous processing of the view signals. I did not really like the previous API. Note that I started work on the calendar equivalent but I noticed that there is currently no way to indicate that we are interested in the LAST-MODIFIED field. I commented on https://bugzilla.gnome.org/show_bug.cgi?id=652180. Kr, Chris.
From f84e07f4fbb674b48a033cfbdf16a4f06b7b3cf7 Mon Sep 17 00:00:00 2001 From: Christophe Dumez <[email protected]> Date: Fri, 5 Aug 2011 10:50:16 +0300 Subject: [PATCH] Support for the new EBookClient API in EDS 3.2 SyncEvolution EDS backend currently uses the EBook API which is deprecated as of EDS v3.2 and replaced by the new EBookClient API. This patch brings support for this new EBookClient API (when EDS 3.2 is detected at compile time). The new code based on the EBookClient API enables a few optimizations, especially the partial fetching of contacts to avoid useless DBus trafic. This results in better contact change tracking by fetching only the UID/REV attributes for each contact. Note: The new code uses the new GLibSupport header instead of the deprecated SmartPointer (eptr). --- src/backends/evolution/EvolutionContactSource.cpp | 311 +++++++++++++++++++-- src/backends/evolution/EvolutionContactSource.h | 12 + src/backends/evolution/EvolutionSyncSource.h | 28 ++ src/syncevo/GLibSupport.h | 78 +++++- src/syncevo/eds_abi_wrapper.h | 9 + 5 files changed, 411 insertions(+), 27 deletions(-) diff --git a/src/backends/evolution/EvolutionContactSource.cpp b/src/backends/evolution/EvolutionContactSource.cpp index 28fd082..8ded1dd 100644 --- a/src/backends/evolution/EvolutionContactSource.cpp +++ b/src/backends/evolution/EvolutionContactSource.cpp @@ -41,25 +41,8 @@ using namespace std; #include <boost/foreach.hpp> #include <syncevo/declarations.h> -SE_BEGIN_CXX - -class unrefEBookChanges { - public: - /** free list of EBookChange instances */ - static void unref(GList *pointer) { - if (pointer) { - GList *next = pointer; - do { - EBookChange *ebc = (EBookChange *)next->data; - g_object_unref(ebc->contact); - g_free(next->data); - next = next->next; - } while (next); - g_list_free(pointer); - } - } -}; +SE_BEGIN_CXX const EvolutionContactSource::extensions EvolutionContactSource::m_vcardExtensions; const EvolutionContactSource::unique EvolutionContactSource::m_uniqueProperties; @@ -78,7 +61,11 @@ EvolutionSyncSource::Databases EvolutionContactSource::getDatabases() { ESourceList *sources = NULL; +#ifdef USE_EBOOK_CLIENT + if (!e_book_client_get_sources(&sources, NULL)) { +#else if (!e_book_get_addressbooks(&sources, NULL)) { +#endif SyncContext::throwError("unable to access address books"); } @@ -120,6 +107,22 @@ EvolutionSyncSource::Databases EvolutionContactSource::getDatabases() // No results? Try system address book (workaround for embedded Evolution Dataserver). if (!result.size()) { +#ifdef USE_EBOOK_CLIENT + EBookClientCXX book; + const char *name; + + name = "<<system>>"; + book = EBookClientCXX::steal(e_book_client_new_system (NULL)); + if (!book) { + name = "<<default>>"; + book = EBookClientCXX::steal(e_book_client_new_default (NULL)); + } + + if (book) { + const char *uri = e_client_get_uri (E_CLIENT ((EBookClient*)book)); + result.push_back(Database(name, uri, true)); + } +#else eptr<EBook, GObject> book; GError *gerror = NULL; const char *name; @@ -137,6 +140,7 @@ EvolutionSyncSource::Databases EvolutionContactSource::getDatabases() const char *uri = e_book_get_uri (book); result.push_back(Database(name, uri, true)); } +#endif } else { // the first DB found is the default result[0].m_isDefault = true; @@ -145,8 +149,92 @@ EvolutionSyncSource::Databases EvolutionContactSource::getDatabases() return result; } +#ifdef USE_EBOOK_CLIENT +static void +handle_error_cb (EClient */*client*/, const gchar *error_msg, gpointer user_data) +{ + EvolutionContactSource *that = static_cast<EvolutionContactSource *>(user_data); + SE_LOG_ERROR(that, NULL, error_msg); +} + +static gboolean +handle_authentication_cb (EClient */*client*/, ECredentials *credentials, gpointer user_data) +{ + EvolutionContactSource *that = static_cast<EvolutionContactSource *>(user_data); + std::string user = that->getUser(); + std::string passwd = that->getPassword(); + + if (!user.empty() || !passwd.empty()) { + e_credentials_set (credentials, E_CREDENTIALS_KEY_USERNAME, user.c_str()); + e_credentials_set (credentials, E_CREDENTIALS_KEY_PASSWORD, passwd.c_str()); + return true; + } else { + return false; + } +} +#endif + void EvolutionContactSource::open() { +#ifdef USE_EBOOK_CLIENT + ESourceList *sources; + + if (!e_book_client_get_sources(&sources, NULL)) { + throwError("unable to access address books"); + } + + string id = getDatabaseID(); + ESource *source = findSource(sources, id); + bool onlyIfExists = true; + bool created = false; + GErrorCXX gerror; + if (!source) { + // might have been special "<<system>>" or "<<default>>", try that and + // creating address book from file:// URI before giving up + if (id.empty() || id == "<<system>>") { + m_addressbook = EBookClientCXX::steal(e_book_client_new_system (gerror)); + } else if (id.empty() || id == "<<default>>") { + m_addressbook = EBookClientCXX::steal(e_book_client_new_default (gerror)); + } else if (boost::starts_with(id, "file://")) { + m_addressbook = EBookClientCXX::steal(e_book_client_new_from_uri(id.c_str(), gerror)); + } else { + throwError(string(getName()) + ": no such address book: '" + id + "'"); + } + created = true; + onlyIfExists = false; + } else { + m_addressbook = EBookClientCXX::steal(e_book_client_new( source, gerror )); + } + + if (!gerror.isNull()) { + gerror.throwError("create addressbook"); + } + + // Listen for errors + g_signal_connect (m_addressbook, "backend-error", G_CALLBACK (handle_error_cb), this); + + // Handle authentication requests from the backend + g_signal_connect (m_addressbook, "authenticate", G_CALLBACK (handle_authentication_cb), this); + + // Open the address book + if (!e_client_open_sync( E_CLIENT ((EBookClient*)m_addressbook), onlyIfExists, NULL, gerror) ) { + if (created) { + // opening newly created address books often fails, try again once more + gerror.clear(); + sleep(5); + if (!e_client_open_sync( E_CLIENT ((EBookClient*)m_addressbook), onlyIfExists, NULL, gerror)) { + gerror.throwError("opening address book"); + } + } else { + gerror.throwError("opening address book"); + } + } + + g_signal_connect_after(m_addressbook, + "backend-died", + G_CALLBACK(SyncContext::fatalError), + (void *)"Evolution Data Server has died unexpectedly, contacts no longer available."); +#else ESourceList *sources; if (!e_book_get_addressbooks(&sources, NULL)) { throwError("unable to access address books"); @@ -223,6 +311,7 @@ void EvolutionContactSource::open() "backend-died", G_CALLBACK(SyncContext::fatalError), (void *)"Evolution Data Server has died unexpectedly, contacts no longer available."); +#endif } bool EvolutionContactSource::isEmpty() @@ -234,8 +323,126 @@ bool EvolutionContactSource::isEmpty() return revisions.empty(); } +#ifdef USE_EBOOK_CLIENT +class EBookClientViewSyncHandler { + public: + EBookClientViewSyncHandler(EBookClientView *view, + void (*processList)(const GSList *list, void *user_data), + void *user_data): + m_view(view), m_processList(processList), m_userData(user_data) {} + + bool process(GError **gerror) { + // Listen for view signals + g_signal_connect(m_view, "objects-added", G_CALLBACK(contactsAdded), this); + g_signal_connect(m_view, "complete", G_CALLBACK(completed), this); + + // Start the view + e_book_client_view_start (m_view, m_error); + if (!m_error.isNull()) { + g_propagate_error(gerror, m_error); + return false; + } + + // Async -> Sync + m_loop.run(); + e_book_client_view_stop (m_view, NULL); + + if (!m_error.isNull()) { + g_propagate_error(gerror, m_error); + return false; + } else { + return true; + } + } + + static void contactsAdded(EBookClientView *ebookview, + const GSList *contacts, + gpointer user_data) { + EBookClientViewSyncHandler *that = (EBookClientViewSyncHandler *)user_data; + that->m_processList(contacts, that->m_userData); + } + + static void completed(EBookClientView *ebookview, + const GError *error, + gpointer user_data) { + EBookClientViewSyncHandler *that = (EBookClientViewSyncHandler *)user_data; + that->m_error = error; + that->m_loop.quit(); + } + + public: + // Process list callback + void (*m_processList)(const GSList *contacts, void *user_data); + void *m_userData; + // Event loop for Async -> Sync + EvolutionAsync m_loop; + + private: + // View watched + EBookClientView *m_view; + // Possible error while watching the view + GErrorCXX m_error; +}; + +static void list_revisions(const GSList *contacts, void *user_data) +{ + EvolutionContactSource::RevisionMap_t *revisions = + static_cast<EvolutionContactSource::RevisionMap_t *>(user_data); + const GSList *l; + + for (l = contacts; l; l = l->next) { + EContact *contact = E_CONTACT(l->data); + if (!contact) { + SE_THROW("contact entry without data"); + } + pair<string, string> revmapping; + const char *uid = (const char *)e_contact_get_const(contact, + E_CONTACT_UID); + if (!uid || !uid[0]) { + SE_THROW("contact entry without UID"); + } + revmapping.first = uid; + const char *rev = (const char *)e_contact_get_const(contact, + E_CONTACT_REV); + if (!rev || !rev[0]) { + SE_THROW(string("contact entry without REV: ") + revmapping.first); + } + revmapping.second = rev; + revisions->insert(revmapping); + } +} + +#endif + void EvolutionContactSource::listAllItems(RevisionMap_t &revisions) { +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + EBookClientView *view; + + EBookQueryCXX allItemsQuery = EBookQueryCXX::steal(e_book_query_any_field_contains("")); + PlainGStr sexp(e_book_query_to_string (allItemsQuery)); + + if (!e_book_client_get_view_sync(m_addressbook, sexp, &view, NULL, gerror)) { + gerror.throwError( "getting the view" ); + } + EBookClientViewCXX viewPtr = EBookClientViewCXX::steal(view); + + // Optimization: set fields_of_interest (UID / REV) + GListCXX<const char, GSList> interesting_field_list; + interesting_field_list.push_back(e_contact_field_name (E_CONTACT_UID)); + interesting_field_list.push_back(e_contact_field_name (E_CONTACT_REV)); + e_book_client_view_set_fields_of_interest (viewPtr, interesting_field_list, gerror); + if (!gerror.isNull()) { + SE_LOG_ERROR(this, NULL, "e_book_client_view_set_fields_of_interest: %s", (const char*)gerror); + gerror.clear(); + } + + EBookClientViewSyncHandler handler(viewPtr, list_revisions, &revisions); + if (!handler.process(gerror)) { + gerror.throwError("watching view"); + } +#else GError *gerror = NULL; eptr<EBookQuery> allItemsQuery(e_book_query_any_field_contains(""), "query"); GList *nextItem; @@ -264,6 +471,7 @@ void EvolutionContactSource::listAllItems(RevisionMap_t &revisions) revisions.insert(revmapping); nextItem = nextItem->next; } +#endif } void EvolutionContactSource::close() @@ -274,6 +482,16 @@ void EvolutionContactSource::close() string EvolutionContactSource::getRevision(const string &luid) { EContact *contact; +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + if (!e_book_client_get_contact_sync(m_addressbook, + luid.c_str(), + &contact, + NULL, + gerror)) { + gerror.throwError(string("reading contact ") + luid); + } +#else GError *gerror = NULL; if (!e_book_get_contact(m_addressbook, luid.c_str(), @@ -282,6 +500,7 @@ string EvolutionContactSource::getRevision(const string &luid) throwError(string("reading contact ") + luid, gerror); } +#endif eptr<EContact, GObject> contactptr(contact, "contact"); const char *rev = (const char *)e_contact_get_const(contact, E_CONTACT_REV); @@ -294,6 +513,16 @@ string EvolutionContactSource::getRevision(const string &luid) void EvolutionContactSource::readItem(const string &luid, std::string &item, bool raw) { EContact *contact; +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + if (!e_book_client_get_contact_sync(m_addressbook, + luid.c_str(), + &contact, + NULL, + gerror)) { + gerror.throwError(string("reading contact ") + luid); + } +#else GError *gerror = NULL; if (!e_book_get_contact(m_addressbook, luid.c_str(), @@ -302,6 +531,7 @@ void EvolutionContactSource::readItem(const string &luid, std::string &item, boo throwError(string("reading contact ") + luid, gerror); } +#endif eptr<EContact, GObject> contactptr(contact, "contact"); eptr<char> vcardstr(e_vcard_to_string(&contactptr->parent, EVC_FORMAT_VCARD_30)); @@ -317,11 +547,29 @@ EvolutionContactSource::insertItem(const string &uid, const std::string &item, b { eptr<EContact, GObject> contact(e_contact_new_from_vcard(item.c_str())); if (contact) { - GError *gerror = NULL; e_contact_set(contact, E_CONTACT_UID, uid.empty() ? NULL : const_cast<char *>(uid.c_str())); +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + if (uid.empty()) { + gchar* newuid; + if (!e_book_client_add_contact_sync(m_addressbook, contact, &newuid, NULL, gerror)) { + gerror.throwError("add new contact"); + } + PlainGStr newuidPtr(newuid); + string newrev = getRevision(newuid); + return InsertItemResult(newuid, newrev, false); + } else { + if (!e_book_client_modify_contact_sync(m_addressbook, contact, NULL, gerror)) { + gerror.throwError("modify existing contact: "+ uid); + } + string newrev = getRevision(uid); + return InsertItemResult(uid, newrev, false); + } +#else + GError *gerror = NULL; if (uid.empty() ? e_book_add_contact(m_addressbook, contact, &gerror) : e_book_commit_contact(m_addressbook, contact, &gerror)) { @@ -337,6 +585,7 @@ EvolutionContactSource::insertItem(const string &uid, const std::string &item, b string("updating contact ") + uid, gerror); } +#endif } else { throwError(string("failure parsing vcard " ) + item); } @@ -346,6 +595,18 @@ EvolutionContactSource::insertItem(const string &uid, const std::string &item, b void EvolutionContactSource::removeItem(const string &uid) { +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + if (!e_book_client_remove_contact_by_uid_sync(m_addressbook, uid.c_str(), NULL, gerror)) { + if (gerror->domain == E_BOOK_CLIENT_ERROR && + gerror->code == E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND) { + SE_LOG_DEBUG(this, NULL, "%s: request to delete non-existant contact ignored", + uid.c_str()); + } else { + gerror.throwError( string( "deleting contact " ) + uid ); + } + } +#else GError *gerror = NULL; if (!e_book_remove_contact(m_addressbook, uid.c_str(), &gerror)) { if (gerror->domain == E_BOOK_ERROR && @@ -358,12 +619,23 @@ void EvolutionContactSource::removeItem(const string &uid) gerror ); } } +#endif } std::string EvolutionContactSource::getDescription(const string &luid) { try { EContact *contact; +#ifdef USE_EBOOK_CLIENT + GErrorCXX gerror; + if (!e_book_client_get_contact_sync(m_addressbook, + luid.c_str(), + &contact, + NULL, + gerror)) { + gerror.throwError(string("reading contact ") + luid); + } +#else GError *gerror = NULL; if (!e_book_get_contact(m_addressbook, luid.c_str(), @@ -372,6 +644,7 @@ std::string EvolutionContactSource::getDescription(const string &luid) throwError(string("reading contact ") + luid, gerror); } +#endif eptr<EContact, GObject> contactptr(contact, "contact"); const char *name = (const char *)e_contact_get_const(contact, E_CONTACT_FULL_NAME); if (name) { diff --git a/src/backends/evolution/EvolutionContactSource.h b/src/backends/evolution/EvolutionContactSource.h index 7d7b5ac..271935e 100644 --- a/src/backends/evolution/EvolutionContactSource.h +++ b/src/backends/evolution/EvolutionContactSource.h @@ -24,6 +24,7 @@ #include "config.h" #include "EvolutionSyncSource.h" #include <syncevo/SmartPtr.h> +#include <syncevo/GLibSupport.h> #include <boost/noncopyable.hpp> @@ -32,6 +33,13 @@ #include <set> #include <syncevo/declarations.h> + +#ifdef USE_EBOOK_CLIENT +SE_GOBJECT_TYPE(EBookClient) +SE_GOBJECT_TYPE(EBookClientView) +SE_GOBJECT_BASED_TYPE(EBookQuery, EBookQuery) +#endif + SE_BEGIN_CXX /** @@ -84,7 +92,11 @@ class EvolutionContactSource : public EvolutionSyncSource, std::string getRevision(const std::string &uid); /** valid after open(): the address book that this source references */ +#ifdef USE_EBOOK_CLIENT + EBookClientCXX m_addressbook; +#else eptr<EBook, GObject> m_addressbook; +#endif /** the format of vcards that new items are expected to have */ const EVCardFormat m_vcardFormat; diff --git a/src/backends/evolution/EvolutionSyncSource.h b/src/backends/evolution/EvolutionSyncSource.h index 64ed70c..475260f 100644 --- a/src/backends/evolution/EvolutionSyncSource.h +++ b/src/backends/evolution/EvolutionSyncSource.h @@ -25,6 +25,10 @@ #include <syncevo/eds_abi_wrapper.h> #include <syncevo/declarations.h> +#include <syncevo/GLibSupport.h> + +SE_GOBJECT_TYPE(GMainLoop) + SE_BEGIN_CXX @@ -85,6 +89,30 @@ class EvolutionSyncSource : public TrackingSyncSource #endif }; +/** + * Utility class which hides the mechanisms needed to handle events + * during asynchronous calls. + */ +class EvolutionAsync { + public: + EvolutionAsync() + { + m_loop = GMainLoopCXX::steal(g_main_loop_new(NULL, FALSE)); + } + + /** start processing events */ + void run() { + g_main_loop_run(m_loop.get()); + } + + /** stop processing events, to be called inside run() by callback */ + void quit() { + g_main_loop_quit(m_loop.get()); + } + + private: + GMainLoopCXX m_loop; +}; SE_END_CXX #endif // INCL_EVOLUTIONSYNCSOURCE diff --git a/src/syncevo/GLibSupport.h b/src/syncevo/GLibSupport.h index e050cb4..e4654e9 100644 --- a/src/syncevo/GLibSupport.h +++ b/src/syncevo/GLibSupport.h @@ -25,6 +25,7 @@ #endif #include <syncevo/util.h> +#include <syncevo/eds_abi_wrapper.h> #ifdef HAVE_GLIB # include <glib-object.h> @@ -33,6 +34,7 @@ typedef void *GMainLoop; #endif +#include <boost/shared_ptr.hpp> #include <boost/intrusive_ptr.hpp> #include <boost/utility.hpp> #include <boost/foreach.hpp> @@ -68,6 +70,21 @@ GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *ti #ifdef HAVE_GLIB +SE_END_CXX +/** static functions for handling (un)referencing of GObjects */ +class GObjectRef { + public: + // Regular GObject + static void ref(GObject *obj) { g_object_ref(obj); } + static void unref(GObject *obj) { g_object_unref(obj); } +#ifdef ENABLE_EBOOK + // EBookQuery + static void ref(EBookQuery *query) { e_book_query_ref(query); } + static void unref(EBookQuery *query) { e_book_query_unref(query); } +#endif +}; +SE_BEGIN_CXX + /** * Defines a shared pointer for a GObject-based type, with intrusive * reference counting. Use *outside* of SyncEvolution namespace @@ -76,7 +93,7 @@ GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *ti * *inside* the SyncEvolution namespace. * * Example: - * SE_GOBJECT_TYPE(GFile); + * SE_GOBJECT_TYPE(GFile) * SE_BEGIN_CXX * { * // reference normally increased during construction, @@ -86,21 +103,32 @@ GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *ti * // file freed here as filecxx gets destroyed * } * SE_END_CXX + * + * If the GObject-based type uses custom ref/unref functions, then use + * SE_GOBJECT_BASED_TYPE(_x, _base) macro instead and indicate the base. + * Make sure corresponding ref()/unref() functions are defined in the + * GObjectRef class. + * + * Example: + * SE_GOBJECT_BASED_TYPE(EBookQuery, EBookQuery) */ -#define SE_GOBJECT_TYPE(_x) \ - void inline intrusive_ptr_add_ref(_x *ptr) { g_object_ref(ptr); } \ - void inline intrusive_ptr_release(_x *ptr) { g_object_unref(ptr); } \ +#define SE_GOBJECT_BASED_TYPE(_x, _base) \ + void inline intrusive_ptr_add_ref(_x *ptr) { GObjectRef::ref((_base *)ptr); } \ + void inline intrusive_ptr_release(_x *ptr) { GObjectRef::unref((_base *)ptr); } \ SE_BEGIN_CXX \ class _x ## CXX : public boost::intrusive_ptr<_x> { \ public: \ _x ## CXX(_x *ptr, bool add_ref = true) : boost::intrusive_ptr<_x>(ptr, add_ref) {} \ _x ## CXX() {} \ _x ## CXX(const _x ## CXX &other) : boost::intrusive_ptr<_x>(other) {} \ + operator _x * () { return boost::intrusive_ptr<_x>::get(); } \ \ static _x ## CXX steal(_x *ptr) { return _x ## CXX(ptr, false); } \ }; \ SE_END_CXX \ +#define SE_GOBJECT_TYPE(_x) SE_GOBJECT_BASED_TYPE(_x, GObject) + SE_END_CXX SE_GOBJECT_TYPE(GFile) @@ -157,10 +185,23 @@ struct GErrorCXX { } return *this; } + GErrorCXX &operator =(const GError* err) { + if (m_gerror) { + g_clear_error(&m_gerror); + } + m_gerror = g_error_copy(err); + return *this; + } + + /** For convenient access to GError members (message, domain, ...) */ + GError* operator-> () const { return m_gerror; } /** error description, with fallback if not set (not expected, so not localized) */ operator const char * () { return m_gerror ? m_gerror->message : "<<no error>>"; } + /** Check if a gError was set */ + bool isNull() const { return m_gerror == NULL; } + /** clear error */ ~GErrorCXX() { g_clear_error(&m_gerror); } @@ -176,6 +217,11 @@ struct GErrorCXX { operator GError ** () { return &m_gerror; } /** + * Use this when passing GErrorCXX instance to C functions to read it. + */ + operator GError * () { return m_gerror; } + + /** * always throws an exception, including information from GError if available: * <action>: <error message>|failure */ @@ -183,6 +229,7 @@ struct GErrorCXX { }; template<class T> void NoopDestructor(T *) {} +template<class T> void GObjectDestructor(T *obj) { g_object_unref(obj); } /** * Wraps a G[S]List of pointers to a specific type. @@ -202,11 +249,11 @@ template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX static void listFree(GSList *l) { g_slist_free(l); } static void listFree(GList *l) { g_list_free(l); } - static GSList *listPrepend(GSList *list, T *entry) { return g_slist_prepend(list, static_cast<gpointer>(entry)); } - static GList *listPrepend(GList *list, T *entry) { return g_list_prepend(list, static_cast<gpointer>(entry)); } + static GSList *listPrepend(GSList *list, T *entry) { return g_slist_prepend(list, (gpointer)entry); } + static GList *listPrepend(GList *list, T *entry) { return g_list_prepend(list, (gpointer)entry); } - static GSList *listAppend(GSList *list, T *entry) { return g_slist_append(list, static_cast<gpointer>(entry)); } - static GList *listAppend(GList *list, T *entry) { return g_list_append(list, static_cast<gpointer>(entry)); } + static GSList *listAppend(GSList *list, T *entry) { return g_slist_append(list, (gpointer)entry); } + static GList *listAppend(GList *list, T *entry) { return g_list_append(list, (gpointer)entry); } public: typedef T * value_type; @@ -214,6 +261,8 @@ template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX /** empty error, NULL pointer */ GListCXX() : m_list(NULL) {} + GListCXX(L* l) : m_list(l) {} + /** free list */ ~GListCXX() { clear(); } @@ -289,6 +338,19 @@ template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX void push_front(T *entry) { m_list = listPrepend(m_list, entry); } }; +/** + * Wraps a C gchar array and takes care of freeing the memory. + */ +class PlainGStr : public boost::shared_ptr<gchar> +{ + public: + PlainGStr() {} + PlainGStr(gchar *str) : boost::shared_ptr<char>(str, g_free) {} + PlainGStr(const PlainGStr &other) : boost::shared_ptr<gchar>(other) {} + operator const gchar *() const { return &**this; } + const gchar *c_str() const { return &**this; } +}; + #endif diff --git a/src/syncevo/eds_abi_wrapper.h b/src/syncevo/eds_abi_wrapper.h index 69d56b7..451b0bf 100644 --- a/src/syncevo/eds_abi_wrapper.h +++ b/src/syncevo/eds_abi_wrapper.h @@ -52,11 +52,20 @@ #ifdef HAVE_EDS #include <glib-object.h> +#include <libedataserver/eds-version.h> #include <libedataserver/e-source.h> #include <libedataserver/e-source-list.h> +#if EDS_CHECK_VERSION(3,1,0) +#define USE_EBOOK_CLIENT 1 +#endif #ifdef ENABLE_EBOOK +#ifdef USE_EBOOK_CLIENT +#include <libebook/e-book-client.h> +#else #include <libebook/e-book.h> +#endif #include <libebook/e-vcard.h> +#include <libebook/e-book-query.h> #endif #ifdef ENABLE_ECAL # define HANDLE_LIBICAL_MEMORY 1 -- 1.7.6
_______________________________________________ SyncEvolution mailing list [email protected] http://lists.syncevolution.org/listinfo/syncevolution
