[evolution-data-server] EDataBook / EDataBookView: Added Direct Read Access APIs / support
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] EDataBook / EDataBookView: Added Direct Read Access APIs / support
- Date: Fri, 15 Feb 2013 09:47:30 +0000 (UTC)
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]