diff options
| author | Matthew Barnes <mbarnes@redhat.com> | 2013-04-03 08:26:27 -0400 |
|---|---|---|
| committer | Matthew Barnes <mbarnes@redhat.com> | 2013-04-03 15:25:42 -0400 |
| commit | ff89f59251f5af8dc5685418e766f12f4c814fe2 (patch) | |
| tree | 45d510412c0168d05fbd3e92b958b27d54728fc4 /addressbook/libedata-book | |
| parent | 80fbdba9285e636bd7473f5368fc3246be8999d1 (diff) | |
| download | evolution-data-server-ff89f59251f5af8dc5685418e766f12f4c814fe2.tar.gz | |
EBookBackend: Add the new backend API alongside the old one.
The new and old EBookBackend class methods will co-exist temporarily,
so I can start converting the simpler EBookBackendSync-based backends
and make final adjustments to the new API.
Diffstat (limited to 'addressbook/libedata-book')
| -rw-r--r-- | addressbook/libedata-book/e-book-backend.c | 663 | ||||
| -rw-r--r-- | addressbook/libedata-book/e-book-backend.h | 41 |
2 files changed, 620 insertions, 84 deletions
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c index 28dcb6ca1..ebe1da355 100644 --- a/addressbook/libedata-book/e-book-backend.c +++ b/addressbook/libedata-book/e-book-backend.c @@ -52,12 +52,18 @@ struct _EBookBackendPrivate { }; struct _AsyncContext { + + /* Indicates if we're using the old or new style API, + * as method results are stashed differently for each. */ + gboolean old_style; + /* Inputs */ gchar *uid; gchar *query; - GSList *string_list; + gchar **strv; /* Outputs */ + EContact *contact; GQueue result_queue; /* One of these should point to result_queue @@ -99,10 +105,9 @@ async_context_free (AsyncContext *async_context) g_free (async_context->uid); g_free (async_context->query); + g_strfreev (async_context->strv); - g_slist_free_full ( - async_context->string_list, - (GDestroyNotify) g_free); + g_clear_object (&async_context->contact); queue = async_context->object_queue; while (queue != NULL && !g_queue_is_empty (queue)) @@ -836,6 +841,35 @@ book_backend_open_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->open_sync != NULL); + + if (!e_book_backend_is_opened (backend)) { + GError *error = NULL; + + class->open_sync (backend, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_open() */ +static void +book_backend_open_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; backend = E_BOOK_BACKEND (source_object); @@ -883,21 +917,39 @@ e_book_backend_open (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; GSimpleAsyncResult *simple; g_return_if_fail (E_IS_BOOK_BACKEND (backend)); + class = E_BOOK_BACKEND_GET_CLASS (backend); + simple = g_simple_async_result_new ( G_OBJECT (backend), callback, user_data, e_book_backend_open); g_simple_async_result_set_check_cancellable (simple, cancellable); - book_backend_push_operation ( - backend, simple, cancellable, TRUE, - book_backend_open_thread); + if (class->open_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, TRUE, + book_backend_open_thread); + book_backend_dispatch_next_operation (backend); + + } else if (class->open != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, TRUE, + book_backend_open_thread_old_style); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -993,24 +1045,53 @@ book_backend_refresh_thread (GSimpleAsyncResult *simple, { 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->refresh_sync != NULL); - data_book = e_book_backend_ref_data_book (backend); - g_return_if_fail (data_book != NULL); - - if (class->refresh == NULL) { + if (!e_book_backend_is_opened (backend)) { g_simple_async_result_set_error ( simple, E_CLIENT_ERROR, - E_CLIENT_ERROR_NOT_SUPPORTED, + E_CLIENT_ERROR_NOT_OPENED, "%s", e_client_error_to_string ( - E_CLIENT_ERROR_NOT_SUPPORTED)); - g_simple_async_result_complete_in_idle (simple); + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->refresh_sync (backend, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } - } else if (!e_book_backend_is_opened (backend)) { + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_refresh() */ +static void +book_backend_refresh_thread_old_style (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->refresh != NULL); + + data_book = e_book_backend_ref_data_book (backend); + g_return_if_fail (data_book != NULL); + + if (!e_book_backend_is_opened (backend)) { g_simple_async_result_set_error ( simple, E_CLIENT_ERROR, E_CLIENT_ERROR_NOT_OPENED, @@ -1052,21 +1133,39 @@ e_book_backend_refresh (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; GSimpleAsyncResult *simple; g_return_if_fail (E_IS_BOOK_BACKEND (backend)); + class = E_BOOK_BACKEND_GET_CLASS (backend); + simple = g_simple_async_result_new ( G_OBJECT (backend), callback, user_data, e_book_backend_refresh); g_simple_async_result_set_check_cancellable (simple, cancellable); - book_backend_push_operation ( - backend, simple, cancellable, FALSE, - book_backend_refresh_thread); + if (class->refresh_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_refresh_thread); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else if (class->refresh != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_refresh_thread_old_style); + book_backend_dispatch_next_operation (backend); + + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -1167,6 +1266,49 @@ book_backend_create_contacts_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + AsyncContext *async_context; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->create_contacts_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->create_contacts_sync ( + backend, + (const gchar * const *) async_context->strv, + async_context->object_queue, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_create_contacts() */ +static void +book_backend_create_contacts_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -1189,13 +1331,25 @@ book_backend_create_contacts_thread (GSimpleAsyncResult *simple, g_simple_async_result_complete_in_idle (simple); } else { + GSList *list = NULL; guint32 opid; + guint ii; + + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; opid = book_backend_stash_operation (backend, simple); + /* The AsyncContext retains ownership of the strings. */ + for (ii = 0; async_context->strv[ii] != NULL; ii++) + list = g_slist_prepend (list, async_context->strv[ii]); + list = g_slist_reverse (list); + class->create_contacts ( - backend, data_book, opid, cancellable, - async_context->string_list); + backend, data_book, opid, cancellable, list); + + g_slist_free (list); } g_object_unref (data_book); @@ -1224,19 +1378,17 @@ e_book_backend_create_contacts (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; 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])); + class = E_BOOK_BACKEND_GET_CLASS (backend); async_context = g_slice_new0 (AsyncContext); - async_context->string_list = g_slist_reverse (list); + async_context->strv = g_strdupv ((gchar **) vcards); async_context->object_queue = &async_context->result_queue; simple = g_simple_async_result_new ( @@ -1248,11 +1400,26 @@ e_book_backend_create_contacts (EBookBackend *backend, 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); + if (class->create_contacts_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_create_contacts_thread); + book_backend_dispatch_next_operation (backend); + + } else if (class->create_contacts != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_create_contacts_thread_old_style); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -1300,10 +1467,10 @@ e_book_backend_create_contacts_finish (EBookBackend *backend, if (g_simple_async_result_propagate_error (simple, error)) return FALSE; - while (!g_queue_is_empty (&async_context->result_queue)) { + while (!g_queue_is_empty (async_context->object_queue)) { EContact *contact; - contact = g_queue_pop_head (&async_context->result_queue); + contact = g_queue_pop_head (async_context->object_queue); g_queue_push_tail (out_contacts, g_object_ref (contact)); e_book_backend_notify_update (backend, contact); g_object_unref (contact); @@ -1363,6 +1530,49 @@ book_backend_modify_contacts_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + AsyncContext *async_context; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->modify_contacts_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->modify_contacts_sync ( + backend, + (const gchar * const *) async_context->strv, + async_context->object_queue, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_modify_contacts() */ +static void +book_backend_modify_contacts_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -1385,13 +1595,25 @@ book_backend_modify_contacts_thread (GSimpleAsyncResult *simple, g_simple_async_result_complete_in_idle (simple); } else { + GSList *list = NULL; guint32 opid; + guint ii; + + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; opid = book_backend_stash_operation (backend, simple); + /* The AsyncContext retains ownership of the strings. */ + for (ii = 0; async_context->strv[ii] != NULL; ii++) + list = g_slist_prepend (list, async_context->strv[ii]); + list = g_slist_reverse (list); + class->modify_contacts ( - backend, data_book, opid, cancellable, - async_context->string_list); + backend, data_book, opid, cancellable, list); + + g_slist_free (list); } g_object_unref (data_book); @@ -1420,19 +1642,17 @@ e_book_backend_modify_contacts (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; 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])); + class = E_BOOK_BACKEND_GET_CLASS (backend); async_context = g_slice_new0 (AsyncContext); - async_context->string_list = g_slist_reverse (list); + async_context->strv = g_strdupv ((gchar **) vcards); async_context->object_queue = &async_context->result_queue; simple = g_simple_async_result_new ( @@ -1444,11 +1664,26 @@ e_book_backend_modify_contacts (EBookBackend *backend, 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); + if (class->modify_contacts_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_modify_contacts_thread); + book_backend_dispatch_next_operation (backend); + + } else if (class->modify_contacts != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_modify_contacts_thread_old_style); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -1488,10 +1723,10 @@ e_book_backend_modify_contacts_finish (EBookBackend *backend, if (g_simple_async_result_propagate_error (simple, error)) return FALSE; - while (!g_queue_is_empty (&async_context->result_queue)) { + while (!g_queue_is_empty (async_context->object_queue)) { EContact *contact; - contact = g_queue_pop_head (&async_context->result_queue); + contact = g_queue_pop_head (async_context->object_queue); e_book_backend_notify_update (backend, contact); g_object_unref (contact); } @@ -1553,6 +1788,48 @@ book_backend_remove_contacts_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + AsyncContext *async_context; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->remove_contacts_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->remove_contacts_sync ( + backend, + (const gchar * const *) async_context->strv, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_remove_contacts() */ +static void +book_backend_remove_contacts_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -1575,13 +1852,25 @@ book_backend_remove_contacts_thread (GSimpleAsyncResult *simple, g_simple_async_result_complete_in_idle (simple); } else { + GSList *list = NULL; guint32 opid; + guint ii; + + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; opid = book_backend_stash_operation (backend, simple); + /* The AsyncContext retains ownership of the strings. */ + for (ii = 0; async_context->strv[ii] != NULL; ii++) + list = g_slist_prepend (list, async_context->strv[ii]); + list = g_slist_reverse (list); + class->remove_contacts ( - backend, data_book, opid, cancellable, - async_context->string_list); + backend, data_book, opid, cancellable, list); + + g_slist_free (list); } g_object_unref (data_book); @@ -1610,19 +1899,17 @@ e_book_backend_remove_contacts (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; 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])); + class = E_BOOK_BACKEND_GET_CLASS (backend); async_context = g_slice_new0 (AsyncContext); - async_context->string_list = g_slist_reverse (list); + async_context->strv = g_strdupv ((gchar **) uids); async_context->string_queue = &async_context->result_queue; simple = g_simple_async_result_new ( @@ -1634,11 +1921,26 @@ e_book_backend_remove_contacts (EBookBackend *backend, 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); + if (class->remove_contacts_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_remove_contacts_thread); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else if (class->remove_contacts != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_remove_contacts_thread_old_style); + book_backend_dispatch_next_operation (backend); + + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -1664,6 +1966,7 @@ e_book_backend_remove_contacts_finish (EBookBackend *backend, { GSimpleAsyncResult *simple; AsyncContext *async_context; + guint ii; g_return_val_if_fail ( g_simple_async_result_is_valid ( @@ -1678,12 +1981,9 @@ e_book_backend_remove_contacts_finish (EBookBackend *backend, 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); + for (ii = 0; async_context->strv[ii] != NULL; ii++) { + const gchar *uid = async_context->strv[ii]; e_book_backend_notify_remove (backend, uid); - g_free (uid); } e_book_backend_notify_complete (backend); @@ -1746,6 +2046,48 @@ book_backend_get_contact_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + AsyncContext *async_context; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->get_contact_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + async_context->contact = class->get_contact_sync ( + backend, + async_context->uid, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_get_contact() */ +static void +book_backend_get_contact_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -1770,6 +2112,10 @@ book_backend_get_contact_thread (GSimpleAsyncResult *simple, } else { guint32 opid; + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; + opid = book_backend_stash_operation (backend, simple); class->get_contact ( @@ -1803,12 +2149,15 @@ e_book_backend_get_contact (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; GSimpleAsyncResult *simple; AsyncContext *async_context; g_return_if_fail (E_IS_BOOK_BACKEND (backend)); g_return_if_fail (uid != NULL); + class = E_BOOK_BACKEND_GET_CLASS (backend); + async_context = g_slice_new0 (AsyncContext); async_context->uid = g_strdup (uid); async_context->object_queue = &async_context->result_queue; @@ -1822,11 +2171,26 @@ e_book_backend_get_contact (EBookBackend *backend, 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); + if (class->get_contact_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_thread); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else if (class->get_contact != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_thread_old_style); + book_backend_dispatch_next_operation (backend); + + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -1855,7 +2219,6 @@ e_book_backend_get_contact_finish (EBookBackend *backend, { GSimpleAsyncResult *simple; AsyncContext *async_context; - EContact *contact; g_return_val_if_fail ( g_simple_async_result_is_valid ( @@ -1870,12 +2233,18 @@ e_book_backend_get_contact_finish (EBookBackend *backend, 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); + /* XXX e_data_book_respond_get_contact() stuffs the + * resulting EContact into the object queue. */ + if (async_context->old_style) { + GQueue *queue = async_context->object_queue; + g_warn_if_fail (async_context->contact == NULL); + async_context->contact = g_queue_pop_head (queue); + g_warn_if_fail (g_queue_is_empty (queue)); + } - g_warn_if_fail (g_queue_is_empty (&async_context->result_queue)); + g_return_val_if_fail (E_IS_CONTACT (async_context->contact), NULL); - return contact; + return g_object_ref (async_context->contact); } /** @@ -1938,6 +2307,49 @@ book_backend_get_contact_list_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + AsyncContext *async_context; + + backend = E_BOOK_BACKEND (source_object); + + class = E_BOOK_BACKEND_GET_CLASS (backend); + g_return_if_fail (class->get_contact_list_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->get_contact_list_sync ( + backend, + async_context->query, + async_context->object_queue, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_get_contact_list() */ +static void +book_backend_get_contact_list_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -1962,6 +2374,10 @@ book_backend_get_contact_list_thread (GSimpleAsyncResult *simple, } else { guint32 opid; + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; + opid = book_backend_stash_operation (backend, simple); class->get_contact_list ( @@ -1996,12 +2412,15 @@ e_book_backend_get_contact_list (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; GSimpleAsyncResult *simple; AsyncContext *async_context; g_return_if_fail (E_IS_BOOK_BACKEND (backend)); g_return_if_fail (query != NULL); + class = E_BOOK_BACKEND_GET_CLASS (backend); + async_context = g_slice_new0 (AsyncContext); async_context->query = g_strdup (query); async_context->object_queue = &async_context->result_queue; @@ -2015,11 +2434,26 @@ e_book_backend_get_contact_list (EBookBackend *backend, 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); + if (class->get_contact_list_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_list_thread); + book_backend_dispatch_next_operation (backend); + + } else if (class->get_contact_list != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_list_thread_old_style); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -2067,7 +2501,7 @@ e_book_backend_get_contact_list_finish (EBookBackend *backend, if (g_simple_async_result_propagate_error (simple, error)) return FALSE; - e_queue_transfer (&async_context->result_queue, out_contacts); + e_queue_transfer (async_context->object_queue, out_contacts); return TRUE; } @@ -2132,6 +2566,49 @@ book_backend_get_contact_list_uids_thread (GSimpleAsyncResult *simple, { EBookBackend *backend; EBookBackendClass *class; + 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_sync != 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_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_OPENED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_OPENED)); + + } else { + GError *error = NULL; + + class->get_contact_list_uids_sync ( + backend, + async_context->query, + async_context->string_queue, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + } + + /* XXX Once we get rid of the old-style API we can dispatch + * methods using g_simple_async_result_run_in_thread(), + * which completes the GSimpleAsyncResult for us. */ + g_simple_async_result_complete_in_idle (simple); +} + +/* Helper for e_book_backend_get_contact_list_uids() */ +static void +book_backend_get_contact_list_uids_thread_old_style (GSimpleAsyncResult *simple, + GObject *source_object, + GCancellable *cancellable) +{ + EBookBackend *backend; + EBookBackendClass *class; EDataBook *data_book; AsyncContext *async_context; @@ -2156,6 +2633,10 @@ book_backend_get_contact_list_uids_thread (GSimpleAsyncResult *simple, } else { guint32 opid; + /* This is so the finish function knows which method + * was invoked and can gather results appropriately. */ + async_context->old_style = TRUE; + opid = book_backend_stash_operation (backend, simple); class->get_contact_list_uids ( @@ -2190,12 +2671,15 @@ e_book_backend_get_contact_list_uids (EBookBackend *backend, GAsyncReadyCallback callback, gpointer user_data) { + EBookBackendClass *class; GSimpleAsyncResult *simple; AsyncContext *async_context; g_return_if_fail (E_IS_BOOK_BACKEND (backend)); g_return_if_fail (query != NULL); + class = E_BOOK_BACKEND_GET_CLASS (backend); + async_context = g_slice_new0 (AsyncContext); async_context->query = g_strdup (query); async_context->string_queue = &async_context->result_queue; @@ -2209,11 +2693,26 @@ e_book_backend_get_contact_list_uids (EBookBackend *backend, 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); + if (class->get_contact_list_uids_sync != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_list_uids_thread); + book_backend_dispatch_next_operation (backend); + + } else if (class->get_contact_list_uids != NULL) { + book_backend_push_operation ( + backend, simple, cancellable, FALSE, + book_backend_get_contact_list_uids_thread_old_style); + book_backend_dispatch_next_operation (backend); - book_backend_dispatch_next_operation (backend); + } else { + g_simple_async_result_set_error ( + simple, E_CLIENT_ERROR, + E_CLIENT_ERROR_NOT_SUPPORTED, + "%s", e_client_error_to_string ( + E_CLIENT_ERROR_NOT_SUPPORTED)); + g_simple_async_result_complete_in_idle (simple); + } g_object_unref (simple); } @@ -2261,7 +2760,7 @@ e_book_backend_get_contact_list_uids_finish (EBookBackend *backend, if (g_simple_async_result_propagate_error (simple, error)) return FALSE; - e_queue_transfer (&async_context->result_queue, out_uids); + e_queue_transfer (async_context->string_queue, out_uids); return TRUE; } diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h index 8a6796a4b..d7a3857b7 100644 --- a/addressbook/libedata-book/e-book-backend.h +++ b/addressbook/libedata-book/e-book-backend.h @@ -108,16 +108,53 @@ struct _EBookBackendClass { * dispatch queue, but helps avoid thread-safety issues. */ gboolean use_serial_dispatch_queue; - /* Virtual methods */ gchar * (*get_backend_property) (EBookBackend *backend, const gchar *prop_name); + gboolean (*open_sync) (EBookBackend *backend, + GCancellable *cancellable, + GError **error); + gboolean (*refresh_sync) (EBookBackend *backend, + GCancellable *cancellable, + GError **error); + gboolean (*create_contacts_sync) (EBookBackend *backend, + const gchar * const *vcards, + GQueue *out_contacts, + GCancellable *cancellable, + GError **error); + gboolean (*modify_contacts_sync) (EBookBackend *backend, + const gchar * const *vcards, + GQueue *out_contacts, + GCancellable *cancellable, + GError **error); + gboolean (*remove_contacts_sync) (EBookBackend *backend, + const gchar * const *uids, + GCancellable *cancellable, + GError **error); + EContact * (*get_contact_sync) (EBookBackend *backend, + const gchar *uid, + GCancellable *cancellable, + GError **error); + gboolean (*get_contact_list_sync) + (EBookBackend *backend, + const gchar *query, + GQueue *out_contacts, + GCancellable *cancellable, + GError **error); + gboolean (*get_contact_list_uids_sync) + (EBookBackend *backend, + const gchar *query, + GQueue *out_uids, + GCancellable *cancellable, + GError **error); + + /* These methods are deprecated and will be removed once all + * known subclasses are converted to the new methods above. */ void (*open) (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean only_if_exists); - void (*refresh) (EBookBackend *backend, EDataBook *book, guint32 opid, |
