[evolution-data-server] EDataBook / EDataBookView: Added Direct Read Access APIs / support



commit ac48694373648fca68a87f2f829d65b2560a4e99
Author: Tristan Van Berkom <tristanvb openismus com>
Date:   Fri Feb 15 18:02:59 2013 +0900

    EDataBook / EDataBookView: Added Direct Read Access APIs / support
    
    EDataBook:
      Now can be created by the client and offers read only APIs for
      reading back contact data directly from a client side instantiated
      backend
    
    EDataBookView:
      Now use a special "x-evolution-uids-only" fields of interest in order
      to reduce D-Bus traffic, this makes it possible for EBookClientView
      to fetch contact data directly upon receival of notifications.

 addressbook/libedata-book/e-data-book-view.c |   22 +-
 addressbook/libedata-book/e-data-book.c      | 1035 ++++++++++++++++++++++----
 addressbook/libedata-book/e-data-book.h      |   69 ++
 3 files changed, 985 insertions(+), 141 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 93fed8e..34c0e6e 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -68,6 +68,7 @@ struct _EDataBookViewPrivate {
 
        /* which fields is listener interested in */
        GHashTable *fields_of_interest;
+       gboolean send_uids_only;
 };
 
 enum {
@@ -331,12 +332,19 @@ impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
                view->priv->fields_of_interest = NULL;
        }
 
+       view->priv->send_uids_only = FALSE;
+
        for (ii = 0; in_fields_of_interest[ii]; ii++) {
                const gchar *field = in_fields_of_interest[ii];
 
                if (!*field)
                        continue;
 
+               if (strcmp (field, "x-evolution-uids-only") == 0) {
+                       view->priv->send_uids_only = TRUE;
+                       continue;
+               }
+
                if (view->priv->fields_of_interest == NULL)
                        view->priv->fields_of_interest =
                                g_hash_table_new_full (
@@ -824,10 +832,12 @@ notify_change (EDataBookView *view,
                send_pending_changes (view);
        }
 
-       utf8_vcard = e_util_utf8_make_valid (vcard);
-       utf8_id = e_util_utf8_make_valid (id);
+       if (view->priv->send_uids_only == FALSE) {
+               utf8_vcard = e_util_utf8_make_valid (vcard);
+               g_array_append_val (view->priv->changes, utf8_vcard);
+       }
 
-       g_array_append_val (view->priv->changes, utf8_vcard);
+       utf8_id = e_util_utf8_make_valid (id);
        g_array_append_val (view->priv->changes, utf8_id);
 
        ensure_pending_flush_timeout (view);
@@ -881,9 +891,11 @@ notify_add (EDataBookView *view,
                        send_pending_adds (view);
                }
 
-               utf8_vcard = e_util_utf8_make_valid (vcard);
+               if (view->priv->send_uids_only == FALSE) {
+                       utf8_vcard = e_util_utf8_make_valid (vcard);
+                       g_array_append_val (view->priv->adds, utf8_vcard);
+               }
 
-               g_array_append_val (view->priv->adds, utf8_vcard);
                g_array_append_val (view->priv->adds, utf8_id_copy);
 
                ensure_pending_flush_timeout (view);
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 3918152..90da454 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -35,6 +35,7 @@
 #include "e-data-book-view.h"
 #include "e-book-backend.h"
 #include "e-book-backend-sexp.h"
+#include "e-book-backend-factory.h"
 
 #define E_DATA_BOOK_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -43,11 +44,15 @@
 struct _EDataBookPrivate {
        GDBusConnection *connection;
        EDBusAddressBook *dbus_interface;
+       EModule *direct_module;
+       EDataBookDirect *direct_book;
+
        EBookBackend *backend;
        gchar *object_path;
 
        GRecMutex pending_ops_lock;
        GHashTable *pending_ops; /* opid -> OperationData */
+       GHashTable *direct_ops; /* opid to DirectOperationData for still running operations */
 
        /* Operations are queued while an
         * open operation is in progress. */
@@ -109,8 +114,41 @@ typedef struct {
        } d;
 } OperationData;
 
+typedef struct {
+       GAsyncReadyCallback callback;
+       gpointer            user_data;
+       GCancellable       *cancellable;
+       GSimpleAsyncResult *result;
+
+       gboolean            is_sync_call;
+       gboolean            sync_call_complete;
+       GMutex              sync_result_mutex;
+       GCond               sync_result_condition;
+} DirectOperationData;
+
+/* EModule's can never be free'd, however the use count can change
+ * Here we ensure that there is only one ever created by way of
+ * static variables and locks
+ */
+static GHashTable *modules_table = NULL;
+G_LOCK_DEFINE (modules_table);
+
+
 /* Forward Declarations */
-static void    e_data_book_initable_init       (GInitableIface *interface);
+static void                 e_data_book_initable_init  (GInitableIface *interface);
+static DirectOperationData *direct_operation_data_push (EDataBook          *book,
+                                                       OperationID         opid,
+                                                       GAsyncReadyCallback callback,
+                                                       gpointer            user_data,
+                                                       GCancellable       *cancellable,
+                                                       gpointer            source_tag,
+                                                       gboolean            sync_call);
+static void                 direct_operation_data_free (DirectOperationData *data);
+static void                 direct_operation_complete  (DirectOperationData *data);
+static void                 direct_operation_wait      (DirectOperationData *data);
+static void                 e_data_book_respond_close  (EDataBook *book,
+                                                       guint opid,
+                                                       GError *error);
 
 G_DEFINE_TYPE_WITH_CODE (
        EDataBook,
@@ -120,6 +158,108 @@ G_DEFINE_TYPE_WITH_CODE (
                G_TYPE_INITABLE,
                e_data_book_initable_init))
 
+static EModule *
+load_module (const gchar *module_path)
+{
+       EModule *module = NULL;
+
+       G_LOCK (modules_table);
+
+       if (!modules_table)
+               modules_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       module = g_hash_table_lookup (modules_table, module_path);
+
+       if (!module) {
+               module = e_module_new (module_path);
+               if (!module)
+                       g_warning ("Failed to open EModule at path: %s", module_path);
+               else
+                       g_hash_table_insert (modules_table, g_strdup (module_path), module);
+       }
+
+       G_UNLOCK (modules_table);
+
+       return module;
+}
+
+static DirectOperationData *
+direct_operation_data_push (EDataBook          *book,
+                           OperationID         opid,
+                           GAsyncReadyCallback callback,
+                           gpointer            user_data,
+                           GCancellable       *cancellable,
+                           gpointer            source_tag,
+                           gboolean            sync_call)
+{
+       DirectOperationData *data;
+
+       data = g_slice_new (DirectOperationData);
+       data->callback = callback;
+       data->user_data = user_data;
+       data->cancellable = g_object_ref (cancellable);
+       data->result = g_simple_async_result_new (G_OBJECT (book),
+                                                 data->callback,
+                                                 data->user_data,
+                                                 source_tag);
+       data->is_sync_call = sync_call;
+       data->sync_call_complete = FALSE;
+
+       if (data->is_sync_call) {
+               g_mutex_init (&data->sync_result_mutex);
+               g_cond_init (&data->sync_result_condition);
+       }
+
+       g_hash_table_insert (book->priv->direct_ops, GUINT_TO_POINTER (opid), data);
+
+       return data;
+}
+
+static void
+direct_operation_data_free (DirectOperationData *data)
+{
+       if (data) {
+               if (data->is_sync_call) {
+                       g_mutex_clear (&data->sync_result_mutex);
+                       g_cond_clear (&data->sync_result_condition);
+               }
+
+               g_object_unref (data->result);
+               g_object_unref (data->cancellable);
+               g_slice_free (DirectOperationData, data);
+       }
+}
+
+static void
+direct_operation_complete (DirectOperationData *data)
+{
+       /* If it was a sync call, we have the calling thread
+        * waiting on the sync call condition, it's up to
+        * the sync call to free the data with direct_operation_data_free().
+        *
+        * Otherwise for async calls we need to complete
+        * in the calling thread.
+        */
+       if (data->is_sync_call) {
+               g_mutex_lock (&data->sync_result_mutex);
+               data->sync_call_complete = TRUE;
+               g_cond_signal (&data->sync_result_condition);
+               g_mutex_unlock (&data->sync_result_mutex);
+       } else {
+               g_simple_async_result_complete_in_idle (data->result);
+               direct_operation_data_free (data);
+       }
+}
+
+static void
+direct_operation_wait (DirectOperationData *data)
+{
+       g_mutex_lock (&data->sync_result_mutex);
+       while (data->sync_call_complete == FALSE)
+               g_cond_wait (&data->sync_result_condition, &data->sync_result_mutex);
+       g_mutex_unlock (&data->sync_result_mutex);
+}
+
 static gchar *
 construct_bookview_path (void)
 {
@@ -260,9 +400,11 @@ op_dispatch (EDataBook *book,
 
 static OperationData *
 op_claim (EDataBook *book,
-          guint32 opid)
+          guint32 opid,
+         DirectOperationData **direct)
 {
        OperationData *data;
+       DirectOperationData *direct_data;
 
        g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
 
@@ -278,16 +420,31 @@ op_claim (EDataBook *book,
                        book->priv->pending_ops,
                        GUINT_TO_POINTER (opid));
        }
+
+       direct_data = g_hash_table_lookup (
+               book->priv->direct_ops,
+               GUINT_TO_POINTER (opid));
+       if (direct_data != NULL) {
+               g_hash_table_steal (
+                        book->priv->direct_ops,
+                       GUINT_TO_POINTER (opid));
+       }
        g_rec_mutex_unlock (&book->priv->pending_ops_lock);
 
+       g_warn_if_fail (direct_data == NULL || direct != NULL);
+       if (direct)
+               *direct = direct_data;
+
        return data;
 }
 
-static void
+static DirectOperationData *
 op_complete (EDataBook *book,
              guint32 opid)
 {
-       g_return_if_fail (E_IS_DATA_BOOK (book));
+       DirectOperationData *direct_data;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
 
        e_operation_pool_release_opid (ops_pool, opid);
 
@@ -295,7 +452,18 @@ op_complete (EDataBook *book,
        g_hash_table_remove (
                book->priv->pending_ops,
                GUINT_TO_POINTER (opid));
+
+       direct_data = g_hash_table_lookup (
+               book->priv->direct_ops,
+               GUINT_TO_POINTER (opid));
+       if (direct_data != NULL) {
+               g_hash_table_steal (
+                        book->priv->direct_ops,
+                       GUINT_TO_POINTER (opid));
+       }
        g_rec_mutex_unlock (&book->priv->pending_ops_lock);
+
+       return direct_data;
 }
 
 static void
@@ -556,17 +724,59 @@ operation_thread (gpointer data,
 
                g_rec_mutex_unlock (&op->book->priv->pending_ops_lock);
 
-               e_dbus_address_book_complete_close (
-                       op->book->priv->dbus_interface,
-                       op->invocation);
+               if (op->book->priv->dbus_interface)
+                       e_dbus_address_book_complete_close (
+                               op->book->priv->dbus_interface,
+                               op->invocation);
 
-               op_complete (op->book, op->id);
+               /* Let direct calls return, notify the direct callers that it's closed */
+               e_data_book_respond_close (op->book, op->id, NULL);
                break;
        }
 
        op_unref (op);
 }
 
+static OperationData *
+op_direct_new (OperationID op,
+              EDataBook *book,
+              GCancellable *cancellable,
+              GAsyncReadyCallback callback,
+              gpointer user_data,
+              gpointer source_tag,
+              gboolean sync_call,
+              DirectOperationData **ret_data)
+{
+       OperationData *data;
+       DirectOperationData *direct_data;
+
+       data = g_slice_new0 (OperationData);
+       data->ref_count = 1;
+       data->op = op;
+       data->book = g_object_ref (book);
+       data->id = e_operation_pool_reserve_opid (ops_pool);
+
+       if (cancellable)
+               data->cancellable = g_object_ref (cancellable);
+       else
+               data->cancellable = g_cancellable_new ();
+
+       g_rec_mutex_lock (&book->priv->pending_ops_lock);
+       g_hash_table_insert (
+               book->priv->pending_ops,
+               GUINT_TO_POINTER (data->id),
+               op_ref (data));
+       direct_data = direct_operation_data_push (
+                book, data->id, callback, user_data,
+               data->cancellable, source_tag, sync_call);
+       g_rec_mutex_unlock (&book->priv->pending_ops_lock);
+
+       if (ret_data)
+               *ret_data = direct_data;
+
+       return data;
+}
+
 /**
  * e_data_book_status_to_string:
  *
@@ -910,12 +1120,13 @@ e_data_book_respond_open (EDataBook *book,
                           guint opid,
                           GError *error)
 {
+       DirectOperationData *direct = NULL;
        OperationData *data;
        GError *copy = NULL;
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, &direct);
        g_return_if_fail (data != NULL);
 
        /* Translators: This is prefix to a detailed error message */
@@ -924,16 +1135,38 @@ e_data_book_respond_open (EDataBook *book,
        /* This function is deprecated, but it's the only way to
         * set EBookBackend's internal 'opened' flag.  We should
         * be the only ones calling this. */
-       if (error != NULL)
+       if (error != NULL) {
+               data_book_convert_to_client_error (error);
                copy = g_error_copy (error);
+       }
        e_book_backend_notify_opened (book->priv->backend, copy);
 
-       if (error == NULL) {
+       if (direct) {
+               gboolean result = FALSE;
+
+               if (error) {
+                       g_simple_async_result_set_error (direct->result,
+                                                        error->domain,
+                                                        error->code,
+                                                        "%s", error->message);
+                       g_error_free (error);
+               } else {
+                       g_simple_async_result_set_check_cancellable (direct->result,
+                                                                    direct->cancellable);
+
+                       if (!g_cancellable_is_cancelled (direct->cancellable))
+                               result = TRUE;
+               }
+
+               g_simple_async_result_set_op_res_gboolean (direct->result, result);
+
+               /* Deliver the result to the caller */
+               direct_operation_complete (direct);
+       } else if (error == NULL) {
                e_dbus_address_book_complete_open (
                        book->priv->dbus_interface,
                        data->invocation);
        } else {
-               data_book_convert_to_client_error (error);
                g_dbus_method_invocation_take_error (
                        data->invocation, error);
        }
@@ -941,7 +1174,6 @@ e_data_book_respond_open (EDataBook *book,
        op_unref (data);
 
        /* Dispatch any pending operations. */
-
        g_mutex_lock (&book->priv->open_lock);
 
        if (opid == book->priv->open_opid) {
@@ -976,7 +1208,7 @@ e_data_book_respond_refresh (EDataBook *book,
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, NULL);
        g_return_if_fail (data != NULL);
 
        /* Translators: This is prefix to a detailed error message */
@@ -1012,7 +1244,7 @@ e_data_book_respond_get_backend_property (EDataBook *book,
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, NULL);
        g_return_if_fail (data != NULL);
 
        if (error == NULL) {
@@ -1051,17 +1283,46 @@ e_data_book_respond_get_contact (EDataBook *book,
                                  GError *error,
                                  const gchar *vcard)
 {
+       DirectOperationData *direct = NULL;
        OperationData *data;
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, &direct);
        g_return_if_fail (data != NULL);
 
-       /* Translators: This is prefix to a detailed error message */
-       g_prefix_error (&error, "%s", _("Cannot get contact: "));
+       if (error) {
+               /* Translators: This is prefix to a detailed error message */
+               g_prefix_error (&error, "%s", _("Cannot get contact: "));
+               data_book_convert_to_client_error (error);
+       }
 
-       if (error == NULL) {
+       if (direct) {
+
+               if (error) {
+                       g_simple_async_result_set_error (direct->result,
+                                                        error->domain,
+                                                        error->code,
+                                                        "%s", error->message);
+                       g_error_free (error);
+               } else {
+                       g_simple_async_result_set_check_cancellable (direct->result,
+                                                                    direct->cancellable);
+
+                       if (!g_cancellable_is_cancelled (direct->cancellable)) {
+                               EContact *contact;
+
+                               contact = e_contact_new_from_vcard (vcard);
+
+                               /* Give it an EContact for the return value */
+                               g_simple_async_result_set_op_res_gpointer (direct->result, contact, 
g_object_unref);
+                       }
+               }
+
+               /* Deliver the result to the caller */
+               direct_operation_complete (direct);
+
+       } else if (error == NULL) {
                gchar *utf8_vcard;
 
                utf8_vcard = e_util_utf8_make_valid (vcard);
@@ -1073,7 +1334,6 @@ e_data_book_respond_get_contact (EDataBook *book,
 
                g_free (utf8_vcard);
        } else {
-               data_book_convert_to_client_error (error);
                g_dbus_method_invocation_take_error (
                        data->invocation, error);
        }
@@ -1087,17 +1347,56 @@ e_data_book_respond_get_contact_list (EDataBook *book,
                                       GError *error,
                                       const GSList *cards)
 {
+       DirectOperationData *direct = NULL;
        OperationData *data;
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, &direct);
        g_return_if_fail (data != NULL);
 
-       /* Translators: This is prefix to a detailed error message */
-       g_prefix_error (&error, "%s", _("Cannot get contact list: "));
+       if (error) {
+               /* Translators: This is prefix to a detailed error message */
+               g_prefix_error (&error, "%s", _("Cannot get contact list: "));
+               data_book_convert_to_client_error (error);
+       }
 
-       if (error == NULL) {
+       if (direct) {
+
+               if (error) {
+                       g_simple_async_result_set_error (direct->result,
+                                                        error->domain,
+                                                        error->code,
+                                                        "%s", error->message);
+                       g_error_free (error);
+               } else {
+                       g_simple_async_result_set_check_cancellable (direct->result,
+                                                                    direct->cancellable);
+
+                       if (!g_cancellable_is_cancelled (direct->cancellable)) {
+                               EContact *contact;
+                               const GSList *l;
+                               GSList *contacts = NULL;
+
+                               for (l = cards; l; l = l->next) {
+                                       const gchar *vcard = l->data;
+
+                                       contact = e_contact_new_from_vcard (vcard);
+                                       contacts = g_slist_prepend (contacts, contact);
+                               }
+
+                               contacts = g_slist_reverse (contacts);
+
+                               /* Give it an EContact for the return value */
+                               g_simple_async_result_set_op_res_gpointer (direct->result, contacts,
+                                                                          
(GDestroyNotify)e_util_free_object_slist);
+                       }
+               }
+
+               /* Deliver the result to the caller */
+               direct_operation_complete (direct);
+
+       } else if (error == NULL) {
                gchar **strv;
                guint length;
                gint ii = 0;
@@ -1117,7 +1416,6 @@ e_data_book_respond_get_contact_list (EDataBook *book,
 
                g_strfreev (strv);
        } else {
-               data_book_convert_to_client_error (error);
                g_dbus_method_invocation_take_error (
                        data->invocation, error);
        }
@@ -1138,17 +1436,46 @@ e_data_book_respond_get_contact_list_uids (EDataBook *book,
                                            GError *error,
                                            const GSList *uids)
 {
+       DirectOperationData *direct = NULL;
        OperationData *data;
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, &direct);
        g_return_if_fail (data != NULL);
 
-       /* Translators: This is prefix to a detailed error message */
-       g_prefix_error (&error, "%s", _("Cannot get contact list uids: "));
+       if (error) {
+               /* Translators: This is prefix to a detailed error message */
+               g_prefix_error (&error, "%s", _("Cannot get contact list uids: "));
+               data_book_convert_to_client_error (error);
+       }
 
-       if (error == NULL) {
+       if (direct) {
+
+               if (error) {
+                       g_simple_async_result_set_error (direct->result,
+                                                        error->domain,
+                                                        error->code,
+                                                        "%s", error->message);
+                       g_error_free (error);
+               } else {
+                       g_simple_async_result_set_check_cancellable (direct->result,
+                                                                    direct->cancellable);
+
+                       if (!g_cancellable_is_cancelled (direct->cancellable)) {
+                               GSList *ret_uids = NULL;
+
+                               ret_uids = e_util_copy_string_slist (NULL, uids);
+
+                               g_simple_async_result_set_op_res_gpointer (direct->result, ret_uids,
+                                                                          
(GDestroyNotify)e_util_free_string_slist);
+                       }
+               }
+
+               /* Deliver the result to the caller */
+               direct_operation_complete (direct);
+
+       } else if (error == NULL) {
                gchar **strv;
                guint length;
                gint ii = 0;
@@ -1168,7 +1495,6 @@ e_data_book_respond_get_contact_list_uids (EDataBook *book,
 
                g_strfreev (strv);
        } else {
-               data_book_convert_to_client_error (error);
                g_dbus_method_invocation_take_error (
                        data->invocation, error);
        }
@@ -1193,7 +1519,7 @@ e_data_book_respond_create_contacts (EDataBook *book,
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, NULL);
        g_return_if_fail (data != NULL);
 
        /* Translators: This is prefix to a detailed error message */
@@ -1256,7 +1582,7 @@ e_data_book_respond_modify_contacts (EDataBook *book,
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, NULL);
        g_return_if_fail (data != NULL);
 
        /* Translators: This is prefix to a detailed error message */
@@ -1297,7 +1623,7 @@ e_data_book_respond_remove_contacts (EDataBook *book,
 
        g_return_if_fail (E_IS_DATA_BOOK (book));
 
-       data = op_claim (book, opid);
+       data = op_claim (book, opid, NULL);
        g_return_if_fail (data != NULL);
 
        /* Translators: This is prefix to a detailed error message */
@@ -1463,17 +1789,18 @@ static void
 data_book_set_connection (EDataBook *book,
                           GDBusConnection *connection)
 {
-       g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+       g_return_if_fail (connection == NULL ||
+                         G_IS_DBUS_CONNECTION (connection));
        g_return_if_fail (book->priv->connection == NULL);
 
-       book->priv->connection = g_object_ref (connection);
+       if (connection)
+               book->priv->connection = g_object_ref (connection);
 }
 
 static void
 data_book_set_object_path (EDataBook *book,
                            const gchar *object_path)
 {
-       g_return_if_fail (object_path != NULL);
        g_return_if_fail (book->priv->object_path == NULL);
 
        book->priv->object_path = g_strdup (object_path);
@@ -1557,6 +1884,16 @@ data_book_dispose (GObject *object)
                priv->backend = NULL;
        }
 
+       if (priv->direct_book) {
+               g_object_unref (priv->direct_book);
+               priv->direct_book = NULL;
+       }
+
+       if (priv->direct_module) {
+               g_type_module_unuse (G_TYPE_MODULE (priv->direct_module));
+               priv->direct_module = NULL;
+       }
+
        /* Chain up to parent's dispose() metnod. */
        G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
 }
@@ -1576,6 +1913,10 @@ data_book_finalize (GObject *object)
        }
 
        g_rec_mutex_clear (&priv->pending_ops_lock);
+       if (priv->direct_ops) {
+               g_hash_table_destroy (priv->direct_ops);
+               priv->direct_ops = NULL;
+       }
 
        if (priv->dbus_interface) {
                g_object_unref (priv->dbus_interface);
@@ -1591,77 +1932,119 @@ data_book_finalize (GObject *object)
        G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object);
 }
 
-static void
-data_book_constructed (GObject *object)
-{
-       EDataBook *book = E_DATA_BOOK (object);
-       OperationData *op;
-
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_data_book_parent_class)->constructed (object);
-
-       g_object_bind_property (
-               book->priv->backend, "cache-dir",
-               book->priv->dbus_interface, "cache-dir",
-               G_BINDING_SYNC_CREATE);
-
-       g_object_bind_property (
-               book->priv->backend, "online",
-               book->priv->dbus_interface, "online",
-               G_BINDING_SYNC_CREATE);
-
-       g_object_bind_property (
-               book->priv->backend, "writable",
-               book->priv->dbus_interface, "writable",
-               G_BINDING_SYNC_CREATE);
-
-       /* XXX Initialize the rest of the properties by faking client
-        *     requests.  At present it's the only way to fish values
-        *     from EBookBackend's antiquated API. */
-
-       op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
-       op->d.prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
-       e_book_backend_get_backend_property (
-               book->priv->backend, book, op->id,
-               op->cancellable, op->d.prop_name);
-       op_unref (op);
-
-       op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
-       op->d.prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
-       e_book_backend_get_backend_property (
-               book->priv->backend, book, op->id,
-               op->cancellable, op->d.prop_name);
-       op_unref (op);
-
-       op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
-       op->d.prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
-       e_book_backend_get_backend_property (
-               book->priv->backend, book, op->id,
-               op->cancellable, op->d.prop_name);
-       op_unref (op);
-
-       op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
-       op->d.prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
-       e_book_backend_get_backend_property (
-               book->priv->backend, book, op->id,
-               op->cancellable, op->d.prop_name);
-       op_unref (op);
-}
-
 static gboolean
 data_book_initable_init (GInitable *initable,
                          GCancellable *cancellable,
                          GError **error)
 {
        EDataBook *book;
+       OperationData *op;
 
        book = E_DATA_BOOK (initable);
 
-       return g_dbus_interface_skeleton_export (
-               G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
-               book->priv->connection,
-               book->priv->object_path,
-               error);
+       if (book->priv->connection && book->priv->object_path) {
+               book->priv->dbus_interface = e_dbus_address_book_skeleton_new ();
+
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-open",
+                       G_CALLBACK (data_book_handle_open_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-refresh",
+                       G_CALLBACK (data_book_handle_refresh_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-get-contact",
+                       G_CALLBACK (data_book_handle_get_contact_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-get-contact-list",
+                       G_CALLBACK (data_book_handle_get_contact_list_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-get-contact-list-uids",
+                       G_CALLBACK (data_book_handle_get_contact_list_uids_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-create-contacts",
+                       G_CALLBACK (data_book_handle_create_contacts_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-remove-contacts",
+                       G_CALLBACK (data_book_handle_remove_contacts_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-modify-contacts",
+                       G_CALLBACK (data_book_handle_modify_contacts_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-get-view",
+                       G_CALLBACK (data_book_handle_get_view_cb), book);
+               g_signal_connect (
+                       book->priv->dbus_interface, "handle-close",
+                       G_CALLBACK (data_book_handle_close_cb), book);
+
+               /* This will be NULL for a backend that does not support direct read access */
+               book->priv->direct_book =
+                       e_book_backend_get_direct_book (book->priv->backend);
+
+               if (book->priv->direct_book) {
+
+                       if (!e_data_book_direct_register_gdbus_object (
+                                    book->priv->direct_book,
+                                    book->priv->connection,
+                                    book->priv->object_path,
+                                    error))
+                               return FALSE;
+               }
+
+               g_object_bind_property (
+                       book->priv->backend, "cache-dir",
+                       book->priv->dbus_interface, "cache-dir",
+                       G_BINDING_SYNC_CREATE);
+
+               g_object_bind_property (
+                       book->priv->backend, "online",
+                       book->priv->dbus_interface, "online",
+                       G_BINDING_SYNC_CREATE);
+
+               g_object_bind_property (
+                       book->priv->backend, "writable",
+                       book->priv->dbus_interface, "writable",
+                       G_BINDING_SYNC_CREATE);
+
+               /* XXX Initialize the rest of the properties by faking client
+                *     requests.  At present it's the only way to fish values
+                *     from EBookBackend's antiquated API. */
+
+               op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
+               op->d.prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
+               e_book_backend_get_backend_property (
+                       book->priv->backend, book, op->id,
+                       op->cancellable, op->d.prop_name);
+               op_unref (op);
+
+               op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
+               op->d.prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
+               e_book_backend_get_backend_property (
+                       book->priv->backend, book, op->id,
+                       op->cancellable, op->d.prop_name);
+               op_unref (op);
+
+               op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
+               op->d.prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
+               e_book_backend_get_backend_property (
+                       book->priv->backend, book, op->id,
+                       op->cancellable, op->d.prop_name);
+               op_unref (op);
+
+               op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
+               op->d.prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
+               e_book_backend_get_backend_property (
+                       book->priv->backend, book, op->id,
+                       op->cancellable, op->d.prop_name);
+               op_unref (op);
+
+               return g_dbus_interface_skeleton_export (
+                              G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
+                              book->priv->connection,
+                              book->priv->object_path,
+                              error);
+       }
+
+       return TRUE;
 }
 
 static void
@@ -1676,7 +2059,6 @@ e_data_book_class_init (EDataBookClass *class)
        object_class->get_property = data_book_get_property;
        object_class->dispose = data_book_dispose;
        object_class->finalize = data_book_finalize;
-       object_class->constructed = data_book_constructed;
 
        g_object_class_install_property (
                object_class,
@@ -1729,52 +2111,18 @@ e_data_book_initable_init (GInitableIface *interface)
 static void
 e_data_book_init (EDataBook *ebook)
 {
-       EDBusAddressBook *dbus_interface;
-
        ebook->priv = E_DATA_BOOK_GET_PRIVATE (ebook);
 
-       dbus_interface = e_dbus_address_book_skeleton_new ();
-       ebook->priv->dbus_interface = dbus_interface;
-
        ebook->priv->pending_ops = g_hash_table_new_full (
                (GHashFunc) g_direct_hash,
                (GEqualFunc) g_direct_equal,
                (GDestroyNotify) NULL,
                (GDestroyNotify) op_unref);
+       ebook->priv->direct_ops = g_hash_table_new_full (
+               g_direct_hash, g_direct_equal, NULL,
+               (GDestroyNotify)direct_operation_data_free);
        g_rec_mutex_init (&ebook->priv->pending_ops_lock);
-
        g_mutex_init (&ebook->priv->open_lock);
-
-       g_signal_connect (
-               dbus_interface, "handle-open",
-               G_CALLBACK (data_book_handle_open_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-refresh",
-               G_CALLBACK (data_book_handle_refresh_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-get-contact",
-               G_CALLBACK (data_book_handle_get_contact_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-get-contact-list",
-               G_CALLBACK (data_book_handle_get_contact_list_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-get-contact-list-uids",
-               G_CALLBACK (data_book_handle_get_contact_list_uids_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-create-contacts",
-               G_CALLBACK (data_book_handle_create_contacts_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-modify-contacts",
-               G_CALLBACK (data_book_handle_modify_contacts_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-remove-contacts",
-               G_CALLBACK (data_book_handle_remove_contacts_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-get-view",
-               G_CALLBACK (data_book_handle_get_view_cb), ebook);
-       g_signal_connect (
-               dbus_interface, "handle-close",
-               G_CALLBACK (data_book_handle_close_cb), ebook);
 }
 
 /**
@@ -1809,6 +2157,82 @@ e_data_book_new (EBookBackend *backend,
                NULL);
 }
 
+EDataBook *
+e_data_book_new_direct (ESourceRegistry *registry,
+                       ESource         *source,
+                       const gchar     *backend_path,
+                       const gchar     *backend_name,
+                       const gchar     *config,
+                       GError         **error)
+{
+       EDataBook *book = NULL;
+       EModule *module;
+       EBookBackend *backend;
+       GType backend_type;
+       GType factory_type;
+       GTypeClass *factory_class;
+
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+       g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+       g_return_val_if_fail (backend_path && backend_path[0], NULL);
+       g_return_val_if_fail (backend_name && backend_name[0], NULL);
+
+       module = load_module (backend_path);
+       if (!module) {
+               g_set_error (error, E_CLIENT_ERROR,
+                            E_CLIENT_ERROR_OTHER_ERROR,
+                            "Failed to load module at specified path: %s", backend_path);
+               goto new_direct_finish;
+       }
+
+       if (!g_type_module_use (G_TYPE_MODULE (module))) {
+               g_set_error (error, E_CLIENT_ERROR,
+                            E_CLIENT_ERROR_OTHER_ERROR,
+                            "Failed to use EModule at path: %s", backend_path);
+               goto new_direct_finish;
+       }
+
+       factory_type = g_type_from_name (backend_name);
+       if (factory_type == 0) {
+               g_set_error (error, E_CLIENT_ERROR,
+                            E_CLIENT_ERROR_OTHER_ERROR,
+                            "Failed to get backend factory '%s' from EModule at path: %s",
+                            backend_name, backend_path);
+               g_type_module_unuse (G_TYPE_MODULE (module));
+               goto new_direct_finish;
+       }
+
+       factory_class = g_type_class_ref (factory_type);
+       backend_type  = E_BOOK_BACKEND_FACTORY_CLASS (factory_class)->backend_type;
+       g_type_class_unref (factory_class);
+
+       backend = g_initable_new (backend_type, NULL, error,
+                               "registry", registry,
+                               "source", source, NULL);
+
+       if (!backend) {
+               g_type_module_unuse (G_TYPE_MODULE (module));
+               goto new_direct_finish;
+       }
+
+       e_book_backend_configure_direct (backend, config);
+
+       book = g_initable_new (E_TYPE_DATA_BOOK, NULL, error,
+                              "backend", backend, NULL);
+       g_object_unref (backend);
+
+       if (!book) {
+               g_type_module_unuse (G_TYPE_MODULE (module));
+               goto new_direct_finish;
+       }
+
+       book->priv->direct_module = module;
+
+ new_direct_finish:
+
+       return book;
+}
+
 /**
  * e_data_book_get_backend:
  * @book: an #EDataBook
@@ -1864,3 +2288,342 @@ e_data_book_get_object_path (EDataBook *book)
        return book->priv->object_path;
 }
 
+/*************************************************************************
+ *                        Direct Read Access APIs                        *
+ *************************************************************************/
+
+static gboolean
+e_data_book_open_finish (EDataBook *book,
+                        GAsyncResult *result,
+                        GError **error)
+{
+       gboolean res;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+       res = g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result));
+       g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+
+       return res;
+}
+
+gboolean
+e_data_book_open_sync (EDataBook *book,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       DirectOperationData *data = NULL;
+       OperationData *op;
+       gboolean result = FALSE;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+       op = op_direct_new (OP_OPEN, book, cancellable, NULL, NULL, e_data_book_open_sync, TRUE, &data);
+
+       op_dispatch (book, op);
+
+       direct_operation_wait (data);
+       result = e_data_book_open_finish (book, G_ASYNC_RESULT (data->result), error);
+       direct_operation_data_free (data);
+
+       return result;
+}
+
+static void
+e_data_book_respond_close (EDataBook *book,
+                          guint opid,
+                          GError *error)
+{
+       DirectOperationData *data;
+
+       data = op_complete (book, opid);
+
+       if (data) {
+               gboolean result = FALSE;
+
+               if (error)
+                       g_simple_async_result_set_error (data->result,
+                                                        error->domain,
+                                                        error->code,
+                                                        "%s", error->message);
+
+               else {
+                       if (!g_cancellable_is_cancelled (data->cancellable))
+                               result = TRUE;
+
+                       g_simple_async_result_set_check_cancellable (data->result,
+                                                                    data->cancellable);
+               }
+
+               g_simple_async_result_set_op_res_gboolean (data->result, result);
+
+               /* Deliver the result to the caller */
+               direct_operation_complete (data);
+       }
+
+       if (error)
+               g_error_free (error);
+}
+
+void
+e_data_book_close (EDataBook *book,
+                  GCancellable *cancellable,
+                  GAsyncReadyCallback callback,
+                  gpointer user_data)
+{
+       OperationData *op;
+
+       g_return_if_fail (E_IS_DATA_BOOK (book));
+
+       op = op_direct_new (OP_CLOSE, book, cancellable, callback, user_data, e_data_book_close, FALSE, NULL);
+
+       /* This operation is never queued. */
+       e_operation_pool_push (ops_pool, op);
+}
+
+gboolean
+e_data_book_close_finish (EDataBook *book,
+                         GAsyncResult *result,
+                         GError **error)
+{
+       gboolean res;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+       res = g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result));
+       g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+
+       return res;
+}
+
+gboolean
+e_data_book_close_sync (EDataBook *book,
+                       GCancellable *cancellable,
+                       GError **error)
+{
+       DirectOperationData *data = NULL;
+       OperationData *op;
+       gboolean result = FALSE;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+       op = op_direct_new (OP_CLOSE, book, cancellable, NULL, NULL, e_data_book_close_sync, TRUE, &data);
+
+       /* This operation is never queued. */
+       e_operation_pool_push (ops_pool, op);
+
+       direct_operation_wait (data);
+       result = e_data_book_close_finish (book, G_ASYNC_RESULT (data->result), error);
+       direct_operation_data_free (data);
+
+       return result;
+}
+
+void
+e_data_book_get_contact (EDataBook *book,
+                        const gchar *uid,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+       OperationData *op;
+
+       g_return_if_fail (E_IS_DATA_BOOK (book));
+       g_return_if_fail (uid && uid[0]);
+
+       op = op_direct_new (OP_GET_CONTACT, book, cancellable, callback, user_data, e_data_book_get_contact, 
FALSE, NULL);
+       op->d.uid = g_strdup (uid);
+
+       op_dispatch (book, op);
+}
+
+gboolean
+e_data_book_get_contact_finish (EDataBook *book,
+                               GAsyncResult *result,
+                               EContact **contact,
+                               GError **error)
+{
+       EContact *ret_contact;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+       ret_contact = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+       g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+
+       if (contact) {
+               if (ret_contact)
+                       *contact = g_object_ref (ret_contact);
+               else
+                       *contact = NULL;
+       }
+
+       return ret_contact != NULL;
+}
+
+gboolean
+e_data_book_get_contact_sync (EDataBook *book,
+                             const gchar *uid,
+                             EContact **contact,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+       DirectOperationData *data = NULL;
+       OperationData *op;
+       gboolean result = FALSE;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (uid && uid[0], FALSE);
+
+       op = op_direct_new (OP_GET_CONTACT, book, cancellable, NULL, NULL, e_data_book_get_contact_sync, 
TRUE, &data);
+       op->d.uid = g_strdup (uid);
+
+       op_dispatch (book, op);
+
+       direct_operation_wait (data);
+       result = e_data_book_get_contact_finish (book, G_ASYNC_RESULT (data->result), contact, error);
+       direct_operation_data_free (data);
+
+       return result;
+}
+
+void
+e_data_book_get_contacts (EDataBook *book,
+                         const gchar *sexp,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+       OperationData *op;
+
+       g_return_if_fail (E_IS_DATA_BOOK (book));
+
+       op = op_direct_new (OP_GET_CONTACTS, book, cancellable, callback, user_data, 
e_data_book_get_contacts, FALSE, NULL);
+       op->d.query = g_strdup (sexp);
+
+       op_dispatch (book, op);
+}
+
+gboolean
+e_data_book_get_contacts_finish (EDataBook *book,
+                                GAsyncResult *result,
+                                GSList **contacts,
+                                GError **error)
+{
+       GSList *ret_contacts;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+       ret_contacts = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+       g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+
+       if (contacts) {
+               if (ret_contacts)
+                       *contacts = e_util_copy_object_slist (NULL, ret_contacts);
+               else
+                       *contacts = NULL;
+       }
+
+       /* How can we tell if it failed ? ... we need to check the error but
+        * GSimpleAsyncResult doesnt tell us if there was an error, only propagates it
+        */
+       return TRUE;
+}
+
+gboolean
+e_data_book_get_contacts_sync (EDataBook *book,
+                              const gchar *sexp,
+                              GSList **contacts,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       DirectOperationData *data = NULL;
+       OperationData *op;
+       gboolean result = FALSE;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+       op = op_direct_new (OP_GET_CONTACTS, book, cancellable, NULL, NULL, e_data_book_get_contacts_sync, 
TRUE, &data);
+       op->d.query = g_strdup (sexp);
+
+       op_dispatch (book, op);
+
+       direct_operation_wait (data);
+       result = e_data_book_get_contacts_finish (book, G_ASYNC_RESULT (data->result), contacts, error);
+       direct_operation_data_free (data);
+
+       return result;
+}
+
+void
+e_data_book_get_contacts_uids (EDataBook *book,
+                              const gchar *sexp,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+       OperationData *op;
+
+       g_return_if_fail (E_IS_DATA_BOOK (book));
+
+       op = op_direct_new (OP_GET_CONTACTS_UIDS, book, cancellable, callback, user_data, 
e_data_book_get_contacts_uids, FALSE, NULL);
+       op->d.query = g_strdup (sexp);
+
+       op_dispatch (book, op);
+}
+
+gboolean
+e_data_book_get_contacts_uids_finish (EDataBook *book,
+                                     GAsyncResult *result,
+                                     GSList **contacts_uids,
+                                     GError **error)
+{
+       GSList *ret_uids;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+       ret_uids = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+       g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+
+       if (contacts_uids) {
+               if (ret_uids)
+                       *contacts_uids = e_util_copy_string_slist (NULL, ret_uids);
+               else
+                       *contacts_uids = NULL;
+       }
+
+       /* How can we tell if it failed ? ... we need to check the error but
+        * GSimpleAsyncResult doesnt tell us if there was an error, only propagates it
+        */
+       return TRUE;
+}
+
+gboolean
+e_data_book_get_contacts_uids_sync (EDataBook *book,
+                                   const gchar *sexp,
+                                   GSList **contacts_uids,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+       DirectOperationData *data = NULL;
+       OperationData *op;
+       gboolean result = FALSE;
+
+       g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+       op = op_direct_new (OP_GET_CONTACTS_UIDS, book, cancellable, NULL, NULL, 
e_data_book_get_contacts_uids_sync, TRUE, &data);
+       op->d.query = g_strdup (sexp);
+
+       op_dispatch (book, op);
+
+       direct_operation_wait (data);
+       result = e_data_book_get_contacts_uids_finish (book, G_ASYNC_RESULT (data->result), contacts_uids, 
error);
+       direct_operation_data_free (data);
+
+       return result;
+}
+
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index 7417a9f..91b76c1 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -146,6 +146,12 @@ EDataBook *        e_data_book_new                 (struct _EBookBackend *backend,
                                                 GDBusConnection *connection,
                                                 const gchar *object_path,
                                                 GError **error);
+EDataBook *    e_data_book_new_direct          (ESourceRegistry *registry,
+                                                ESource *source,
+                                                const gchar *backend_path,
+                                                const gchar *backend_name,
+                                                const gchar *config,
+                                                GError **error);
 struct _EBookBackend *
                e_data_book_get_backend         (EDataBook *book);
 GDBusConnection *
@@ -203,6 +209,69 @@ void               e_data_book_report_backend_property_changed
 gchar *                e_data_book_string_slist_to_comma_string
                                                (const GSList *strings);
 
+/* Direct read access apis */
+gboolean       e_data_book_open_sync           (EDataBook *book,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           e_data_book_close               (EDataBook *book,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_data_book_close_finish        (EDataBook *book,
+                                                GAsyncResult *result,
+                                                GError **error);
+gboolean       e_data_book_close_sync          (EDataBook *book,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           e_data_book_get_contact         (EDataBook *book,
+                                                const gchar *uid,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_data_book_get_contact_finish  (EDataBook *book,
+                                                GAsyncResult *result,
+                                                EContact **contact,
+                                                GError **error);
+gboolean       e_data_book_get_contact_sync    (EDataBook *book,
+                                                const gchar *uid,
+                                                EContact **contact,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           e_data_book_get_contacts        (EDataBook *book,
+                                                const gchar *sexp,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_data_book_get_contacts_finish (EDataBook *book,
+                                                GAsyncResult *result,
+                                                GSList **contacts,
+                                                GError **error);
+gboolean       e_data_book_get_contacts_sync   (EDataBook *book,
+                                                const gchar *sexp,
+                                                GSList **contacts,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
+void           e_data_book_get_contacts_uids   (EDataBook *book,
+                                                const gchar *sexp,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_data_book_get_contacts_uids_finish
+                                                (EDataBook *book,
+                                                GAsyncResult *result,
+                                                GSList **contacts_uids,
+                                                GError **error);
+gboolean       e_data_book_get_contacts_uids_sync
+                                                (EDataBook *book,
+                                                const gchar *sexp,
+                                                GSList **contacts_uids,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
 #ifndef EDS_DISABLE_DEPRECATED
 void           e_data_book_respond_set_backend_property
                                                (EDataBook *book,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]