[evolution-data-server] Modernize EBookBackend's public API.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Modernize EBookBackend's public API.
- Date: Fri, 29 Mar 2013 22:31:32 +0000 (UTC)
commit a56367dc71cbd1d4371ec6024fa4e3b4e7147bcc
Author: Matthew Barnes <mbarnes redhat com>
Date: Mon Mar 25 09:28:40 2013 -0400
Modernize EBookBackend's public API.
This leaves EBookBackend and EDataBook engaging in a somewhat ridiculous
kind of ping-pong game for the moment, but the desired public API (in as
much as a backend has a public API) is starting to take shape.
With the scaffolding now in place, we can begin converting backends to
use modern GIO conventions one method at a time, and eventually remove
all the "respond" functions in EDataBook.
addressbook/libedata-book/e-book-backend.c | 2224 +++++++++++++++++---
addressbook/libedata-book/e-book-backend.h | 172 ++-
addressbook/libedata-book/e-data-book.c | 2106 +++++++++----------
addressbook/libedata-book/e-data-book.h | 26 +-
configure.ac | 2 +-
.../libedata-book/libedata-book-sections.txt | 21 +-
6 files changed, 3017 insertions(+), 1534 deletions(-)
---
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index 4f17bcb..1218ce7 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -1,9 +1,19 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Author:
- * Nat Friedman (nat ximian com)
+ * e-book-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*/
#include <config.h>
@@ -14,12 +24,13 @@
#include "e-data-book.h"
#include "e-book-backend.h"
-#define EDB_NOT_OPENED_ERROR e_data_book_create_error (E_DATA_BOOK_STATUS_NOT_OPENED, NULL)
-
#define E_BOOK_BACKEND_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_BOOK_BACKEND, EBookBackendPrivate))
+typedef struct _AsyncContext AsyncContext;
+typedef struct _DispatchNode DispatchNode;
+
struct _EBookBackendPrivate {
ESourceRegistry *registry;
EDataBook *data_book;
@@ -31,9 +42,40 @@ struct _EBookBackendPrivate {
GList *views;
gchar *cache_dir;
+
+ GMutex operation_lock;
+ GHashTable *operation_ids;
+ GQueue pending_operations;
+ guint32 next_operation_id;
+ GSimpleAsyncResult *blocked;
+};
+
+struct _AsyncContext {
+ /* Inputs */
+ gchar *uid;
+ gchar *query;
+ const gchar *prop_name;
+ GSList *string_list;
+
+ /* Outputs */
+ GQueue result_queue;
+
+ /* One of these should point to result_queue
+ * so any leftover resources can be released. */
+ GQueue *object_queue;
+ GQueue *string_queue;
+};
+
+struct _DispatchNode {
+ /* This is the dispatch function
+ * that invokes the class method. */
+ GSimpleAsyncThreadFunc dispatch_func;
+ gboolean blocking_operation;
+
+ GSimpleAsyncResult *simple;
+ GCancellable *cancellable;
};
-/* Property IDs */
enum {
PROP_0,
PROP_CACHE_DIR,
@@ -51,6 +93,175 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (EBookBackend, e_book_backend, E_TYPE_BACKEND)
static void
+async_context_free (AsyncContext *async_context)
+{
+ GQueue *queue;
+
+ g_free (async_context->uid);
+ g_free (async_context->query);
+
+ g_slist_free_full (
+ async_context->string_list,
+ (GDestroyNotify) g_free);
+
+ queue = async_context->object_queue;
+ while (queue != NULL && !g_queue_is_empty (queue))
+ g_object_unref (g_queue_pop_head (queue));
+
+ queue = async_context->string_queue;
+ while (queue != NULL && !g_queue_is_empty (queue))
+ g_free (g_queue_pop_head (queue));
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static void
+dispatch_node_free (DispatchNode *dispatch_node)
+{
+ g_clear_object (&dispatch_node->simple);
+ g_clear_object (&dispatch_node->cancellable);
+
+ g_slice_free (DispatchNode, dispatch_node);
+}
+
+static void
+book_backend_push_operation (EBookBackend *backend,
+ GSimpleAsyncResult *simple,
+ GCancellable *cancellable,
+ gboolean blocking_operation,
+ GSimpleAsyncThreadFunc dispatch_func)
+{
+ DispatchNode *node;
+
+ g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (simple));
+ g_return_if_fail (dispatch_func != NULL);
+
+ g_mutex_lock (&backend->priv->operation_lock);
+
+ node = g_slice_new0 (DispatchNode);
+ node->dispatch_func = dispatch_func;
+ node->blocking_operation = blocking_operation;
+ node->simple = g_object_ref (simple);
+
+ if (G_IS_CANCELLABLE (cancellable))
+ node->cancellable = g_object_ref (cancellable);
+
+ g_queue_push_tail (&backend->priv->pending_operations, node);
+
+ g_mutex_unlock (&backend->priv->operation_lock);
+}
+
+static gboolean
+book_backend_dispatch_thread (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ DispatchNode *node = user_data;
+ GError *error = NULL;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+ g_simple_async_result_take_error (node->simple, error);
+ g_simple_async_result_complete_in_idle (node->simple);
+ } else {
+ GAsyncResult *result;
+ GObject *source_object;
+
+ result = G_ASYNC_RESULT (node->simple);
+ source_object = g_async_result_get_source_object (result);
+ node->dispatch_func (node->simple, source_object, cancellable);
+ g_object_unref (source_object);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+book_backend_dispatch_next_operation (EBookBackend *backend)
+{
+ DispatchNode *node;
+
+ g_mutex_lock (&backend->priv->operation_lock);
+
+ /* We can't dispatch additional operations
+ * while a blocking operation is in progress. */
+ if (backend->priv->blocked != NULL) {
+ g_mutex_unlock (&backend->priv->operation_lock);
+ return FALSE;
+ }
+
+ /* Pop the next DispatchNode off the queue. */
+ node = g_queue_pop_head (&backend->priv->pending_operations);
+ if (node == NULL) {
+ g_mutex_unlock (&backend->priv->operation_lock);
+ return FALSE;
+ }
+
+ /* If this a blocking operation, block any
+ * further dispatching until this finishes. */
+ if (node->blocking_operation)
+ backend->priv->blocked = g_object_ref (node->simple);
+
+ g_mutex_unlock (&backend->priv->operation_lock);
+
+ g_io_scheduler_push_job (
+ book_backend_dispatch_thread,
+ node, (GDestroyNotify) dispatch_node_free,
+ G_PRIORITY_DEFAULT,
+ node->cancellable);
+
+ return TRUE;
+}
+
+static guint32
+book_backend_stash_operation (EBookBackend *backend,
+ GSimpleAsyncResult *simple)
+{
+ guint32 opid;
+
+ g_mutex_lock (&backend->priv->operation_lock);
+
+ if (backend->priv->next_operation_id == 0)
+ backend->priv->next_operation_id = 1;
+
+ opid = backend->priv->next_operation_id++;
+
+ g_hash_table_insert (
+ backend->priv->operation_ids,
+ GUINT_TO_POINTER (opid),
+ g_object_ref (simple));
+
+ g_mutex_unlock (&backend->priv->operation_lock);
+
+ return opid;
+}
+
+static GSimpleAsyncResult *
+book_backend_claim_operation (EBookBackend *backend,
+ guint32 opid)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (opid > 0, NULL);
+
+ g_mutex_lock (&backend->priv->operation_lock);
+
+ simple = g_hash_table_lookup (
+ backend->priv->operation_ids,
+ GUINT_TO_POINTER (opid));
+
+ if (simple != NULL) {
+ /* Steal the hash table's reference. */
+ g_hash_table_steal (
+ backend->priv->operation_ids,
+ GUINT_TO_POINTER (opid));
+ }
+
+ g_mutex_unlock (&backend->priv->operation_lock);
+
+ return simple;
+}
+
+static void
book_backend_set_default_cache_dir (EBookBackend *backend)
{
ESource *source;
@@ -224,6 +435,13 @@ book_backend_dispose (GObject *object)
priv->views = NULL;
}
+ g_hash_table_remove_all (priv->operation_ids);
+
+ while (!g_queue_is_empty (&priv->pending_operations))
+ g_object_unref (g_queue_pop_head (&priv->pending_operations));
+
+ g_clear_object (&priv->blocked);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_book_backend_parent_class)->dispose (object);
}
@@ -239,6 +457,9 @@ book_backend_finalize (GObject *object)
g_free (priv->cache_dir);
+ g_mutex_clear (&priv->operation_lock);
+ g_hash_table_destroy (priv->operation_ids);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_book_backend_parent_class)->finalize (object);
}
@@ -369,6 +590,14 @@ e_book_backend_init (EBookBackend *backend)
backend->priv->views = NULL;
g_mutex_init (&backend->priv->views_mutex);
+
+ g_mutex_init (&backend->priv->operation_lock);
+
+ backend->priv->operation_ids = g_hash_table_new_full (
+ (GHashFunc) g_direct_hash,
+ (GEqualFunc) g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) g_object_unref);
}
/**
@@ -533,370 +762,1547 @@ e_book_backend_set_writable (EBookBackend *backend,
}
/**
- * e_book_backend_open:
+ * e_book_backend_open_sync:
* @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @only_if_exists: %TRUE to prevent the creation of a new book
- *
- * Executes an 'open' request specified by @opid on @book
- * using @backend. This call might be finished
- * with e_data_book_respond_open() or e_book_backend_respond_opened(),
- * though the overall opening phase finishes only after call
- * of e_book_backend_notify_opened() after which call the backend
- * is either fully opened (including authentication against (remote)
- * server/storage) or an error was encountered during this opening phase.
- * 'opened' and 'opening' properties are updated automatically.
- * The backend refuses all other operations until the opening phase is finished.
- *
- * The e_book_backend_notify_opened() is called either from this function
- * or from e_book_backend_authenticate_user(), or after necessary steps
- * initiated by these two functions.
- *
- * The opening phase usually works like this:
- * 1) client requests open for the backend
- * 2) server receives this request and calls e_book_backend_open() - the opening phase begun
- * 3) either the backend is opened during this call, and notifies client
- * with e_book_backend_notify_opened() about that. This is usually
- * for local backends; their opening phase is finished
- * 4) or the backend requires authentication, thus it notifies client
- * about that with e_book_backend_notify_auth_required() and is
- * waiting for credentials, which will be received from client
- * by e_book_backend_authenticate_user() call. Backend's opening
- * phase is still running in this case, thus it doesn't call
- * e_book_backend_notify_opened() within e_book_backend_open() call.
- * 5) when backend receives credentials in e_book_backend_authenticate_user()
- * then it tries to authenticate against a server/storage with them
- * and only after it knows result of the authentication, whether user
- * was or wasn't authenticated, it notifies client with the result
- * by e_book_backend_notify_opened() and it's opening phase is
- * finished now. If there was no error returned then the backend is
- * considered opened, otherwise it's considered closed. Use AuthenticationFailed
- * error when the given credentials were rejected by the server/store, which
- * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
- * if there was anything wrong with the given credentials. Set error's
- * message to a reason for a re-prompt, it'll be shown to a user.
- * 6) client checks error returned from e_book_backend_notify_opened() and
- * reprompts for a password if it was AuthenticationFailed. Otherwise
- * considers backend opened based on the error presence (no error means success).
- *
- * In any case, the call of e_book_backend_open() should be always finished
- * with e_data_book_respond_open(), which has no influence on the opening phase,
- * or alternatively with e_book_backend_respond_opened(). Never use authentication
- * errors in e_data_book_respond_open() to notify the client the authentication is
- * required, there is e_book_backend_notify_auth_required() for this.
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * "Opens" the @backend. Opening a backend is something of an outdated
+ * concept, but the operation is hanging around for a little while longer.
+ * This usually involves some custom initialization logic, and testing of
+ * remote authentication if applicable.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
**/
-void
-e_book_backend_open (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- gboolean only_if_exists)
+gboolean
+e_book_backend_open_sync (EBookBackend *backend,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_open (
+ backend, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_open_finish (backend, result, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_open() */
+static void
+book_backend_open_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->open != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
if (e_book_backend_is_opened (backend)) {
- e_data_book_respond_open (book, opid, NULL);
+ g_simple_async_result_complete_in_idle (simple);
+
} else {
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->open != NULL);
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
- (* E_BOOK_BACKEND_GET_CLASS (backend)->open) (backend, book, opid, cancellable,
only_if_exists);
+ class->open (backend, data_book, opid, cancellable, FALSE);
}
+
+ g_object_unref (data_book);
}
/**
- * e_book_backend_refresh:
+ * e_book_backend_open:
* @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
*
- * Refreshes the address book being accessed by the given backend.
- * This might be finished with e_data_book_respond_refresh(),
- * and it might be called as soon as possible; it doesn't mean
- * that the refreshing is done after calling that, the backend
- * is only notifying client whether it started the refresh process
- * or not.
+ * Asynchronously "opens" the @backend. Opening a backend is something of
+ * an outdated concept, but the operation is hanging around for a little
+ * while longer. This usually involves some custom initialization logic,
+ * and testing of remote authentication if applicable.
*
- * Since: 3.2
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_open_finish() to get the result of the operation.
+ *
+ * Since: 3.10
**/
void
-e_book_backend_refresh (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable)
+e_book_backend_open (EBookBackend *backend,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- g_return_if_fail (backend != NULL);
+ GSimpleAsyncResult *simple;
+
g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- if (!E_BOOK_BACKEND_GET_CLASS (backend)->refresh)
- e_data_book_respond_refresh (book, opid, e_data_book_create_error
(E_DATA_BOOK_STATUS_NOT_SUPPORTED, NULL));
- else if (!e_book_backend_is_opened (backend))
- e_data_book_respond_refresh (book, opid, EDB_NOT_OPENED_ERROR);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->refresh) (backend, book, opid, cancellable);
-}
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback,
+ user_data, e_book_backend_open);
-/**
- * e_book_backend_create_contacts
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @vcards: a #GSList of vCards to add
- *
- * Executes a 'create contacts' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_create_contacts().
- *
- * Since: 3.4
- **/
-void
-e_book_backend_create_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *vcards)
-{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (vcards);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->create_contacts);
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_create_contacts (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->create_contacts) (backend, book, opid, cancellable,
vcards);
-}
+ book_backend_push_operation (
+ backend, simple, cancellable, TRUE,
+ book_backend_open_thread);
-/**
- * e_book_backend_remove_contacts:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @id_list: list of string IDs to remove
- *
- * Executes a 'remove contacts' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_remove_contacts().
- **/
-void
-e_book_backend_remove_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *id_list)
-{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (id_list);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts);
+ book_backend_dispatch_next_operation (backend);
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_remove_contacts (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, opid, cancellable,
id_list);
+ g_object_unref (simple);
}
/**
- * e_book_backend_modify_contacts:
+ * e_book_backend_open_finish:
* @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @vcards: the VCards to update
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
*
- * Executes a 'modify contacts' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_modify_contacts().
+ * Finishes the operation started with e_book_backend_open().
*
- * Since: 3.4
+ * If an error occurred, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
**/
-void
-e_book_backend_modify_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const GSList *vcards)
+gboolean
+e_book_backend_open_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (vcards);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->modify_contacts);
-
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_modify_contacts (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contacts) (backend, book, opid, cancellable,
vcards);
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_open), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ /* This operation blocks, so we need to let waiting operations
+ * through. (FIXME Centralize this for any blocking operation.) */
+ g_mutex_lock (&backend->priv->operation_lock);
+ if (backend->priv->blocked == simple)
+ g_clear_object (&backend->priv->blocked);
+ g_mutex_unlock (&backend->priv->operation_lock);
+ while (book_backend_dispatch_next_operation (backend))
+ ;
+
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
}
/**
- * e_book_backend_get_contact:
+ * e_book_backend_refresh_sync:
* @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @id: the ID of the contact to get
- *
- * Executes a 'get contact' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_get_contact().
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Initiates a refresh for @backend, if the @backend supports refreshing.
+ * The actual refresh operation completes on its own time. This function
+ * merely initiates the operation.
+ *
+ * If an error occurs while initiating the refresh, the function will set
+ * @error and return %FALSE. If the @backend does not support refreshing,
+ * the function will set an %E_DATA_BOOK_STATUS_NOT_SUPPORTED error and
+ * return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
**/
-void
-e_book_backend_get_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *id)
+gboolean
+e_book_backend_refresh_sync (EBookBackend *backend,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (id);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact);
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_get_contact (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, opid, cancellable, id);
-}
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
-/**
- * e_book_backend_get_contact_list:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @query: the s-expression to match
- *
- * Executes a 'get contact list' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_get_contact_list().
- **/
-void
-e_book_backend_get_contact_list (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *query)
-{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (query);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list);
+ closure = e_async_closure_new ();
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_get_contact_list (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, opid, cancellable,
query);
-}
+ e_book_backend_refresh (
+ backend, cancellable,
+ e_async_closure_callback, closure);
-/**
- * e_book_backend_get_contact_list_uids:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @query: the s-expression to match
- *
- * Executes a 'get contact list uids' request specified by @opid on @book
- * using @backend.
- * This might be finished with e_data_book_respond_get_contact_list_uids().
- *
- * Since: 3.2
- **/
-void
-e_book_backend_get_contact_list_uids (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable,
- const gchar *query)
-{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK (book));
- g_return_if_fail (query);
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list_uids);
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_refresh_finish (backend, result, error);
- if (!e_book_backend_is_opened (backend))
- e_data_book_respond_get_contact_list_uids (book, opid, EDB_NOT_OPENED_ERROR, NULL);
- else
- (* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list_uids) (backend, book, opid,
cancellable, query);
+ e_async_closure_free (closure);
+
+ return success;
}
-/**
- * e_book_backend_start_view:
- * @backend: an #EBookBackend
- * @view: the #EDataBookView to start
- *
- * Starts running the query specified by @view, emitting signals for
- * matching contacts.
- **/
-void
-e_book_backend_start_view (EBookBackend *backend,
- EDataBookView *view)
+/* Helper for e_book_backend_refresh() */
+static void
+book_backend_refresh_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
{
+ EBookBackend *backend;
EBookBackendClass *class;
+ EDataBook *data_book;
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+ backend = E_BOOK_BACKEND (source_object);
class = E_BOOK_BACKEND_GET_CLASS (backend);
- g_return_if_fail (class->start_view);
- class->start_view (backend, view);
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ if (class->refresh == NULL) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_SUPPORTED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_SUPPORTED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->refresh (backend, data_book, opid, cancellable);
+ }
+
+ g_object_unref (data_book);
}
/**
- * e_book_backend_stop_view:
+ * e_book_backend_refresh:
* @backend: an #EBookBackend
- * @view: the #EDataBookView to stop
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
*
- * Stops running the query specified by @view, emitting no more signals.
+ * Asynchronously initiates a refresh for @backend, if the @backend supports
+ * refreshing. The actual refresh operation completes on its own time. This
+ * function, along with e_book_backend_refresh_finish(), merely initiates the
+ * operation.
+ *
+ * Once the refresh is initiated, @callback will be called. You can then
+ * call e_book_backend_refresh_finish() to get the result of the initiation.
+ *
+ * Since: 3.10
**/
void
-e_book_backend_stop_view (EBookBackend *backend,
- EDataBookView *view)
+e_book_backend_refresh (EBookBackend *backend,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- EBookBackendClass *class;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
- class = E_BOOK_BACKEND_GET_CLASS (backend);
- g_return_if_fail (class->stop_view != NULL);
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback,
+ user_data, e_book_backend_refresh);
- class->stop_view (backend, view);
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_refresh_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
}
/**
- * e_book_backend_add_view:
+ * e_book_backend_refresh_finish:
* @backend: an #EBookBackend
- * @view: an #EDataBookView
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
*
- * Adds @view to @backend for querying.
+ * Finishes the refresh initiation started with e_book_backend_refresh().
+ *
+ * If an error occurred while initiating the refresh, the function will set
+ * @error and return %FALSE. If the @backend does not support refreshing,
+ * the function will set an %E_DATA_BOOK_STATUS_NOT_SUPPORTED error and
+ * return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
**/
-void
-e_book_backend_add_view (EBookBackend *backend,
- EDataBookView *view)
+gboolean
+e_book_backend_refresh_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
{
- g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ GSimpleAsyncResult *simple;
- g_mutex_lock (&backend->priv->views_mutex);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_refresh), FALSE);
- g_object_ref (view);
- backend->priv->views = g_list_append (backend->priv->views, view);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
- g_mutex_unlock (&backend->priv->views_mutex);
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
}
/**
- * e_book_backend_remove_view:
+ * e_book_backend_create_contacts_sync:
* @backend: an #EBookBackend
- * @view: an #EDataBookView
+ * @vcards: a %NULL-terminated array of vCard strings
+ * @out_contacts: a #GQueue in which to deposit results
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
*
- * Removes @view from @backend.
+ * Creates one or more new contacts from @vcards, and deposits an #EContact
+ * instance for each newly-created contact in @out_contacts.
+ *
+ * The returned #EContact instances are referenced for thread-safety and
+ * must be unreferenced with g_object_unref() when finished with them.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_create_contacts_sync (EBookBackend *backend,
+ const gchar * const *vcards,
+ GQueue *out_contacts,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
+ g_return_val_if_fail (vcards != NULL, FALSE);
+ g_return_val_if_fail (out_contacts != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_create_contacts (
+ backend, vcards, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_create_contacts_finish (
+ backend, result, out_contacts, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_create_contacts() */
+static void
+book_backend_create_contacts_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->create_contacts != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->create_contacts (
+ backend, data_book, opid, cancellable,
+ async_context->string_list);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_create_contacts
+ * @backend: an #EBookBackend
+ * @vcards: a %NULL-terminated array of vCard strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously creates one or more new contacts from @vcards.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_create_contacts_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_create_contacts (EBookBackend *backend,
+ const gchar * const *vcards,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ GSList *list = NULL;
+ gint ii;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (vcards != NULL);
+
+ for (ii = 0; vcards[ii] != NULL; ii++)
+ list = g_slist_prepend (list, g_strdup (vcards[ii]));
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->string_list = g_slist_reverse (list);
+ async_context->object_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_create_contacts);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_create_contacts_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_create_contacts_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @out_contacts: a #GQueue in which to deposit results
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_create_contacts().
+ *
+ * An #EContact instance for each newly-created contact is deposited in
+ * @out_contacts. The returned #EContact instances are referenced for
+ * thread-safety and must be unreferenced with g_object_unref() when
+ * finished with them.
+ *
+ * If an error occurred, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_create_contacts_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_contacts,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_create_contacts), FALSE);
+ g_return_val_if_fail (out_contacts != NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ while (!g_queue_is_empty (&async_context->result_queue)) {
+ EContact *contact;
+
+ contact = g_queue_pop_head (&async_context->result_queue);
+ g_queue_push_tail (out_contacts, g_object_ref (contact));
+ e_book_backend_notify_update (backend, contact);
+ g_object_unref (contact);
+ }
+
+ e_book_backend_notify_complete (backend);
+
+ return TRUE;
+}
+
+/**
+ * e_book_backend_modify_contacts_sync:
+ * @backend: an #EBookBackend
+ * @vcards: a %NULL-terminated array of vCard strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Modifies one or more contacts according to @vcards.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_modify_contacts_sync (EBookBackend *backend,
+ const gchar * const *vcards,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_modify_contacts (
+ backend, vcards, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_modify_contacts_finish (
+ backend, result, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_modify_contacts() */
+static void
+book_backend_modify_contacts_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->modify_contacts != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->modify_contacts (
+ backend, data_book, opid, cancellable,
+ async_context->string_list);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_modify_contacts:
+ * @backend: an #EBookBackend
+ * @vcards: a %NULL-terminated array of vCard strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously modifies one or more contacts according to @vcards.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_modify_contacts_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_modify_contacts (EBookBackend *backend,
+ const gchar * const *vcards,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ GSList *list = NULL;
+ gint ii;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (vcards != NULL);
+
+ for (ii = 0; vcards[ii] != NULL; ii++)
+ list = g_slist_prepend (list, g_strdup (vcards[ii]));
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->string_list = g_slist_reverse (list);
+ async_context->object_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_modify_contacts);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_modify_contacts_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_modify_contacts_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_modify_contacts().
+ *
+ * If an error occurred, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_modify_contacts_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_modify_contacts), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ while (!g_queue_is_empty (&async_context->result_queue)) {
+ EContact *contact;
+
+ contact = g_queue_pop_head (&async_context->result_queue);
+ e_book_backend_notify_update (backend, contact);
+ g_object_unref (contact);
+ }
+
+ e_book_backend_notify_complete (backend);
+
+ return TRUE;
+}
+
+/**
+ * e_book_backend_remove_contacts_sync:
+ * @backend: an #EBookBackend
+ * @uids: a %NULL-terminated array of contact ID strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Removes one or more contacts according to @uids.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_remove_contacts_sync (EBookBackend *backend,
+ const gchar * const *uids,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
+ g_return_val_if_fail (uids != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_remove_contacts (
+ backend, uids, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_remove_contacts_finish (
+ backend, result, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_remove_contacts() */
+static void
+book_backend_remove_contacts_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->remove_contacts != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->remove_contacts (
+ backend, data_book, opid, cancellable,
+ async_context->string_list);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_remove_contacts:
+ * @backend: an #EBookBackend
+ * @uids: a %NULL-terminated array of contact ID strings
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously removes one or more contacts according to @uids.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_remove_contacts_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_remove_contacts (EBookBackend *backend,
+ const gchar * const *uids,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ GSList *list = NULL;
+ gint ii;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (uids != NULL);
+
+ for (ii = 0; uids[ii] != NULL; ii++)
+ list = g_slist_prepend (list, g_strdup (uids[ii]));
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->string_list = g_slist_reverse (list);
+ async_context->string_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_remove_contacts);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_remove_contacts_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_remove_contacts_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_remove_contacts().
+ *
+ * If an error occurred, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_remove_contacts_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_remove_contacts), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ while (!g_queue_is_empty (&async_context->result_queue)) {
+ gchar *uid;
+
+ uid = g_queue_pop_head (&async_context->result_queue);
+ e_book_backend_notify_remove (backend, uid);
+ g_free (uid);
+ }
+
+ e_book_backend_notify_complete (backend);
+
+ return TRUE;
+}
+
+/**
+ * e_book_backend_get_contact_sync:
+ * @backend: an #EBookBackend
+ * @uid: a contact ID
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Obtains an #EContact for @uid.
+ *
+ * The returned #EContact is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * If an error occurs, the function will set @error and return %NULL.
+ *
+ * Returns: an #EContact, or %NULL
+ *
+ * Since: 3.10
+ **/
+EContact *
+e_book_backend_get_contact_sync (EBookBackend *backend,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ EContact *contact;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_get_contact (
+ backend, uid, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ contact = e_book_backend_get_contact_finish (
+ backend, result, error);
+
+ e_async_closure_free (closure);
+
+ return contact;
+}
+
+/* Helper for e_book_backend_get_contact() */
+static void
+book_backend_get_contact_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->get_contact != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->get_contact (
+ backend, data_book, opid, cancellable,
+ async_context->uid);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_get_contact:
+ * @backend: an #EBookBackend
+ * @uid: a contact ID
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously obtains an #EContact for @uid.
+ *
+ * When the operation is finished, @callback will be called. You can
+ * then call e_book_backend_get_contact_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_get_contact (EBookBackend *backend,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (uid != NULL);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->uid = g_strdup (uid);
+ async_context->object_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_get_contact);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_get_contact_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_get_contact_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_get_contact_finish().
+ *
+ * The returned #EContact is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * If an error occurred, the function will set @error and return %NULL.
+ *
+ * Returns: an #EContact, or %NULL
+ *
+ * Since: 3.10
+ **/
+EContact *
+e_book_backend_get_contact_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ EContact *contact;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_get_contact), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ contact = g_queue_pop_head (&async_context->result_queue);
+ g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
+
+ g_warn_if_fail (g_queue_is_empty (&async_context->result_queue));
+
+ return contact;
+}
+
+/**
+ * e_book_backend_get_contact_list_sync:
+ * @backend: an #EBookBackend
+ * @query: a search query in S-expression format
+ * @out_contacts: a #GQueue in which to deposit results
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Obtains a set of #EContact instances which satisfy the criteria specified
+ * in @query, and deposits them in @out_contacts.
+ *
+ * The returned #EContact instances are referenced for thread-safety and
+ * must be unreferenced with g_object_unref() when finished with them.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ * Note that an empty result set does not necessarily imply an error.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_get_contact_list_sync (EBookBackend *backend,
+ const gchar *query,
+ GQueue *out_contacts,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
+ g_return_val_if_fail (query != NULL, FALSE);
+ g_return_val_if_fail (out_contacts != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_get_contact_list (
+ backend, query, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_get_contact_list_finish (
+ backend, result, out_contacts, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_get_contact_list() */
+static void
+book_backend_get_contact_list_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->get_contact_list != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->get_contact_list (
+ backend, data_book, opid, cancellable,
+ async_context->query);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_get_contact_list:
+ * @backend: an #EBookBackend
+ * @query: a search query in S-expression format
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously obtains a set of #EContact instances which satisfy the
+ * criteria specified in @query.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_get_contact_list_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_get_contact_list (EBookBackend *backend,
+ const gchar *query,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (query != NULL);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->query = g_strdup (query);
+ async_context->object_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_get_contact_list);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_get_contact_list_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_get_contact_list_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @out_contacts: a #GQueue in which to deposit results
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_get_contact_list().
+ *
+ * The matching #EContact instances are deposited in @out_contacts. The
+ * returned #EContact instances are referenced for thread-safety and must
+ * be unreferenced with g_object_unref() when finished with them.
+ *
+ * If an error occurred, the function will set @error and return %FALSE.
+ * Note that an empty result set does not necessarily imply an error.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_get_contact_list_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_contacts,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_get_contact_list), FALSE);
+ g_return_val_if_fail (out_contacts != NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ e_queue_transfer (&async_context->result_queue, out_contacts);
+
+ return TRUE;
+}
+
+/**
+ * e_book_backend_get_contact_list_uids_sync:
+ * @backend: an #EBookBackend
+ * @query: a search query in S-expression format
+ * @out_uids: a #GQueue in which to deposit results
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Obtains a set of ID strings for contacts which satisfy the criteria
+ * specified in @query, and deposits them in @out_uids.
+ *
+ * The returned ID strings must be freed with g_free() with finished
+ * with them.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ * Note that an empty result set does not necessarily imply an error.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_get_contact_list_uids_sync (EBookBackend *backend,
+ const gchar *query,
+ GQueue *out_uids,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
+ g_return_val_if_fail (query != NULL, FALSE);
+ g_return_val_if_fail (out_uids != NULL, FALSE);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_get_contact_list_uids (
+ backend, query, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ success = e_book_backend_get_contact_list_uids_finish (
+ backend, result, out_uids, error);
+
+ e_async_closure_free (closure);
+
+ return success;
+}
+
+/* Helper for e_book_backend_get_contact_list_uids() */
+static void
+book_backend_get_contact_list_uids_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->get_contact_list_uids != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (!e_book_backend_is_opened (backend)) {
+ g_simple_async_result_set_error (
+ simple, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_NOT_OPENED,
+ "%s", e_data_book_status_to_string (
+ E_DATA_BOOK_STATUS_NOT_OPENED));
+ g_simple_async_result_complete_in_idle (simple);
+
+ } else {
+ guint32 opid;
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->get_contact_list_uids (
+ backend, data_book, opid, cancellable,
+ async_context->query);
+ }
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_get_contact_list_uids:
+ * @backend: an #EBookBackend
+ * @query: a search query in S-expression format
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously obtains a set of ID strings for contacts which satisfy
+ * the criteria specified in @query.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_get_contact_list_uids_finish() to get the result of
+ * the operation.
+ *
+ * Since: 3.10
+ **/
+void
+e_book_backend_get_contact_list_uids (EBookBackend *backend,
+ const gchar *query,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (query != NULL);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->query = g_strdup (query);
+ async_context->string_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_get_contact_list_uids);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_get_contact_list_uids_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_get_contact_list_uids_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @out_uids: a #GQueue in which to deposit results
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with
+ * e_book_backend_get_contact_list_uids_finish().
+ *
+ * ID strings for the matching contacts are deposited in @out_uids, and
+ * must be freed with g_free() when finished with them.
+ *
+ * If an error occurs, the function will set @error and return %FALSE.
+ * Note that an empty result set does not necessarily imply an error.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.10
+ **/
+gboolean
+e_book_backend_get_contact_list_uids_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_uids,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_get_contact_list_uids), FALSE);
+ g_return_val_if_fail (out_uids != NULL, FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ e_queue_transfer (&async_context->result_queue, out_uids);
+
+ return TRUE;
+}
+
+/**
+ * e_book_backend_start_view:
+ * @backend: an #EBookBackend
+ * @view: the #EDataBookView to start
+ *
+ * Starts running the query specified by @view, emitting signals for
+ * matching contacts.
+ **/
+void
+e_book_backend_start_view (EBookBackend *backend,
+ EDataBookView *view)
+{
+ EBookBackendClass *class;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->start_view);
+
+ class->start_view (backend, view);
+}
+
+/**
+ * e_book_backend_stop_view:
+ * @backend: an #EBookBackend
+ * @view: the #EDataBookView to stop
+ *
+ * Stops running the query specified by @view, emitting no more signals.
+ **/
+void
+e_book_backend_stop_view (EBookBackend *backend,
+ EDataBookView *view)
+{
+ EBookBackendClass *class;
+
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->stop_view != NULL);
+
+ class->stop_view (backend, view);
+}
+
+/**
+ * e_book_backend_add_view:
+ * @backend: an #EBookBackend
+ * @view: an #EDataBookView
+ *
+ * Adds @view to @backend for querying.
+ **/
+void
+e_book_backend_add_view (EBookBackend *backend,
+ EDataBookView *view)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+
+ g_mutex_lock (&backend->priv->views_mutex);
+
+ g_object_ref (view);
+ backend->priv->views = g_list_append (backend->priv->views, view);
+
+ g_mutex_unlock (&backend->priv->views_mutex);
+}
+
+/**
+ * e_book_backend_remove_view:
+ * @backend: an #EBookBackend
+ * @view: an #EDataBookView
+ *
+ * Removes @view from @backend.
**/
void
e_book_backend_remove_view (EBookBackend *backend,
@@ -961,33 +2367,180 @@ e_book_backend_list_views (EBookBackend *backend)
}
/**
- * e_book_backend_get_book_backend_property:
+ * e_book_backend_get_backend_property_sync:
* @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @cancellable: a #GCancellable for the operation
- * @prop_name: property name to get value of; cannot be NULL
- *
- * Calls the get_backend_property method on the given backend.
- * This might be finished with e_data_book_respond_get_backend_property().
- * Default implementation takes care of common properties and returns
- * an 'unsupported' error for any unknown properties. The subclass may
- * always call this default implementation for properties which fetching
- * it doesn't overwrite.
+ * @prop_name: a backend property name
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
*
- * Since: 3.2
+ * Obtains the value of the backend property named @prop_name.
+ *
+ * Despite appearances, this function does not actually block. So the
+ * @cancellable can safely be %NULL. It can, however, return an error
+ * if @prop_name is not recognized.
+ *
+ * The returned string must be freed with g_free() when finished with it.
+ *
+ * Returns: the value for @prop_name
+ *
+ * Since: 3.10
+ **/
+gchar *
+e_book_backend_get_backend_property_sync (EBookBackend *backend,
+ const gchar *prop_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EAsyncClosure *closure;
+ GAsyncResult *result;
+ gchar *prop_value;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
+ g_return_val_if_fail (prop_name != NULL, NULL);
+
+ closure = e_async_closure_new ();
+
+ e_book_backend_get_backend_property (
+ backend, prop_name, cancellable,
+ e_async_closure_callback, closure);
+
+ result = e_async_closure_wait (closure);
+
+ prop_value = e_book_backend_get_backend_property_finish (
+ backend, result, error);
+
+ e_async_closure_free (closure);
+
+ return prop_value;
+}
+
+/* Helper for e_book_backend_get_backend_property() */
+static void
+book_backend_get_backend_property_thread (GSimpleAsyncResult *simple,
+ GObject *source_object,
+ GCancellable *cancellable)
+{
+ EBookBackend *backend;
+ EBookBackendClass *class;
+ EDataBook *data_book;
+ AsyncContext *async_context;
+ guint32 opid;
+
+ backend = E_BOOK_BACKEND (source_object);
+
+ class = E_BOOK_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->get_backend_property != NULL);
+
+ data_book = e_book_backend_ref_data_book (backend);
+ g_return_if_fail (data_book != NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ opid = book_backend_stash_operation (backend, simple);
+
+ class->get_backend_property (
+ backend, data_book, opid, cancellable,
+ async_context->prop_name);
+
+ g_object_unref (data_book);
+}
+
+/**
+ * e_book_backend_get_backend_property:
+ * @backend: an #EBookBackend
+ * @prop_name: a backend property name
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously obtains the value of the backend property named @prop_name.
+ *
+ * Despite appearances, e_book_backend_get_backend_property_sync() does not
+ * actually block, and is more convenient than this function. This function
+ * exists for the moment merely to invoke the class method and collect the
+ * result from #EDataBook.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_book_backend_get_backend_property_finish() to get the result of
+ * the operation.
+ *
+ * Since: 3.10
**/
void
e_book_backend_get_backend_property (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar *prop_name,
GCancellable *cancellable,
- const gchar *prop_name)
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
g_return_if_fail (E_IS_BOOK_BACKEND (backend));
- g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_backend_property);
+ g_return_if_fail (prop_name != NULL);
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->prop_name = g_intern_string (prop_name);
+ async_context->string_queue = &async_context->result_queue;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (backend), callback, user_data,
+ e_book_backend_get_backend_property);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, async_context, (GDestroyNotify) async_context_free);
+
+ book_backend_push_operation (
+ backend, simple, cancellable, FALSE,
+ book_backend_get_backend_property_thread);
+
+ book_backend_dispatch_next_operation (backend);
+
+ g_object_unref (simple);
+}
+
+/**
+ * e_book_backend_get_backend_property_finish:
+ * @backend: an #EBookBackend
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_book_backend_get_backend_property().
+ *
+ * The returned string must be freed with g_free() when finished with it.
+ *
+ * Returns: the requested property value
+ *
+ * Since: 3.10
+ **/
+gchar *
+e_book_backend_get_backend_property_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+ gchar *prop_value;
+
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (backend),
+ e_book_backend_get_backend_property), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
- E_BOOK_BACKEND_GET_CLASS (backend)->get_backend_property (backend, book, opid, cancellable,
prop_name);
+ prop_value = g_queue_pop_head (&async_context->result_queue);
+ g_return_val_if_fail (prop_value != NULL, NULL);
+
+ g_warn_if_fail (g_queue_is_empty (&async_context->result_queue));
+
+ return prop_value;
}
/**
@@ -1284,3 +2837,50 @@ e_book_backend_notify_property_changed (EBookBackend *backend,
}
}
+/**
+ * e_book_backend_prepare_for_completion:
+ * @backend: an #EBookBackend
+ * @opid: an operation ID given to #EDataBook
+ * @result_queue: return location for a #GQueue, or %NULL
+ *
+ * Obtains the #GSimpleAsyncResult for @opid and sets @result_queue as a
+ * place to deposit results prior to completing the #GSimpleAsyncResult.
+ *
+ * <note>
+ * <para>
+ * This is a temporary function to serve #EDataBook's "respond"
+ * functions until they can be removed. Nothing else should be
+ * calling this function.
+ * </para>
+ * </note>
+ *
+ * Returns: (transfer full): a #GSimpleAsyncResult
+ *
+ * Since: 3.10
+ **/
+GSimpleAsyncResult *
+e_book_backend_prepare_for_completion (EBookBackend *backend,
+ guint32 opid,
+ GQueue **result_queue)
+{
+ GSimpleAsyncResult *simple;
+ AsyncContext *async_context;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
+ g_return_val_if_fail (opid > 0, NULL);
+
+ simple = book_backend_claim_operation (backend, opid);
+ g_return_val_if_fail (simple != NULL, NULL);
+
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (result_queue != NULL) {
+ if (async_context != NULL)
+ *result_queue = &async_context->result_queue;
+ else
+ *result_queue = NULL;
+ }
+
+ return simple;
+}
+
diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h
index 97d308f..e1e8714 100644
--- a/addressbook/libedata-book/e-book-backend.h
+++ b/addressbook/libedata-book/e-book-backend.h
@@ -1,22 +1,19 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * An abstract class which defines the API to a given backend.
- * There will be one EBookBackend object for every URI which is loaded.
+ * e-book-backend.h
*
- * Two people will call into the EBookBackend API:
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
*
- * 1. The PASBookFactory, when it has been asked to load a book.
- * It will create a new EBookBackend if one is not already running
- * for the requested URI. It will call e_book_backend_add_client to
- * add a new client to an existing EBookBackend server.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * 2. A PASBook, when a client has requested an operation on the
- * GNOME_Evolution_Addressbook_Book interface.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
- * Author:
- * Nat Friedman (nat ximian com)
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*/
#if !defined (__LIBEDATA_BOOK_H_INSIDE__) && !defined (LIBEDATA_BOOK_COMPILATION)
@@ -226,53 +223,131 @@ gboolean e_book_backend_is_opened (EBookBackend *backend);
gboolean e_book_backend_is_readonly (EBookBackend *backend);
gboolean e_book_backend_is_removed (EBookBackend *backend);
+gchar * e_book_backend_get_backend_property_sync
+ (EBookBackend *backend,
+ const gchar *prop_name,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_get_backend_property
(EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar *prop_name,
GCancellable *cancellable,
- const gchar *prop_name);
-
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gchar * e_book_backend_get_backend_property_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_book_backend_open_sync (EBookBackend *backend,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_open (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
GCancellable *cancellable,
- gboolean only_if_exists);
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_open_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_book_backend_refresh_sync (EBookBackend *backend,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_refresh (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
- GCancellable *cancellable);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_refresh_finish (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_book_backend_create_contacts_sync
+ (EBookBackend *backend,
+ const gchar * const *vcards,
+ GQueue *out_contacts,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_create_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar * const *vcards,
GCancellable *cancellable,
- const GSList *vcards);
-void e_book_backend_remove_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_create_contacts_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_contacts,
+ GError **error);
+gboolean e_book_backend_modify_contacts_sync
+ (EBookBackend *backend,
+ const gchar * const *vcards,
GCancellable *cancellable,
- const GSList *id_list);
+ GError **error);
void e_book_backend_modify_contacts (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar * const *vcards,
GCancellable *cancellable,
- const GSList *vcards);
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_modify_contacts_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_book_backend_remove_contacts_sync
+ (EBookBackend *backend,
+ const gchar * const *uids,
+ GCancellable *cancellable,
+ GError **error);
+void e_book_backend_remove_contacts (EBookBackend *backend,
+ const gchar * const *uids,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_remove_contacts_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+EContact * e_book_backend_get_contact_sync (EBookBackend *backend,
+ const gchar *uid,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_get_contact (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar *uid,
GCancellable *cancellable,
- const gchar *id);
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EContact * e_book_backend_get_contact_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GError **error);
+gboolean e_book_backend_get_contact_list_sync
+ (EBookBackend *backend,
+ const gchar *query,
+ GQueue *out_contacts,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_get_contact_list (EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar *query,
GCancellable *cancellable,
- const gchar *query);
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_get_contact_list_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_contacts,
+ GError **error);
+gboolean e_book_backend_get_contact_list_uids_sync
+ (EBookBackend *backend,
+ const gchar *query,
+ GQueue *out_uids,
+ GCancellable *cancellable,
+ GError **error);
void e_book_backend_get_contact_list_uids
(EBookBackend *backend,
- EDataBook *book,
- guint32 opid,
+ const gchar *query,
GCancellable *cancellable,
- const gchar *query);
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_book_backend_get_contact_list_uids_finish
+ (EBookBackend *backend,
+ GAsyncResult *result,
+ GQueue *out_uids,
+ GError **error);
void e_book_backend_start_view (EBookBackend *backend,
EDataBookView *view);
@@ -298,8 +373,9 @@ void e_book_backend_notify_property_changed
const gchar *prop_value);
EDataBookDirect *
- e_book_backend_get_direct_book (EBookBackend *backend);
-void e_book_backend_configure_direct (EBookBackend *backend, const gchar *config);
+ e_book_backend_get_direct_book (EBookBackend *backend);
+void e_book_backend_configure_direct (EBookBackend *backend,
+ const gchar *config);
void e_book_backend_sync (EBookBackend *backend);
@@ -307,6 +383,12 @@ void e_book_backend_sync (EBookBackend *backend);
void e_book_backend_set_is_removed (EBookBackend *backend,
gboolean is_removed);
+GSimpleAsyncResult *
+ e_book_backend_prepare_for_completion
+ (EBookBackend *backend,
+ guint32 opid,
+ GQueue **result_queue);
+
G_END_DECLS
#endif /* E_BOOK_BACKEND_H */
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index c9d66a0..5f81fe6 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -1,23 +1,19 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2006 OpenedHand Ltd
- * Copyright (C) 2009 Intel Corporation
+ * e-data-book.c
*
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of version 2.1 of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
*
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
- * Author: Ross Burton <ross linux intel com>
*/
#include <unistd.h>
@@ -41,6 +37,8 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_DATA_BOOK, EDataBookPrivate))
+typedef struct _AsyncContext AsyncContext;
+
struct _EDataBookPrivate {
GDBusConnection *connection;
EDBusAddressBook *dbus_interface;
@@ -52,15 +50,16 @@ struct _EDataBookPrivate {
gboolean opened;
- GRecMutex pending_ops_lock;
- GHashTable *pending_ops; /* opid -> OperationData */
- GHashTable *direct_ops; /* opid to DirectOperationData for still running operations */
+ GMutex sender_lock;
+ GHashTable *sender_table;
+};
- /* Operations are queued while an
- * open operation is in progress. */
- GMutex open_lock;
- guint32 open_opid;
- GQueue open_queue;
+struct _AsyncContext {
+ EDataBook *data_book;
+ EDBusAddressBook *interface;
+ GDBusMethodInvocation *invocation;
+ GCancellable *cancellable;
+ guint watcher_id;
};
enum {
@@ -70,66 +69,6 @@ enum {
PROP_OBJECT_PATH
};
-static EOperationPool *ops_pool = NULL;
-
-typedef enum {
- OP_OPEN,
- OP_REFRESH,
- OP_GET_CONTACT,
- OP_GET_CONTACTS,
- OP_GET_CONTACTS_UIDS,
- OP_ADD_CONTACTS,
- OP_REMOVE_CONTACTS,
- OP_MODIFY_CONTACTS,
- OP_GET_BACKEND_PROPERTY,
- OP_GET_VIEW,
- OP_CLOSE
-} OperationID;
-
-typedef struct {
- volatile gint ref_count;
-
- OperationID op;
- guint32 id; /* operation id */
- EDataBook *book;
- EBookBackend *backend;
- GCancellable *cancellable;
- GDBusMethodInvocation *invocation;
- const gchar *sender; /* owned by invocation */
- guint watcher_id;
-
- union {
- /* OP_GET_CONTACT */
- gchar *uid;
- /* OP_REMOVE_CONTACTS */
- GSList *ids;
- /* OP_ADD_CONTACTS */
- /* OP_MODIFY_CONTACTS */
- GSList *vcards;
- /* OP_GET_VIEW */
- /* OP_GET_CONTACTS */
- /* OP_GET_CONTACTS_UIDS */
- gchar *query;
- /* OP_GET_BACKEND_PROPERTY */
- const gchar *prop_name;
-
- /* OP_REFRESH */
- /* OP_CLOSE */
- } 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
@@ -138,20 +77,7 @@ static GHashTable *modules_table = NULL;
G_LOCK_DEFINE (modules_table);
/* Forward Declarations */
-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);
+static void e_data_book_initable_init (GInitableIface *interface);
G_DEFINE_TYPE_WITH_CODE (
EDataBook,
@@ -161,315 +87,156 @@ 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)
+sender_vanished_cb (GDBusConnection *connection,
+ const gchar *sender,
+ GCancellable *cancellable)
{
- 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);
- }
+ g_cancellable_cancel (cancellable);
}
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)
+sender_table_insert (EDataBook *data_book,
+ const gchar *sender,
+ GCancellable *cancellable)
{
- static volatile gint counter = 1;
+ GHashTable *sender_table;
+ GPtrArray *array;
- g_atomic_int_inc (&counter);
+ g_return_if_fail (sender != NULL);
- return g_strdup_printf (
- "/org/gnome/evolution/dataserver/AddressBookView/%d/%d",
- getpid (), counter);
-}
+ g_mutex_lock (&data_book->priv->sender_lock);
-static void
-op_sender_vanished_cb (GDBusConnection *connection,
- const gchar *sender,
- GCancellable *cancellable)
-{
- g_cancellable_cancel (cancellable);
-}
+ sender_table = data_book->priv->sender_table;
+ array = g_hash_table_lookup (sender_table, sender);
-static OperationData *
-op_ref (OperationData *data)
-{
- g_return_val_if_fail (data != NULL, data);
- g_return_val_if_fail (data->ref_count > 0, data);
+ if (array == NULL) {
+ array = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_object_unref);
+ g_hash_table_insert (
+ sender_table, g_strdup (sender), array);
+ }
- g_atomic_int_inc (&data->ref_count);
+ g_ptr_array_add (array, g_object_ref (cancellable));
- return data;
+ g_mutex_unlock (&data_book->priv->sender_lock);
}
-static OperationData *
-op_new (OperationID op,
- EDataBook *book,
- EBookBackend *backend,
- GDBusMethodInvocation *invocation)
+static gboolean
+sender_table_remove (EDataBook *data_book,
+ const gchar *sender,
+ GCancellable *cancellable)
{
- OperationData *data;
+ GHashTable *sender_table;
+ GPtrArray *array;
+ gboolean removed = FALSE;
- data = g_slice_new0 (OperationData);
- data->ref_count = 1;
- data->op = op;
- data->id = e_operation_pool_reserve_opid (ops_pool);
- data->book = g_object_ref (book);
- data->backend = g_object_ref (backend);
- data->cancellable = g_cancellable_new ();
+ g_return_val_if_fail (sender != NULL, FALSE);
- /* This is optional so we can fake client requests. */
- if (invocation != NULL) {
- GDBusConnection *connection;
+ g_mutex_lock (&data_book->priv->sender_lock);
- data->invocation = g_object_ref (invocation);
- data->sender = g_dbus_method_invocation_get_sender (invocation);
+ sender_table = data_book->priv->sender_table;
+ array = g_hash_table_lookup (sender_table, sender);
- connection = e_data_book_get_connection (book);
+ if (array != NULL) {
+ removed = g_ptr_array_remove_fast (array, cancellable);
- data->watcher_id = g_bus_watch_name_on_connection (
- connection, data->sender,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- (GBusNameAppearedCallback) NULL,
- (GBusNameVanishedCallback) op_sender_vanished_cb,
- g_object_ref (data->cancellable),
- (GDestroyNotify) g_object_unref);
+ if (array->len == 0)
+ g_hash_table_remove (sender_table, sender);
}
- 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));
- g_rec_mutex_unlock (&book->priv->pending_ops_lock);
+ g_mutex_unlock (&data_book->priv->sender_lock);
- return data;
+ return removed;
}
-static void
-op_unref (OperationData *data)
-{
- g_return_if_fail (data != NULL);
- g_return_if_fail (data->ref_count > 0);
-
- if (g_atomic_int_dec_and_test (&data->ref_count)) {
-
- switch (data->op) {
- case OP_GET_CONTACT:
- g_free (data->d.uid);
- break;
- case OP_REMOVE_CONTACTS:
- g_slist_free_full (
- data->d.ids,
- (GDestroyNotify) g_free);
- break;
- case OP_ADD_CONTACTS:
- case OP_MODIFY_CONTACTS:
- g_slist_free_full (
- data->d.vcards,
- (GDestroyNotify) g_free);
- break;
- case OP_GET_VIEW:
- case OP_GET_CONTACTS:
- case OP_GET_CONTACTS_UIDS:
- g_free (data->d.query);
- break;
- default:
- break;
- }
+static AsyncContext *
+async_context_new (EDataBook *data_book,
+ GDBusMethodInvocation *invocation)
+{
+ AsyncContext *async_context;
+ EDBusAddressBook *interface;
- g_object_unref (data->book);
- g_object_unref (data->backend);
- g_object_unref (data->cancellable);
+ interface = data_book->priv->dbus_interface;
- if (data->invocation != NULL)
- g_object_unref (data->invocation);
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->data_book = g_object_ref (data_book);
+ async_context->interface = g_object_ref (interface);
+ async_context->invocation = g_object_ref (invocation);
+ async_context->cancellable = g_cancellable_new ();
- if (data->watcher_id > 0)
- g_bus_unwatch_name (data->watcher_id);
+ async_context->watcher_id = g_bus_watch_name_on_connection (
+ g_dbus_method_invocation_get_connection (invocation),
+ g_dbus_method_invocation_get_sender (invocation),
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback) NULL,
+ (GBusNameVanishedCallback) sender_vanished_cb,
+ g_object_ref (async_context->cancellable),
+ (GDestroyNotify) g_object_unref);
- g_slice_free (OperationData, data);
- }
+ sender_table_insert (
+ async_context->data_book,
+ g_dbus_method_invocation_get_sender (invocation),
+ async_context->cancellable);
+
+ return async_context;
}
static void
-op_dispatch (EDataBook *book,
- OperationData *data)
+async_context_free (AsyncContext *async_context)
{
- g_mutex_lock (&book->priv->open_lock);
+ sender_table_remove (
+ async_context->data_book,
+ g_dbus_method_invocation_get_sender (
+ async_context->invocation),
+ async_context->cancellable);
- /* If an open operation is currently in progress, queue this
- * operation to be dispatched when the open operation finishes. */
- if (book->priv->open_opid > 0) {
- g_queue_push_tail (&book->priv->open_queue, data);
- } else {
- if (data->op == OP_OPEN)
- book->priv->open_opid = data->id;
- e_operation_pool_push (ops_pool, data);
- }
+ g_clear_object (&async_context->data_book);
+ g_clear_object (&async_context->interface);
+ g_clear_object (&async_context->invocation);
+ g_clear_object (&async_context->cancellable);
+
+ if (async_context->watcher_id > 0)
+ g_bus_unwatch_name (async_context->watcher_id);
- g_mutex_unlock (&book->priv->open_lock);
+ g_slice_free (AsyncContext, async_context);
}
-static OperationData *
-op_claim (EDataBook *book,
- guint32 opid,
- DirectOperationData **direct)
+static EModule *
+load_module (const gchar *module_path)
{
- OperationData *data;
- DirectOperationData *direct_data;
+ EModule *module = NULL;
- g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
+ G_LOCK (modules_table);
- e_operation_pool_release_opid (ops_pool, opid);
-
- g_rec_mutex_lock (&book->priv->pending_ops_lock);
- data = g_hash_table_lookup (
- book->priv->pending_ops,
- GUINT_TO_POINTER (opid));
- if (data != NULL) {
- /* Steal the hash table's reference. */
- g_hash_table_steal (
- book->priv->pending_ops,
- GUINT_TO_POINTER (opid));
- }
+ if (!modules_table)
+ modules_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- 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));
+ 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_rec_mutex_unlock (&book->priv->pending_ops_lock);
- g_warn_if_fail (direct_data == NULL || direct != NULL);
- if (direct)
- *direct = direct_data;
+ G_UNLOCK (modules_table);
- return data;
+ return module;
}
-static DirectOperationData *
-op_complete (EDataBook *book,
- guint32 opid)
+static gchar *
+construct_bookview_path (void)
{
- DirectOperationData *direct_data;
-
- g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
-
- e_operation_pool_release_opid (ops_pool, opid);
-
- g_rec_mutex_lock (&book->priv->pending_ops_lock);
- g_hash_table_remove (
- book->priv->pending_ops,
- GUINT_TO_POINTER (opid));
+ static volatile gint counter = 1;
- 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_atomic_int_inc (&counter);
- return direct_data;
+ return g_strdup_printf (
+ "/org/gnome/evolution/dataserver/AddressBookView/%d/%d",
+ getpid (), counter);
}
static void
@@ -593,207 +360,6 @@ data_book_convert_to_client_error (GError *error)
}
}
-static void
-cancel_operations_for_sender (EDataBook *book,
- const gchar *sender)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_return_if_fail (sender != NULL);
-
- g_rec_mutex_lock (&book->priv->pending_ops_lock);
-
- g_hash_table_iter_init (&iter, book->priv->pending_ops);
- while (g_hash_table_iter_next (&iter, NULL, &value)) {
- OperationData *op = value;
-
- if (op->sender != NULL && g_str_equal (sender, op->sender))
- g_cancellable_cancel (op->cancellable);
- }
-
- g_rec_mutex_unlock (&book->priv->pending_ops_lock);
-}
-
-static void
-operation_thread (gpointer data,
- gpointer user_data)
-{
- OperationData *op = data;
-
- switch (op->op) {
- case OP_OPEN:
- e_book_backend_open (
- op->backend, op->book, op->id,
- op->cancellable, FALSE);
- break;
-
- case OP_ADD_CONTACTS:
- e_book_backend_create_contacts (
- op->backend, op->book, op->id,
- op->cancellable, op->d.vcards);
- break;
-
- case OP_GET_CONTACT:
- e_book_backend_get_contact (
- op->backend, op->book, op->id,
- op->cancellable, op->d.uid);
- break;
-
- case OP_GET_CONTACTS:
- e_book_backend_get_contact_list (
- op->backend, op->book, op->id,
- op->cancellable, op->d.query);
- break;
-
- case OP_GET_CONTACTS_UIDS:
- e_book_backend_get_contact_list_uids (
- op->backend, op->book, op->id,
- op->cancellable, op->d.query);
- break;
-
- case OP_MODIFY_CONTACTS:
- e_book_backend_modify_contacts (
- op->backend, op->book, op->id,
- op->cancellable, op->d.vcards);
- break;
-
- case OP_REMOVE_CONTACTS:
- e_book_backend_remove_contacts (
- op->backend, op->book, op->id,
- op->cancellable, op->d.ids);
- break;
-
- case OP_REFRESH:
- e_book_backend_refresh (
- op->backend, op->book, op->id, op->cancellable);
- break;
-
- case OP_GET_BACKEND_PROPERTY:
- e_book_backend_get_backend_property (
- op->backend, op->book, op->id,
- op->cancellable, op->d.prop_name);
- break;
-
- case OP_GET_VIEW:
- if (op->d.query) {
- EDataBookView *view;
- EBookBackendSExp *card_sexp;
- GDBusConnection *connection;
- gchar *object_path;
- GError *error = NULL;
-
- card_sexp = e_book_backend_sexp_new (op->d.query);
- if (!card_sexp) {
- g_dbus_method_invocation_return_error_literal (
- op->invocation,
- E_CLIENT_ERROR,
- E_CLIENT_ERROR_INVALID_QUERY,
- _("Invalid query"));
-
- op_complete (op->book, op->id);
- break;
- }
-
- object_path = construct_bookview_path ();
- connection = e_data_book_get_connection (op->book);
-
- view = e_data_book_view_new (
- op->backend, card_sexp,
- connection, object_path, &error);
-
- g_object_unref (card_sexp);
-
- /* Sanity check. */
- g_return_if_fail (
- ((view != NULL) && (error == NULL)) ||
- ((view == NULL) && (error != NULL)));
-
- if (error != NULL) {
- /* Translators: This is prefix to a detailed error message */
- g_prefix_error (&error, "%s", _("Invalid query: "));
- data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- op->invocation, error);
-
- op_complete (op->book, op->id);
- g_free (object_path);
- break;
- }
-
- e_book_backend_add_view (op->backend, view);
-
- e_dbus_address_book_complete_get_view (
- op->book->priv->dbus_interface,
- op->invocation,
- object_path);
-
- op_complete (op->book, op->id);
-
- g_object_unref (view);
- g_free (object_path);
- }
- break;
-
- case OP_CLOSE:
- if (op->sender != NULL)
- cancel_operations_for_sender (op->book, op->sender);
-
- if (op->book->priv->dbus_interface != NULL)
- e_dbus_address_book_complete_close (
- op->book->priv->dbus_interface,
- op->invocation);
-
- /* 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,
- EBookBackend *backend,
- 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->backend = g_object_ref (backend);
- 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:
*
@@ -970,176 +536,457 @@ e_data_book_string_slist_to_comma_string (const GSList *strings)
return res;
}
+static void
+data_book_complete_open_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GError *error = NULL;
+
+ e_book_backend_open_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
+
+ if (error == NULL) {
+ e_dbus_address_book_complete_open (
+ async_context->interface,
+ async_context->invocation);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_open_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_OPEN, book, backend, invocation);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_open (
+ backend,
+ async_context->cancellable,
+ data_book_complete_open_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_refresh_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GError *error = NULL;
+
+ e_book_backend_refresh_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
+
+ if (error == NULL) {
+ e_dbus_address_book_complete_refresh (
+ async_context->interface,
+ async_context->invocation);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_refresh_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_REFRESH, book, backend, invocation);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_refresh (
+ backend,
+ async_context->cancellable,
+ data_book_complete_refresh_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_get_contact_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EContact *contact;
+ GError *error = NULL;
+
+ contact = e_book_backend_get_contact_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((contact != NULL) && (error == NULL)) ||
+ ((contact == NULL) && (error != NULL)));
+
+ if (contact != NULL) {
+ gchar *vcard;
+ gchar *utf8_vcard;
+
+ vcard = e_vcard_to_string (
+ E_VCARD (contact),
+ EVC_FORMAT_VCARD_30);
+ utf8_vcard = e_util_utf8_make_valid (vcard);
+ e_dbus_address_book_complete_get_contact (
+ async_context->interface,
+ async_context->invocation,
+ utf8_vcard);
+ g_free (utf8_vcard);
+ g_free (vcard);
+
+ g_object_unref (contact);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_get_contact_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar *in_uid,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_GET_CONTACT, book, backend, invocation);
- op->d.uid = g_strdup (in_uid);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_get_contact (
+ backend, in_uid,
+ async_context->cancellable,
+ data_book_complete_get_contact_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_get_contact_list_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GQueue queue = G_QUEUE_INIT;
+ GError *error = NULL;
+
+ e_book_backend_get_contact_list_finish (
+ E_BOOK_BACKEND (source_object), result, &queue, &error);
+
+ if (error == NULL) {
+ gchar **strv;
+ gint ii = 0;
+
+ strv = g_new0 (gchar *, queue.length + 1);
+
+ while (!g_queue_is_empty (&queue)) {
+ EContact *contact;
+ gchar *vcard;
+
+ contact = g_queue_pop_head (&queue);
+
+ vcard = e_vcard_to_string (
+ E_VCARD (contact),
+ EVC_FORMAT_VCARD_30);
+ strv[ii++] = e_util_utf8_make_valid (vcard);
+ g_free (vcard);
+
+ g_object_unref (contact);
+ }
+
+ e_dbus_address_book_complete_get_contact_list (
+ async_context->interface,
+ async_context->invocation,
+ (const gchar * const *) strv);
+
+ g_strfreev (strv);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_get_contact_list_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar *in_query,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_GET_CONTACTS, book, backend, invocation);
- op->d.query = g_strdup (in_query);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_get_contact_list (
+ backend, in_query,
+ async_context->cancellable,
+ data_book_complete_get_contact_list_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_get_contact_list_uids_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GQueue queue = G_QUEUE_INIT;
+ GError *error = NULL;
+
+ e_book_backend_get_contact_list_uids_finish (
+ E_BOOK_BACKEND (source_object), result, &queue, &error);
+
+ if (error == NULL) {
+ gchar **strv;
+ gint ii = 0;
+
+ strv = g_new0 (gchar *, queue.length + 1);
+
+ while (!g_queue_is_empty (&queue)) {
+ gchar *uid = g_queue_pop_head (&queue);
+ strv[ii++] = e_util_utf8_make_valid (uid);
+ g_free (uid);
+ }
+
+ e_dbus_address_book_complete_get_contact_list_uids (
+ async_context->interface,
+ async_context->invocation,
+ (const gchar * const *) strv);
+
+ g_strfreev (strv);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_get_contact_list_uids_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar *in_query,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_GET_CONTACTS_UIDS, book, backend, invocation);
- op->d.query = g_strdup (in_query);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_get_contact_list_uids (
+ backend, in_query,
+ async_context->cancellable,
+ data_book_complete_get_contact_list_uids_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_create_contacts_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GQueue queue = G_QUEUE_INIT;
+ GError *error = NULL;
+
+ e_book_backend_create_contacts_finish (
+ E_BOOK_BACKEND (source_object), result, &queue, &error);
+
+ if (error == NULL) {
+ gchar **strv;
+ gint ii = 0;
+
+ strv = g_new0 (gchar *, queue.length + 1);
+
+ while (!g_queue_is_empty (&queue)) {
+ EContact *contact;
+ const gchar *uid;
+
+ contact = g_queue_pop_head (&queue);
+ uid = e_contact_get_const (contact, E_CONTACT_UID);
+ strv[ii++] = e_util_utf8_make_valid (uid);
+ }
+
+ e_dbus_address_book_complete_create_contacts (
+ async_context->interface,
+ async_context->invocation,
+ (const gchar * const *) strv);
+
+ g_strfreev (strv);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_create_contacts_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar * const *in_vcards,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_ADD_CONTACTS, book, backend, invocation);
- op->d.vcards = e_util_strv_to_slist (in_vcards);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_create_contacts (
+ backend, in_vcards,
+ async_context->cancellable,
+ data_book_complete_create_contacts_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_modify_contacts_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GError *error = NULL;
+
+ e_book_backend_modify_contacts_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
+
+ if (error == NULL) {
+ e_dbus_address_book_complete_modify_contacts (
+ async_context->interface,
+ async_context->invocation);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_modify_contacts_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar * const *in_vcards,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_MODIFY_CONTACTS, book, backend, invocation);
- op->d.vcards = e_util_strv_to_slist (in_vcards);
+ async_context = async_context_new (data_book, invocation);
- op_dispatch (book, op);
+ e_book_backend_modify_contacts (
+ backend, in_vcards,
+ async_context->cancellable,
+ data_book_complete_modify_contacts_cb,
+ async_context);
g_object_unref (backend);
return TRUE;
}
+static void
+data_book_complete_remove_contacts_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ GError *error = NULL;
+
+ e_book_backend_remove_contacts_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
+
+ if (error == NULL) {
+ e_dbus_address_book_complete_remove_contacts (
+ async_context->interface,
+ async_context->invocation);
+ } else {
+ g_dbus_method_invocation_take_error (
+ async_context->invocation, error);
+ }
+
+ async_context_free (async_context);
+}
+
static gboolean
data_book_handle_remove_contacts_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar * const *in_uids,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ AsyncContext *async_context;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_REMOVE_CONTACTS, book, backend, invocation);
+ async_context = async_context_new (data_book, invocation);
- /* Allow an empty array to be removed */
- for (; in_uids && *in_uids; in_uids++) {
- op->d.ids = g_slist_prepend (op->d.ids, g_strdup (*in_uids));
- }
-
- op_dispatch (book, op);
+ e_book_backend_remove_contacts (
+ backend, in_uids,
+ async_context->cancellable,
+ data_book_complete_remove_contacts_cb,
+ async_context);
g_object_unref (backend);
@@ -1150,19 +997,54 @@ static gboolean
data_book_handle_get_view_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
const gchar *in_query,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
+ EDataBookView *view;
+ EBookBackendSExp *sexp;
+ GDBusConnection *connection;
+ gchar *object_path;
+ GError *error = NULL;
- backend = e_data_book_ref_backend (book);
+ backend = e_data_book_ref_backend (data_book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_new (OP_GET_VIEW, book, backend, invocation);
- op->d.query = g_strdup (in_query);
+ sexp = e_book_backend_sexp_new (in_query);
+ if (sexp == NULL) {
+ g_dbus_method_invocation_return_error_literal (
+ invocation,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_INVALID_QUERY,
+ _("Invalid query"));
+ g_object_unref (backend);
+ return TRUE;
+ }
+
+ object_path = construct_bookview_path ();
+ connection = g_dbus_method_invocation_get_connection (invocation);
- /* This operation is never queued. */
- e_operation_pool_push (ops_pool, op);
+ view = e_data_book_view_new (
+ backend, sexp, connection, object_path, &error);
+
+ g_object_unref (sexp);
+
+ /* Sanity check. */
+ g_return_val_if_fail (
+ ((view != NULL) && (error == NULL)) ||
+ ((view == NULL) && (error != NULL)), FALSE);
+
+ if (view != NULL) {
+ e_dbus_address_book_complete_get_view (
+ interface, invocation, object_path);
+ e_book_backend_add_view (backend, view);
+ g_object_unref (view);
+ } else {
+ data_book_convert_to_client_error (error);
+ g_prefix_error (&error, "%s", _("Invalid query: "));
+ g_dbus_method_invocation_take_error (invocation, error);
+ }
+
+ g_free (object_path);
g_object_unref (backend);
@@ -1172,19 +1054,15 @@ data_book_handle_get_view_cb (EDBusAddressBook *interface,
static gboolean
data_book_handle_close_cb (EDBusAddressBook *interface,
GDBusMethodInvocation *invocation,
- EDataBook *book)
+ EDataBook *data_book)
{
- OperationData *op;
EBookBackend *backend;
const gchar *sender;
- backend = e_data_book_ref_backend (book);
- g_return_val_if_fail (backend != NULL, FALSE);
-
- op = op_new (OP_CLOSE, book, backend, invocation);
+ e_dbus_address_book_complete_close (interface, invocation);
- /* This operation is never queued. */
- e_operation_pool_push (ops_pool, op);
+ backend = e_data_book_ref_backend (data_book);
+ g_return_val_if_fail (backend != NULL, FALSE);
sender = g_dbus_method_invocation_get_sender (invocation);
g_signal_emit_by_name (backend, "closed", sender);
@@ -1199,66 +1077,31 @@ e_data_book_respond_open (EDataBook *book,
guint opid,
GError *error)
{
- DirectOperationData *direct = NULL;
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, &direct);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
+
+ simple = e_book_backend_prepare_for_completion (backend, opid, NULL);
+ g_return_if_fail (simple != NULL);
/* Translators: This is prefix to a detailed error message */
g_prefix_error (&error, "%s", _("Cannot open book: "));
book->priv->opened = (error == NULL);
- if (direct) {
- gboolean result = FALSE;
-
- if (error) {
- data_book_convert_to_client_error (error);
- g_simple_async_result_take_error (
- direct->result, 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 {
+ if (error != NULL) {
data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
-
- /* Dispatch any pending operations. */
- g_mutex_lock (&book->priv->open_lock);
-
- if (opid == book->priv->open_opid) {
- OperationData *op;
-
- book->priv->open_opid = 0;
-
- while (!g_queue_is_empty (&book->priv->open_queue)) {
- op = g_queue_pop_head (&book->priv->open_queue);
- e_operation_pool_push (ops_pool, op);
- }
- }
+ g_simple_async_result_complete_in_idle (simple);
- g_mutex_unlock (&book->priv->open_lock);
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1275,27 +1118,29 @@ e_data_book_respond_refresh (EDataBook *book,
guint32 opid,
GError *error)
{
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, NULL);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
- /* Translators: This is prefix to a detailed error message */
- g_prefix_error (&error, "%s", _("Cannot refresh address book: "));
+ simple = e_book_backend_prepare_for_completion (backend, opid, NULL);
+ g_return_if_fail (simple);
- if (error == NULL) {
- e_dbus_address_book_complete_refresh (
- book->priv->dbus_interface,
- data->invocation);
- } else {
+ /* Translators: This is prefix to a detailed error message */
+ g_prefix_error (&error, "%s", _("Cannot refresh address book: "));
+
+ if (error != NULL) {
data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1311,24 +1156,32 @@ e_data_book_respond_get_backend_property (EDataBook *book,
GError *error,
const gchar *prop_value)
{
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, NULL);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
+
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
if (error == NULL) {
- e_data_book_report_backend_property_changed (
- book, data->d.prop_name, prop_value);
+ /* Convert NULL to an empty string. */
+ if (prop_value == NULL)
+ prop_value = "";
+ g_queue_push_tail (queue, g_strdup (prop_value));
} else {
- /* This should never happen, since all backend property
- * requests now originate from our constructed() method. */
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
void
@@ -1337,64 +1190,37 @@ e_data_book_respond_get_contact (EDataBook *book,
GError *error,
const gchar *vcard)
{
- DirectOperationData *direct = NULL;
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, &direct);
- g_return_if_fail (data != NULL);
-
- 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 (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);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
- } else if (error == NULL) {
- gchar *utf8_vcard;
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
- utf8_vcard = e_util_utf8_make_valid (vcard);
+ /* Translators: This is prefix to a detailed error message */
+ g_prefix_error (&error, "%s", _("Cannot get contact: "));
- e_dbus_address_book_complete_get_contact (
- book->priv->dbus_interface,
- data->invocation,
- utf8_vcard);
+ if (error == NULL) {
+ EContact *contact;
- g_free (utf8_vcard);
+ contact = e_contact_new_from_vcard (vcard);
+ g_queue_push_tail (queue, g_object_ref (contact));
+ g_object_unref (contact);
} else {
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ data_book_convert_to_client_error (error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
void
@@ -1403,83 +1229,44 @@ e_data_book_respond_get_contact_list (EDataBook *book,
GError *error,
const GSList *cards)
{
- DirectOperationData *direct = NULL;
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, &direct);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
- 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);
- }
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != 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);
- }
- }
+ /* Translators: This is prefix to a detailed error message */
+ g_prefix_error (&error, "%s", _("Cannot get contact list: "));
- /* Deliver the result to the caller */
- direct_operation_complete (direct);
+ if (error == NULL) {
+ GSList *list, *link;
- } else if (error == NULL) {
- gchar **strv;
- guint length;
- gint ii = 0;
+ list = (GSList *) cards;
- length = g_slist_length ((GSList *) cards);
- strv = g_new0 (gchar *, length + 1);
+ for (link = list; link != NULL; link = g_slist_next (link)) {
+ EContact *contact;
- while (cards != NULL) {
- strv[ii++] = e_util_utf8_make_valid (cards->data);
- cards = g_slist_next ((GSList *) cards);
+ contact = e_contact_new_from_vcard (link->data);
+ g_queue_push_tail (queue, g_object_ref (contact));
+ g_object_unref (contact);
}
- e_dbus_address_book_complete_get_contact_list (
- book->priv->dbus_interface,
- data->invocation,
- (const gchar * const *) strv);
-
- g_strfreev (strv);
} else {
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ data_book_convert_to_client_error (error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1495,73 +1282,39 @@ e_data_book_respond_get_contact_list_uids (EDataBook *book,
GError *error,
const GSList *uids)
{
- DirectOperationData *direct = NULL;
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, &direct);
- g_return_if_fail (data != NULL);
-
- 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 (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);
- }
- }
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
- /* Deliver the result to the caller */
- direct_operation_complete (direct);
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
- } else if (error == NULL) {
- gchar **strv;
- guint length;
- gint ii = 0;
+ /* Translators: This is prefix to a detailed error message */
+ g_prefix_error (&error, "%s", _("Cannot get contact list uids: "));
- length = g_slist_length ((GSList *) uids);
- strv = g_new0 (gchar *, length + 1);
+ if (error == NULL) {
+ GSList *list, *link;
- while (uids != NULL) {
- strv[ii++] = e_util_utf8_make_valid (uids->data);
- uids = g_slist_next ((GSList *) uids);
- }
+ list = (GSList *) uids;
- e_dbus_address_book_complete_get_contact_list_uids (
- book->priv->dbus_interface,
- data->invocation,
- (const gchar * const *) strv);
+ for (link = list; link != NULL; link = g_slist_next (link))
+ g_queue_push_tail (queue, g_strdup (link->data));
- g_strfreev (strv);
} else {
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ data_book_convert_to_client_error (error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1577,52 +1330,41 @@ e_data_book_respond_create_contacts (EDataBook *book,
GError *error,
const GSList *contacts)
{
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, NULL);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
+
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
/* Translators: This is prefix to a detailed error message */
g_prefix_error (&error, "%s", _("Cannot add contact: "));
if (error == NULL) {
- gchar **strv;
- guint length;
- gint ii = 0;
+ GSList *list, *link;
- length = g_slist_length ((GSList *) contacts);
- strv = g_new0 (gchar *, length + 1);
+ list = (GSList *) contacts;
- while (contacts != NULL) {
- EContact *contact = E_CONTACT (contacts->data);
- const gchar *uid;
-
- uid = e_contact_get_const (contact, E_CONTACT_UID);
- strv[ii++] = e_util_utf8_make_valid (uid);
-
- e_book_backend_notify_update (data->backend, contact);
-
- contacts = g_slist_next ((GSList *) contacts);
+ for (link = list; link != NULL; link = g_slist_next (link)) {
+ EContact *contact = E_CONTACT (link->data);
+ g_queue_push_tail (queue, g_object_ref (contact));
}
- e_dbus_address_book_complete_create_contacts (
- book->priv->dbus_interface,
- data->invocation,
- (const gchar * const *) strv);
-
- e_book_backend_notify_complete (data->backend);
-
- g_strfreev (strv);
-
} else {
data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1638,36 +1380,41 @@ e_data_book_respond_modify_contacts (EDataBook *book,
GError *error,
const GSList *contacts)
{
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, NULL);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
+
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
/* Translators: This is prefix to a detailed error message */
g_prefix_error (&error, "%s", _("Cannot modify contacts: "));
if (error == NULL) {
- e_dbus_address_book_complete_modify_contacts (
- book->priv->dbus_interface,
- data->invocation);
+ GSList *list, *link;
+
+ list = (GSList *) contacts;
- while (contacts != NULL) {
+ for (link = list; link != NULL; link = g_slist_next (link)) {
EContact *contact = E_CONTACT (contacts->data);
- e_book_backend_notify_update (data->backend, contact);
- contacts = g_slist_next ((GSList *) contacts);
+ g_queue_push_tail (queue, g_object_ref (contact));
}
- e_book_backend_notify_complete (data->backend);
-
} else {
data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
void
@@ -1676,35 +1423,39 @@ e_data_book_respond_remove_contacts (EDataBook *book,
GError *error,
const GSList *ids)
{
- OperationData *data;
+ EBookBackend *backend;
+ GSimpleAsyncResult *simple;
+ GQueue *queue = NULL;
g_return_if_fail (E_IS_DATA_BOOK (book));
- data = op_claim (book, opid, NULL);
- g_return_if_fail (data != NULL);
+ backend = e_data_book_ref_backend (book);
+ g_return_if_fail (backend != NULL);
+
+ simple = e_book_backend_prepare_for_completion (backend, opid, &queue);
+ g_return_if_fail (simple != NULL);
+ g_return_if_fail (queue != NULL);
/* Translators: This is prefix to a detailed error message */
g_prefix_error (&error, "%s", _("Cannot remove contacts: "));
if (error == NULL) {
- e_dbus_address_book_complete_remove_contacts (
- book->priv->dbus_interface,
- data->invocation);
+ GSList *list, *link;
- while (ids != NULL) {
- e_book_backend_notify_remove (data->backend, ids->data);
- ids = g_slist_next ((GSList *) ids);
- }
+ list = (GSList *) ids;
- e_book_backend_notify_complete (data->backend);
+ for (link = list; link != NULL; link = g_slist_next (link))
+ g_queue_push_tail (queue, g_strdup (link->data));
} else {
data_book_convert_to_client_error (error);
- g_dbus_method_invocation_take_error (
- data->invocation, error);
+ g_simple_async_result_take_error (simple, error);
}
- op_unref (data);
+ g_simple_async_result_complete_in_idle (simple);
+
+ g_object_unref (simple);
+ g_object_unref (backend);
}
/**
@@ -1894,6 +1645,8 @@ data_book_dispose (GObject *object)
priv->direct_module = NULL;
}
+ g_hash_table_remove_all (priv->sender_table);
+
/* Chain up to parent's dispose() metnod. */
G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
}
@@ -1907,27 +1660,14 @@ data_book_finalize (GObject *object)
g_free (priv->object_path);
- if (priv->pending_ops) {
- g_hash_table_destroy (priv->pending_ops);
- priv->pending_ops = NULL;
- }
-
- g_rec_mutex_clear (&priv->pending_ops_lock);
- if (priv->direct_ops) {
- g_hash_table_destroy (priv->direct_ops);
- priv->direct_ops = NULL;
- }
+ g_mutex_clear (&priv->sender_lock);
+ g_hash_table_destroy (priv->sender_table);
if (priv->dbus_interface) {
g_object_unref (priv->dbus_interface);
priv->dbus_interface = NULL;
}
- g_mutex_clear (&priv->open_lock);
-
- /* This should be empty now, else we leak memory. */
- g_warn_if_fail (g_queue_is_empty (&priv->open_queue));
-
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object);
}
@@ -1939,17 +1679,18 @@ data_book_initable_init (GInitable *initable,
{
EBookBackend *backend;
EDataBook *book;
- OperationData *op;
gboolean success = TRUE;
book = E_DATA_BOOK (initable);
backend = e_data_book_ref_backend (book);
- if (book->priv->connection != NULL && book->priv->object_path != NULL) {
+ /* Attach ourselves to the EBookBackend. */
+ e_book_backend_set_data_book (backend, book);
- /* Attach ourselves to the EBookBackend. */
- e_book_backend_set_data_book (backend, book);
+ if (book->priv->connection != NULL && book->priv->object_path != NULL) {
+ const gchar *prop_name;
+ gchar *prop_value;
book->priv->dbus_interface =
e_dbus_address_book_skeleton_new ();
@@ -2015,37 +1756,35 @@ data_book_initable_init (GInitable *initable,
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, backend, NULL);
- op->d.prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
- e_book_backend_get_backend_property (
- backend, book, op->id,
- op->cancellable, op->d.prop_name);
- op_unref (op);
-
- op = op_new (OP_GET_BACKEND_PROPERTY, book, backend, NULL);
- op->d.prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
- e_book_backend_get_backend_property (
- backend, book, op->id,
- op->cancellable, op->d.prop_name);
- op_unref (op);
-
- op = op_new (OP_GET_BACKEND_PROPERTY, book, backend, NULL);
- op->d.prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
- e_book_backend_get_backend_property (
- backend, book, op->id,
- op->cancellable, op->d.prop_name);
- op_unref (op);
-
- op = op_new (OP_GET_BACKEND_PROPERTY, book, backend, NULL);
- op->d.prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
- e_book_backend_get_backend_property (
- backend, book, op->id,
- op->cancellable, op->d.prop_name);
- op_unref (op);
+ /* XXX Initialize the rest of the properties. */
+
+ prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
+ prop_value = e_book_backend_get_backend_property_sync (
+ backend, prop_name, NULL, NULL);
+ e_data_book_report_backend_property_changed (
+ book, prop_name, prop_value);
+ g_free (prop_value);
+
+ prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
+ prop_value = e_book_backend_get_backend_property_sync (
+ backend, prop_name, NULL, NULL);
+ e_data_book_report_backend_property_changed (
+ book, prop_name, prop_value);
+ g_free (prop_value);
+
+ prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
+ prop_value = e_book_backend_get_backend_property_sync (
+ backend, prop_name, NULL, NULL);
+ e_data_book_report_backend_property_changed (
+ book, prop_name, prop_value);
+ g_free (prop_value);
+
+ prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
+ prop_value = e_book_backend_get_backend_property_sync (
+ backend, prop_name, NULL, NULL);
+ e_data_book_report_backend_property_changed (
+ book, prop_name, prop_value);
+ g_free (prop_value);
success = g_dbus_interface_skeleton_export (
G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
@@ -2110,9 +1849,6 @@ e_data_book_class_init (EDataBookClass *class)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
-
- if (!ops_pool)
- ops_pool = e_operation_pool_new (10, operation_thread, NULL);
}
static void
@@ -2122,20 +1858,17 @@ e_data_book_initable_init (GInitableIface *interface)
}
static void
-e_data_book_init (EDataBook *ebook)
+e_data_book_init (EDataBook *data_book)
{
- ebook->priv = E_DATA_BOOK_GET_PRIVATE (ebook);
+ data_book->priv = E_DATA_BOOK_GET_PRIVATE (data_book);
- 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_mutex_init (&data_book->priv->sender_lock);
+
+ data_book->priv->sender_table = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_ptr_array_unref);
}
/**
@@ -2262,7 +1995,6 @@ e_data_book_new_direct (ESourceRegistry *registry,
book = g_initable_new (
E_TYPE_DATA_BOOK, NULL, error,
"backend", backend, NULL);
- e_book_backend_set_data_book (backend, book);
if (!book) {
g_type_module_unuse (G_TYPE_MODULE (module));
@@ -2366,22 +2098,6 @@ e_data_book_is_opened (EDataBook *book)
* 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;
-}
-
/**
* e_data_book_open_sync:
* @book: an #EDataBook
@@ -2403,64 +2119,18 @@ e_data_book_open_sync (EDataBook *book,
GError **error)
{
EBookBackend *backend;
- DirectOperationData *data = NULL;
- OperationData *op;
- gboolean result = FALSE;
+ gboolean success;
g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
backend = e_data_book_ref_backend (book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_direct_new (OP_OPEN, book, backend, 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);
+ success = e_book_backend_open_sync (backend, cancellable, error);
g_object_unref (backend);
- 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);
+ return success;
}
/**
@@ -2484,20 +2154,21 @@ e_data_book_close (EDataBook *book,
GAsyncReadyCallback callback,
gpointer user_data)
{
- EBookBackend *backend;
- OperationData *op;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
- backend = e_data_book_ref_backend (book);
- g_return_if_fail (backend != NULL);
+ simple = g_simple_async_result_new (
+ G_OBJECT (book), callback,
+ user_data, e_data_book_close);
- op = op_direct_new (OP_CLOSE, book, backend, cancellable, callback, user_data, e_data_book_close,
FALSE, NULL);
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
- /* This operation is never queued. */
- e_operation_pool_push (ops_pool, op);
+ /* XXX This operation has no GDBusMethodInvocation,
+ * so there's nothing to do. */
+ g_simple_async_result_complete_in_idle (simple);
- g_object_unref (backend);
+ g_object_unref (simple);
}
/**
@@ -2518,15 +2189,16 @@ e_data_book_close_finish (EDataBook *book,
GAsyncResult *result,
GError **error)
{
- gboolean res;
+ GSimpleAsyncResult *simple;
- g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (book), e_data_book_close), 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);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
- return res;
+ /* Assume success unless a GError is set. */
+ return !g_simple_async_result_propagate_error (simple, error);
}
/**
@@ -2549,28 +2221,43 @@ e_data_book_close_sync (EDataBook *book,
GCancellable *cancellable,
GError **error)
{
- EBookBackend *backend;
- DirectOperationData *data = NULL;
- OperationData *op;
- gboolean result = FALSE;
+ /* XXX This operation has no GDBusMethodInvocation,
+ * so there's nothing to do. */
+ return TRUE;
+}
- g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+static void
+data_book_get_contact_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ EContact *contact;
+ GError *error = NULL;
- backend = e_data_book_ref_backend (book);
- g_return_val_if_fail (backend != NULL, FALSE);
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
- op = op_direct_new (OP_CLOSE, book, backend, cancellable, NULL, NULL, e_data_book_close_sync, TRUE,
&data);
+ contact = e_book_backend_get_contact_finish (
+ E_BOOK_BACKEND (source_object), result, &error);
- /* This operation is never queued. */
- e_operation_pool_push (ops_pool, op);
+ /* Sanity check. */
+ g_return_if_fail (
+ ((contact != NULL) && (error == NULL)) ||
+ ((contact == NULL) && (error != NULL)));
- direct_operation_wait (data);
- result = e_data_book_close_finish (book, G_ASYNC_RESULT (data->result), error);
- direct_operation_data_free (data);
+ if (contact != NULL) {
+ g_simple_async_result_set_op_res_gpointer (
+ simple, g_object_ref (contact),
+ (GDestroyNotify) g_object_unref);
+ g_object_unref (contact);
+ }
- g_object_unref (backend);
+ if (error != NULL)
+ g_simple_async_result_take_error (simple, error);
- return result;
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
}
/**
@@ -2599,7 +2286,7 @@ e_data_book_get_contact (EDataBook *book,
gpointer user_data)
{
EBookBackend *backend;
- OperationData *op;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
g_return_if_fail (uid && uid[0]);
@@ -2607,11 +2294,16 @@ e_data_book_get_contact (EDataBook *book,
backend = e_data_book_ref_backend (book);
g_return_if_fail (backend != NULL);
- op = op_direct_new (OP_GET_CONTACT, book, backend, cancellable, callback, user_data,
e_data_book_get_contact, FALSE, NULL);
- op->d.uid = g_strdup (uid);
+ simple = g_simple_async_result_new (
+ G_OBJECT (book), callback,
+ user_data, e_data_book_get_contact);
- op_dispatch (book, op);
+ e_book_backend_get_contact (
+ backend, uid, cancellable,
+ data_book_get_contact_cb,
+ g_object_ref (simple));
+ g_object_unref (simple);
g_object_unref (backend);
}
@@ -2635,22 +2327,24 @@ e_data_book_get_contact_finish (EDataBook *book,
EContact **contact,
GError **error)
{
+ GSimpleAsyncResult *simple;
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);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ ret_contact = g_simple_async_result_get_op_res_gpointer (simple);
- if (contact) {
- if (ret_contact)
- *contact = g_object_ref (ret_contact);
- else
- *contact = NULL;
- }
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_return_val_if_fail (ret_contact != NULL, FALSE);
- return ret_contact != NULL;
+ if (contact != NULL)
+ *contact = g_object_ref (ret_contact);
+
+ return TRUE;
}
/**
@@ -2678,9 +2372,8 @@ e_data_book_get_contact_sync (EDataBook *book,
GError **error)
{
EBookBackend *backend;
- DirectOperationData *data = NULL;
- OperationData *op;
- gboolean result = FALSE;
+ EContact *ret_contact;
+ gboolean success = FALSE;
g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
g_return_val_if_fail (uid && uid[0], FALSE);
@@ -2688,18 +2381,57 @@ e_data_book_get_contact_sync (EDataBook *book,
backend = e_data_book_ref_backend (book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_direct_new (OP_GET_CONTACT, book, backend, cancellable, NULL, NULL,
e_data_book_get_contact_sync, TRUE, &data);
- op->d.uid = g_strdup (uid);
+ ret_contact = e_book_backend_get_contact_sync (
+ backend, uid, cancellable, error);
+
+ if (ret_contact != NULL) {
+ if (contact != NULL)
+ *contact = g_object_ref (ret_contact);
- op_dispatch (book, op);
+ g_object_unref (ret_contact);
- direct_operation_wait (data);
- result = e_data_book_get_contact_finish (book, G_ASYNC_RESULT (data->result), contact, error);
- direct_operation_data_free (data);
+ success = TRUE;
+ }
g_object_unref (backend);
- return result;
+ return success;
+}
+
+static void
+data_book_get_contacts_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GQueue queue = G_QUEUE_INIT;
+ GError *error = NULL;
+
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ e_book_backend_get_contact_list_finish (
+ E_BOOK_BACKEND (source_object), result, &queue, &error);
+
+ if (error == NULL) {
+ GSList *list = NULL;
+
+ while (!g_queue_is_empty (&queue)) {
+ EContact *contact;
+
+ contact = g_queue_pop_tail (&queue);
+ list = g_slist_prepend (list, contact);
+ }
+
+ /* XXX This assumes the finish() function will be called. */
+ g_simple_async_result_set_op_res_gpointer (
+ simple, list, (GDestroyNotify) NULL);
+ } else {
+ g_simple_async_result_take_error (simple, error);
+ }
+
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
}
/**
@@ -2728,18 +2460,25 @@ e_data_book_get_contacts (EDataBook *book,
gpointer user_data)
{
EBookBackend *backend;
- OperationData *op;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
backend = e_data_book_ref_backend (book);
g_return_if_fail (backend != NULL);
- op = op_direct_new (OP_GET_CONTACTS, book, backend, cancellable, callback, user_data,
e_data_book_get_contacts, FALSE, NULL);
- op->d.query = g_strdup (sexp);
+ simple = g_simple_async_result_new (
+ G_OBJECT (book), callback, user_data,
+ e_data_book_get_contacts);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
- op_dispatch (book, op);
+ e_book_backend_get_contact_list (
+ backend, sexp, cancellable,
+ data_book_get_contacts_cb,
+ g_object_ref (simple));
+ g_object_unref (simple);
g_object_unref (backend);
}
@@ -2763,26 +2502,26 @@ e_data_book_get_contacts_finish (EDataBook *book,
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);
+ GSimpleAsyncResult *simple;
+ GSList *list;
- ret_contacts = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (book),
+ e_data_book_get_contacts), FALSE);
- if (contacts) {
- if (ret_contacts)
- *contacts = e_util_copy_object_slist (NULL, ret_contacts);
- else
- *contacts = NULL;
- }
+ simple = G_SIMPLE_ASYNC_RESULT (result);
- /* If there was an error, the return is FALSE, otherwise
- * the call was successfull even if no results were found
- */
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
+ list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (contacts != NULL)
+ *contacts = list;
+ else
+ g_slist_free_full (list, (GDestroyNotify) g_object_unref);
+
return TRUE;
}
@@ -2812,27 +2551,65 @@ e_data_book_get_contacts_sync (EDataBook *book,
GError **error)
{
EBookBackend *backend;
- DirectOperationData *data = NULL;
- OperationData *op;
- gboolean result = FALSE;
+ GQueue queue = G_QUEUE_INIT;
+ gboolean success;
g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
backend = e_data_book_ref_backend (book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_direct_new (OP_GET_CONTACTS, book, backend, cancellable, NULL, NULL,
e_data_book_get_contacts_sync, TRUE, &data);
- op->d.query = g_strdup (sexp);
+ success = e_book_backend_get_contact_list_sync (
+ backend, sexp, &queue, cancellable, error);
- 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);
+ if (contacts != NULL) {
+ while (!g_queue_is_empty (&queue))
+ *contacts = g_slist_prepend (
+ *contacts, g_queue_pop_tail (&queue));
+ } else {
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+ }
g_object_unref (backend);
- return result;
+ return success;
+}
+
+static void
+data_book_get_contacts_uids_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GQueue queue = G_QUEUE_INIT;
+ GError *error = NULL;
+
+ simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ e_book_backend_get_contact_list_uids_finish (
+ E_BOOK_BACKEND (source_object), result, &queue, &error);
+
+ if (error == NULL) {
+ GSList *list = NULL;
+
+ while (!g_queue_is_empty (&queue)) {
+ gchar *uid;
+
+ uid = g_queue_pop_tail (&queue);
+ list = g_slist_prepend (list, uid);
+ }
+
+ /* XXX This assumes the finish() function will be called. */
+ g_simple_async_result_set_op_res_gpointer (
+ simple, list, (GDestroyNotify) NULL);
+ } else {
+ g_simple_async_result_take_error (simple, error);
+ }
+
+ g_simple_async_result_complete (simple);
+
+ g_object_unref (simple);
}
/**
@@ -2861,18 +2638,25 @@ e_data_book_get_contacts_uids (EDataBook *book,
gpointer user_data)
{
EBookBackend *backend;
- OperationData *op;
+ GSimpleAsyncResult *simple;
g_return_if_fail (E_IS_DATA_BOOK (book));
backend = e_data_book_ref_backend (book);
g_return_if_fail (backend != NULL);
- op = op_direct_new (OP_GET_CONTACTS_UIDS, book, backend, cancellable, callback, user_data,
e_data_book_get_contacts_uids, FALSE, NULL);
- op->d.query = g_strdup (sexp);
+ simple = g_simple_async_result_new (
+ G_OBJECT (book), callback, user_data,
+ e_data_book_get_contacts_uids);
+
+ g_simple_async_result_set_check_cancellable (simple, cancellable);
- op_dispatch (book, op);
+ e_book_backend_get_contact_list_uids (
+ backend, sexp, cancellable,
+ data_book_get_contacts_uids_cb,
+ g_object_ref (simple));
+ g_object_unref (simple);
g_object_unref (backend);
}
@@ -2896,26 +2680,26 @@ e_data_book_get_contacts_uids_finish (EDataBook *book,
GSList **contacts_uids,
GError **error)
{
- GSList *ret_uids;
+ GSimpleAsyncResult *simple;
+ GSList *list;
- g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (
+ result, G_OBJECT (book),
+ e_data_book_get_contacts_uids), FALSE);
- ret_uids = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
-
- if (contacts_uids) {
- if (ret_uids)
- *contacts_uids = e_util_copy_string_slist (NULL, ret_uids);
- else
- *contacts_uids = NULL;
- }
+ simple = G_SIMPLE_ASYNC_RESULT (result);
- /* If there was an error, the return is FALSE, otherwise
- * the call was successfull even if no results were found
- */
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ if (g_simple_async_result_propagate_error (simple, error))
return FALSE;
+ list = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (contacts_uids != NULL)
+ *contacts_uids = list;
+ else
+ g_slist_free_full (list, (GDestroyNotify) g_free);
+
return TRUE;
}
@@ -2945,25 +2729,27 @@ e_data_book_get_contacts_uids_sync (EDataBook *book,
GError **error)
{
EBookBackend *backend;
- DirectOperationData *data = NULL;
- OperationData *op;
- gboolean result = FALSE;
+ GQueue queue = G_QUEUE_INIT;
+ gboolean success;
g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
backend = e_data_book_ref_backend (book);
g_return_val_if_fail (backend != NULL, FALSE);
- op = op_direct_new (OP_GET_CONTACTS_UIDS, book, backend, cancellable, NULL, NULL,
e_data_book_get_contacts_uids_sync, TRUE, &data);
- op->d.query = g_strdup (sexp);
+ success = e_book_backend_get_contact_list_uids_sync (
+ backend, sexp, &queue, cancellable, error);
- 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);
+ if (contacts_uids != NULL) {
+ while (!g_queue_is_empty (&queue))
+ *contacts_uids = g_slist_prepend (
+ *contacts_uids, g_queue_pop_tail (&queue));
+ } else {
+ while (!g_queue_is_empty (&queue))
+ g_free (g_queue_pop_head (&queue));
+ }
g_object_unref (backend);
- return result;
+ return success;
}
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index 836d96e..289048d 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -1,23 +1,19 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2006 OpenedHand Ltd
- * Copyright (C) 2009 Intel Corporation
+ * e-data-book.h
*
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of version 2.1 of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
*
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
- * Author: Ross Burton <ross linux intel com>
*/
#if !defined (__LIBEDATA_BOOK_H_INSIDE__) && !defined (LIBEDATA_BOOK_COMPILATION)
diff --git a/configure.ac b/configure.ac
index 6112c33..1e1ac78 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,7 +118,7 @@ LIBEDATACAL_CURRENT=20
LIBEDATACAL_REVISION=0
LIBEDATACAL_AGE=0
-LIBEDATABOOK_CURRENT=18
+LIBEDATABOOK_CURRENT=19
LIBEDATABOOK_REVISION=0
LIBEDATABOOK_AGE=0
diff --git a/docs/reference/addressbook/libedata-book/libedata-book-sections.txt
b/docs/reference/addressbook/libedata-book/libedata-book-sections.txt
index 78e8f48..eb8405b 100644
--- a/docs/reference/addressbook/libedata-book/libedata-book-sections.txt
+++ b/docs/reference/addressbook/libedata-book/libedata-book-sections.txt
@@ -19,15 +19,33 @@ e_book_backend_set_writable
e_book_backend_is_opened
e_book_backend_is_readonly
e_book_backend_is_removed
+e_book_backend_get_backend_property_sync
e_book_backend_get_backend_property
+e_book_backend_get_backend_property_finish
+e_book_backend_open_sync
e_book_backend_open
+e_book_backend_open_finish
+e_book_backend_refresh_sync
e_book_backend_refresh
+e_book_backend_refresh_finish
+e_book_backend_create_contacts_sync
e_book_backend_create_contacts
-e_book_backend_remove_contacts
+e_book_backend_create_contacts_finish
+e_book_backend_modify_contacts_sync
e_book_backend_modify_contacts
+e_book_backend_modify_contacts_finish
+e_book_backend_remove_contacts_sync
+e_book_backend_remove_contacts
+e_book_backend_remove_contacts_finish
+e_book_backend_get_contact_sync
e_book_backend_get_contact
+e_book_backend_get_contact_finish
+e_book_backend_get_contact_list_sync
e_book_backend_get_contact_list
+e_book_backend_get_contact_list_finish
+e_book_backend_get_contact_list_uids_sync
e_book_backend_get_contact_list_uids
+e_book_backend_get_contact_list_uids_finish
e_book_backend_start_view
e_book_backend_stop_view
e_book_backend_add_view
@@ -53,6 +71,7 @@ EBookBackendClass
e_book_backend_get_type
<SUBSECTION Private>
EBookBackendPrivate
+e_book_backend_prepare_for_completion
</SECTION>
<SECTION>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]