EDataBook: Watch the system bus for locale notifications
[platform/upstream/evolution-data-server.git] / addressbook / libedata-book / e-data-book.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  * Copyright (C) 2006 OpenedHand Ltd
5  * Copyright (C) 2009 Intel Corporation
6  *
7  * This library is free software; you can redistribute it and/or modify it under
8  * the terms of version 2.1 of the GNU Lesser General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  * Author: Ross Burton <ross@linux.intel.com>
21  */
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <glib/gi18n.h>
26 #include <gio/gio.h>
27
28 /* Private D-Bus classes. */
29 #include <e-dbus-address-book.h>
30
31 #include <libebook-contacts/libebook-contacts.h>
32
33 #include "e-data-book-factory.h"
34 #include "e-data-book.h"
35 #include "e-data-book-view.h"
36 #include "e-book-backend.h"
37 #include "e-book-backend-sexp.h"
38 #include "e-book-backend-factory.h"
39 #include "e-dbus-localed.h"
40
41 #define E_DATA_BOOK_GET_PRIVATE(obj) \
42         (G_TYPE_INSTANCE_GET_PRIVATE \
43         ((obj), E_TYPE_DATA_BOOK, EDataBookPrivate))
44
45 struct _EDataBookPrivate {
46         GDBusConnection *connection;
47         EDBusAddressBook *dbus_interface;
48         EModule *direct_module;
49         EDataBookDirect *direct_book;
50
51         EBookBackend *backend;
52         gchar *object_path;
53
54         GRecMutex pending_ops_lock;
55         GHashTable *pending_ops; /* opid -> OperationData */
56         GHashTable *direct_ops; /* opid to DirectOperationData for still running operations */
57
58         /* Operations are queued while an
59          * open operation is in progress. */
60         GMutex open_lock;
61         guint32 open_opid;
62         GQueue open_queue;
63
64         guint localed_watch_id;
65         EDBusLocale1 *localed_proxy;
66         GCancellable *localed_cancel;
67 };
68
69 enum {
70         PROP_0,
71         PROP_BACKEND,
72         PROP_CONNECTION,
73         PROP_OBJECT_PATH
74 };
75
76 static EOperationPool *ops_pool = NULL;
77
78 typedef enum {
79         OP_OPEN,
80         OP_REFRESH,
81         OP_GET_CONTACT,
82         OP_GET_CONTACTS,
83         OP_GET_CONTACTS_UIDS,
84         OP_ADD_CONTACTS,
85         OP_REMOVE_CONTACTS,
86         OP_MODIFY_CONTACTS,
87         OP_GET_BACKEND_PROPERTY,
88         OP_GET_VIEW,
89         OP_CLOSE
90 } OperationID;
91
92 typedef struct {
93         volatile gint ref_count;
94
95         OperationID op;
96         guint32 id; /* operation id */
97         EDataBook *book; /* book */
98         GCancellable *cancellable;
99         GDBusMethodInvocation *invocation;
100         guint watcher_id;
101
102         union {
103                 /* OP_GET_CONTACT */
104                 gchar *uid;
105                 /* OP_REMOVE_CONTACTS */
106                 GSList *ids;
107                 /* OP_ADD_CONTACTS */
108                 /* OP_MODIFY_CONTACTS */
109                 GSList *vcards;
110                 /* OP_GET_VIEW */
111                 /* OP_GET_CONTACTS */
112                 /* OP_GET_CONTACTS_UIDS */
113                 gchar *query;
114                 /* OP_GET_BACKEND_PROPERTY */
115                 const gchar *prop_name;
116
117                 /* OP_REFRESH */
118                 /* OP_CLOSE */
119         } d;
120 } OperationData;
121
122 typedef struct {
123         GAsyncReadyCallback callback;
124         gpointer            user_data;
125         GCancellable       *cancellable;
126         GSimpleAsyncResult *result;
127
128         gboolean            is_sync_call;
129         gboolean            sync_call_complete;
130         GMutex              sync_result_mutex;
131         GCond               sync_result_condition;
132 } DirectOperationData;
133
134 /* EModule's can never be free'd, however the use count can change
135  * Here we ensure that there is only one ever created by way of
136  * static variables and locks
137  */
138 static GHashTable *modules_table = NULL;
139 G_LOCK_DEFINE (modules_table);
140
141 /* Forward Declarations */
142 static void                 e_data_book_initable_init  (GInitableIface *interface);
143 static DirectOperationData *direct_operation_data_push (EDataBook          *book,
144                                                         OperationID         opid,
145                                                         GAsyncReadyCallback callback,
146                                                         gpointer            user_data,
147                                                         GCancellable       *cancellable,
148                                                         gpointer            source_tag,
149                                                         gboolean            sync_call);
150 static void                 direct_operation_data_free (DirectOperationData *data);
151 static void                 direct_operation_complete  (DirectOperationData *data);
152 static void                 direct_operation_wait      (DirectOperationData *data);
153 static void                 e_data_book_respond_close  (EDataBook *book,
154                                                         guint opid,
155                                                         GError *error);
156
157 G_DEFINE_TYPE_WITH_CODE (
158         EDataBook,
159         e_data_book,
160         G_TYPE_OBJECT,
161         G_IMPLEMENT_INTERFACE (
162                 G_TYPE_INITABLE,
163                 e_data_book_initable_init))
164
165 static EModule *
166 load_module (const gchar *module_path)
167 {
168         EModule *module = NULL;
169
170         G_LOCK (modules_table);
171
172         if (!modules_table)
173                 modules_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
174
175         module = g_hash_table_lookup (modules_table, module_path);
176
177         if (!module) {
178                 module = e_module_new (module_path);
179                 if (!module)
180                         g_warning ("Failed to open EModule at path: %s", module_path);
181                 else
182                         g_hash_table_insert (modules_table, g_strdup (module_path), module);
183         }
184
185         G_UNLOCK (modules_table);
186
187         return module;
188 }
189
190 static DirectOperationData *
191 direct_operation_data_push (EDataBook *book,
192                             OperationID opid,
193                             GAsyncReadyCallback callback,
194                             gpointer user_data,
195                             GCancellable *cancellable,
196                             gpointer source_tag,
197                             gboolean sync_call)
198 {
199         DirectOperationData *data;
200
201         data = g_slice_new (DirectOperationData);
202         data->callback = callback;
203         data->user_data = user_data;
204         data->cancellable = g_object_ref (cancellable);
205         data->result = g_simple_async_result_new (
206                 G_OBJECT (book),
207                 data->callback,
208                 data->user_data,
209                 source_tag);
210         data->is_sync_call = sync_call;
211         data->sync_call_complete = FALSE;
212
213         if (data->is_sync_call) {
214                 g_mutex_init (&data->sync_result_mutex);
215                 g_cond_init (&data->sync_result_condition);
216         }
217
218         g_hash_table_insert (book->priv->direct_ops, GUINT_TO_POINTER (opid), data);
219
220         return data;
221 }
222
223 static void
224 direct_operation_data_free (DirectOperationData *data)
225 {
226         if (data) {
227                 if (data->is_sync_call) {
228                         g_mutex_clear (&data->sync_result_mutex);
229                         g_cond_clear (&data->sync_result_condition);
230                 }
231
232                 g_object_unref (data->result);
233                 g_object_unref (data->cancellable);
234                 g_slice_free (DirectOperationData, data);
235         }
236 }
237
238 static void
239 direct_operation_complete (DirectOperationData *data)
240 {
241         /* If it was a sync call, we have the calling thread
242          * waiting on the sync call condition, it's up to
243          * the sync call to free the data with direct_operation_data_free().
244          *
245          * Otherwise for async calls we need to complete
246          * in the calling thread.
247          */
248         if (data->is_sync_call) {
249                 g_mutex_lock (&data->sync_result_mutex);
250                 data->sync_call_complete = TRUE;
251                 g_cond_signal (&data->sync_result_condition);
252                 g_mutex_unlock (&data->sync_result_mutex);
253         } else {
254                 g_simple_async_result_complete_in_idle (data->result);
255                 direct_operation_data_free (data);
256         }
257 }
258
259 static void
260 direct_operation_wait (DirectOperationData *data)
261 {
262         g_mutex_lock (&data->sync_result_mutex);
263         while (data->sync_call_complete == FALSE)
264                 g_cond_wait (&data->sync_result_condition, &data->sync_result_mutex);
265         g_mutex_unlock (&data->sync_result_mutex);
266 }
267
268 static gchar *
269 construct_bookview_path (void)
270 {
271         static volatile gint counter = 1;
272
273         g_atomic_int_inc (&counter);
274
275         return g_strdup_printf (
276                 "/org/gnome/evolution/dataserver/AddressBookView/%d/%d",
277                 getpid (), counter);
278 }
279
280 static void
281 op_sender_vanished_cb (GDBusConnection *connection,
282                        const gchar *sender,
283                        GCancellable *cancellable)
284 {
285         g_cancellable_cancel (cancellable);
286 }
287
288 static OperationData *
289 op_ref (OperationData *data)
290 {
291         g_return_val_if_fail (data != NULL, data);
292         g_return_val_if_fail (data->ref_count > 0, data);
293
294         g_atomic_int_inc (&data->ref_count);
295
296         return data;
297 }
298
299 static OperationData *
300 op_new (OperationID op,
301         EDataBook *book,
302         GDBusMethodInvocation *invocation)
303 {
304         OperationData *data;
305
306         data = g_slice_new0 (OperationData);
307         data->ref_count = 1;
308         data->op = op;
309         data->id = e_operation_pool_reserve_opid (ops_pool);
310         data->book = g_object_ref (book);
311         data->cancellable = g_cancellable_new ();
312
313         /* This is optional so we can fake client requests. */
314         if (invocation != NULL) {
315                 GDBusConnection *connection;
316                 const gchar *sender;
317
318                 data->invocation = g_object_ref (invocation);
319
320                 connection = e_data_book_get_connection (book);
321                 sender = g_dbus_method_invocation_get_sender (invocation);
322
323                 data->watcher_id = g_bus_watch_name_on_connection (
324                         connection, sender,
325                         G_BUS_NAME_WATCHER_FLAGS_NONE,
326                         (GBusNameAppearedCallback) NULL,
327                         (GBusNameVanishedCallback) op_sender_vanished_cb,
328                         g_object_ref (data->cancellable),
329                         (GDestroyNotify) g_object_unref);
330         }
331
332         g_rec_mutex_lock (&book->priv->pending_ops_lock);
333         g_hash_table_insert (
334                 book->priv->pending_ops,
335                 GUINT_TO_POINTER (data->id),
336                 op_ref (data));
337         g_rec_mutex_unlock (&book->priv->pending_ops_lock);
338
339         return data;
340 }
341
342 static void
343 op_unref (OperationData *data)
344 {
345         g_return_if_fail (data != NULL);
346         g_return_if_fail (data->ref_count > 0);
347
348         if (g_atomic_int_dec_and_test (&data->ref_count)) {
349
350                 switch (data->op) {
351                         case OP_GET_CONTACT:
352                                 g_free (data->d.uid);
353                                 break;
354                         case OP_REMOVE_CONTACTS:
355                                 g_slist_free_full (
356                                         data->d.ids,
357                                         (GDestroyNotify) g_free);
358                                 break;
359                         case OP_ADD_CONTACTS:
360                         case OP_MODIFY_CONTACTS:
361                                 g_slist_free_full (
362                                         data->d.vcards,
363                                         (GDestroyNotify) g_free);
364                                 break;
365                         case OP_GET_VIEW:
366                         case OP_GET_CONTACTS:
367                         case OP_GET_CONTACTS_UIDS:
368                                 g_free (data->d.query);
369                                 break;
370                         default:
371                                 break;
372                 }
373
374                 g_object_unref (data->book);
375                 g_object_unref (data->cancellable);
376
377                 if (data->invocation != NULL)
378                         g_object_unref (data->invocation);
379
380                 if (data->watcher_id > 0)
381                         g_bus_unwatch_name (data->watcher_id);
382
383                 g_slice_free (OperationData, data);
384         }
385 }
386
387 static void
388 op_dispatch (EDataBook *book,
389              OperationData *data)
390 {
391         g_mutex_lock (&book->priv->open_lock);
392
393         /* If an open operation is currently in progress, queue this
394          * operation to be dispatched when the open operation finishes. */
395         if (book->priv->open_opid > 0) {
396                 g_queue_push_tail (&book->priv->open_queue, data);
397         } else {
398                 if (data->op == OP_OPEN)
399                         book->priv->open_opid = data->id;
400                 e_operation_pool_push (ops_pool, data);
401         }
402
403         g_mutex_unlock (&book->priv->open_lock);
404 }
405
406 static OperationData *
407 op_claim (EDataBook *book,
408           guint32 opid,
409           DirectOperationData **direct)
410 {
411         OperationData *data;
412         DirectOperationData *direct_data;
413
414         g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
415
416         e_operation_pool_release_opid (ops_pool, opid);
417
418         g_rec_mutex_lock (&book->priv->pending_ops_lock);
419         data = g_hash_table_lookup (
420                 book->priv->pending_ops,
421                 GUINT_TO_POINTER (opid));
422         if (data != NULL) {
423                 /* Steal the hash table's reference. */
424                 g_hash_table_steal (
425                         book->priv->pending_ops,
426                         GUINT_TO_POINTER (opid));
427         }
428
429         direct_data = g_hash_table_lookup (
430                 book->priv->direct_ops,
431                 GUINT_TO_POINTER (opid));
432         if (direct_data != NULL) {
433                 g_hash_table_steal (
434                         book->priv->direct_ops,
435                         GUINT_TO_POINTER (opid));
436         }
437         g_rec_mutex_unlock (&book->priv->pending_ops_lock);
438
439         g_warn_if_fail (direct_data == NULL || direct != NULL);
440         if (direct)
441                 *direct = direct_data;
442
443         return data;
444 }
445
446 static DirectOperationData *
447 op_complete (EDataBook *book,
448              guint32 opid)
449 {
450         DirectOperationData *direct_data;
451
452         g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
453
454         e_operation_pool_release_opid (ops_pool, opid);
455
456         g_rec_mutex_lock (&book->priv->pending_ops_lock);
457         g_hash_table_remove (
458                 book->priv->pending_ops,
459                 GUINT_TO_POINTER (opid));
460
461         direct_data = g_hash_table_lookup (
462                 book->priv->direct_ops,
463                 GUINT_TO_POINTER (opid));
464         if (direct_data != NULL) {
465                 g_hash_table_steal (
466                         book->priv->direct_ops,
467                         GUINT_TO_POINTER (opid));
468         }
469         g_rec_mutex_unlock (&book->priv->pending_ops_lock);
470
471         return direct_data;
472 }
473
474 static void
475 data_book_convert_to_client_error (GError *error)
476 {
477         g_return_if_fail (error != NULL);
478
479         if (error->domain != E_DATA_BOOK_ERROR)
480                 return;
481
482         switch (error->code) {
483                 case E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE:
484                         error->domain = E_CLIENT_ERROR;
485                         error->code = E_CLIENT_ERROR_REPOSITORY_OFFLINE;
486                         break;
487
488                 case E_DATA_BOOK_STATUS_PERMISSION_DENIED:
489                         error->domain = E_CLIENT_ERROR;
490                         error->code = E_CLIENT_ERROR_PERMISSION_DENIED;
491                         break;
492
493                 case E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND:
494                         error->domain = E_BOOK_CLIENT_ERROR;
495                         error->code = E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND;
496                         break;
497
498                 case E_DATA_BOOK_STATUS_CONTACTID_ALREADY_EXISTS:
499                         error->domain = E_BOOK_CLIENT_ERROR;
500                         error->code = E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS;
501                         break;
502
503                 case E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED:
504                         error->domain = E_CLIENT_ERROR;
505                         error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
506                         break;
507
508                 case E_DATA_BOOK_STATUS_UNSUPPORTED_AUTHENTICATION_METHOD:
509                         error->domain = E_CLIENT_ERROR;
510                         error->code = E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD;
511                         break;
512
513                 case E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE:
514                         error->domain = E_CLIENT_ERROR;
515                         error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
516                         break;
517
518                 case E_DATA_BOOK_STATUS_NO_SUCH_BOOK:
519                         error->domain = E_BOOK_CLIENT_ERROR;
520                         error->code = E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK;
521                         break;
522
523                 case E_DATA_BOOK_STATUS_BOOK_REMOVED:
524                         error->domain = E_BOOK_CLIENT_ERROR;
525                         error->code = E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE;
526                         break;
527
528                 case E_DATA_BOOK_STATUS_OFFLINE_UNAVAILABLE:
529                         error->domain = E_CLIENT_ERROR;
530                         error->code = E_CLIENT_ERROR_OFFLINE_UNAVAILABLE;
531                         break;
532
533                 case E_DATA_BOOK_STATUS_SEARCH_SIZE_LIMIT_EXCEEDED:
534                         error->domain = E_CLIENT_ERROR;
535                         error->code = E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED;
536                         break;
537
538                 case E_DATA_BOOK_STATUS_SEARCH_TIME_LIMIT_EXCEEDED:
539                         error->domain = E_CLIENT_ERROR;
540                         error->code = E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED;
541                         break;
542
543                 case E_DATA_BOOK_STATUS_INVALID_QUERY:
544                         error->domain = E_CLIENT_ERROR;
545                         error->code = E_CLIENT_ERROR_INVALID_QUERY;
546                         break;
547
548                 case E_DATA_BOOK_STATUS_QUERY_REFUSED:
549                         error->domain = E_CLIENT_ERROR;
550                         error->code = E_CLIENT_ERROR_QUERY_REFUSED;
551                         break;
552
553                 case E_DATA_BOOK_STATUS_COULD_NOT_CANCEL:
554                         error->domain = E_CLIENT_ERROR;
555                         error->code = E_CLIENT_ERROR_COULD_NOT_CANCEL;
556                         break;
557
558                 case E_DATA_BOOK_STATUS_NO_SPACE:
559                         error->domain = E_BOOK_CLIENT_ERROR;
560                         error->code = E_BOOK_CLIENT_ERROR_NO_SPACE;
561                         break;
562
563                 case E_DATA_BOOK_STATUS_INVALID_ARG:
564                         error->domain = E_CLIENT_ERROR;
565                         error->code = E_CLIENT_ERROR_INVALID_ARG;
566                         break;
567
568                 case E_DATA_BOOK_STATUS_NOT_SUPPORTED:
569                         error->domain = E_CLIENT_ERROR;
570                         error->code = E_CLIENT_ERROR_NOT_SUPPORTED;
571                         break;
572
573                 case E_DATA_BOOK_STATUS_NOT_OPENED:
574                         error->domain = E_CLIENT_ERROR;
575                         error->code = E_CLIENT_ERROR_NOT_OPENED;
576                         break;
577
578                 case E_DATA_BOOK_STATUS_OUT_OF_SYNC:
579                         error->domain = E_CLIENT_ERROR;
580                         error->code = E_CLIENT_ERROR_OUT_OF_SYNC;
581                         break;
582
583                 case E_DATA_BOOK_STATUS_UNSUPPORTED_FIELD:
584                 case E_DATA_BOOK_STATUS_OTHER_ERROR:
585                 case E_DATA_BOOK_STATUS_INVALID_SERVER_VERSION:
586                         error->domain = E_CLIENT_ERROR;
587                         error->code = E_CLIENT_ERROR_OTHER_ERROR;
588                         break;
589
590                 default:
591                         g_warn_if_reached ();
592         }
593 }
594
595 static void
596 operation_thread (gpointer data,
597                   gpointer user_data)
598 {
599         OperationData *op = data;
600         EBookBackend *backend;
601         GHashTableIter iter;
602         gpointer value;
603
604         backend = e_data_book_get_backend (op->book);
605
606         switch (op->op) {
607         case OP_OPEN:
608                 e_book_backend_open (
609                         backend, op->book, op->id,
610                         op->cancellable, FALSE);
611                 break;
612
613         case OP_ADD_CONTACTS:
614                 e_book_backend_create_contacts (
615                         backend, op->book, op->id,
616                         op->cancellable, op->d.vcards);
617                 break;
618
619         case OP_GET_CONTACT:
620                 e_book_backend_get_contact (
621                         backend, op->book, op->id,
622                         op->cancellable, op->d.uid);
623                 break;
624
625         case OP_GET_CONTACTS:
626                 e_book_backend_get_contact_list (
627                         backend, op->book, op->id,
628                         op->cancellable, op->d.query);
629                 break;
630
631         case OP_GET_CONTACTS_UIDS:
632                 e_book_backend_get_contact_list_uids (
633                         backend, op->book, op->id,
634                         op->cancellable, op->d.query);
635                 break;
636
637         case OP_MODIFY_CONTACTS:
638                 e_book_backend_modify_contacts (
639                         backend, op->book, op->id,
640                         op->cancellable, op->d.vcards);
641                 break;
642
643         case OP_REMOVE_CONTACTS:
644                 e_book_backend_remove_contacts (
645                         backend, op->book, op->id,
646                         op->cancellable, op->d.ids);
647                 break;
648
649         case OP_REFRESH:
650                 e_book_backend_refresh (
651                         backend, op->book, op->id, op->cancellable);
652                 break;
653
654         case OP_GET_BACKEND_PROPERTY:
655                 e_book_backend_get_backend_property (
656                         backend, op->book, op->id,
657                         op->cancellable, op->d.prop_name);
658                 break;
659
660         case OP_GET_VIEW:
661                 if (op->d.query) {
662                         EDataBookView *view;
663                         EBookBackendSExp *card_sexp;
664                         GDBusConnection *connection;
665                         gchar *object_path;
666                         GError *error = NULL;
667
668                         card_sexp = e_book_backend_sexp_new (op->d.query);
669                         if (!card_sexp) {
670                                 g_dbus_method_invocation_return_error_literal (
671                                         op->invocation,
672                                         E_CLIENT_ERROR,
673                                         E_CLIENT_ERROR_INVALID_QUERY,
674                                         _("Invalid query"));
675
676                                 op_complete (op->book, op->id);
677                                 break;
678                         }
679
680                         object_path = construct_bookview_path ();
681                         connection = e_data_book_get_connection (op->book);
682
683                         view = e_data_book_view_new (
684                                 op->book, card_sexp,
685                                 connection, object_path, &error);
686
687                         g_object_unref (card_sexp);
688
689                         /* Sanity check. */
690                         g_return_if_fail (
691                                 ((view != NULL) && (error == NULL)) ||
692                                 ((view == NULL) && (error != NULL)));
693
694                         if (error != NULL) {
695                                 /* Translators: This is prefix to a detailed error message */
696                                 g_prefix_error (&error, "%s", _("Invalid query: "));
697                                 data_book_convert_to_client_error (error);
698                                 g_dbus_method_invocation_take_error (
699                                         op->invocation, error);
700
701                                 op_complete (op->book, op->id);
702                                 g_free (object_path);
703                                 break;
704                         }
705
706                         e_book_backend_add_view (backend, view);
707
708                         e_dbus_address_book_complete_get_view (
709                                 op->book->priv->dbus_interface,
710                                 op->invocation,
711                                 object_path);
712
713                         op_complete (op->book, op->id);
714                         g_free (object_path);
715                 }
716                 break;
717
718         case OP_CLOSE:
719                 /* close just cancels all pending ops and frees data book */
720                 e_book_backend_remove_client (backend, op->book);
721
722                 g_rec_mutex_lock (&op->book->priv->pending_ops_lock);
723
724                 g_hash_table_iter_init (&iter, op->book->priv->pending_ops);
725                 while (g_hash_table_iter_next (&iter, NULL, &value)) {
726                         OperationData *cancel_op = value;
727                         g_cancellable_cancel (cancel_op->cancellable);
728                 }
729
730                 g_rec_mutex_unlock (&op->book->priv->pending_ops_lock);
731
732                 if (op->book->priv->dbus_interface)
733                         e_dbus_address_book_complete_close (
734                                 op->book->priv->dbus_interface,
735                                 op->invocation);
736
737                 /* Let direct calls return, notify the direct callers that it's closed */
738                 e_data_book_respond_close (op->book, op->id, NULL);
739                 break;
740         }
741
742         op_unref (op);
743 }
744
745 static OperationData *
746 op_direct_new (OperationID op,
747                EDataBook *book,
748                GCancellable *cancellable,
749                GAsyncReadyCallback callback,
750                gpointer user_data,
751                gpointer source_tag,
752                gboolean sync_call,
753                DirectOperationData **ret_data)
754 {
755         OperationData *data;
756         DirectOperationData *direct_data;
757
758         data = g_slice_new0 (OperationData);
759         data->ref_count = 1;
760         data->op = op;
761         data->book = g_object_ref (book);
762         data->id = e_operation_pool_reserve_opid (ops_pool);
763
764         if (cancellable)
765                 data->cancellable = g_object_ref (cancellable);
766         else
767                 data->cancellable = g_cancellable_new ();
768
769         g_rec_mutex_lock (&book->priv->pending_ops_lock);
770         g_hash_table_insert (
771                 book->priv->pending_ops,
772                 GUINT_TO_POINTER (data->id),
773                 op_ref (data));
774         direct_data = direct_operation_data_push (
775                 book, data->id, callback, user_data,
776                 data->cancellable, source_tag, sync_call);
777         g_rec_mutex_unlock (&book->priv->pending_ops_lock);
778
779         if (ret_data)
780                 *ret_data = direct_data;
781
782         return data;
783 }
784
785 /**
786  * e_data_book_status_to_string:
787  *
788  * Since: 2.32
789  **/
790 const gchar *
791 e_data_book_status_to_string (EDataBookStatus status)
792 {
793         gint i;
794         static struct _statuses {
795                 EDataBookStatus status;
796                 const gchar *msg;
797         } statuses[] = {
798                 { E_DATA_BOOK_STATUS_SUCCESS,                           N_("Success") },
799                 { E_DATA_BOOK_STATUS_BUSY,                              N_("Backend is busy") },
800                 { E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,                N_("Repository offline") },
801                 { E_DATA_BOOK_STATUS_PERMISSION_DENIED,                 N_("Permission denied") },
802                 { E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,                 N_("Contact not found") },
803                 { E_DATA_BOOK_STATUS_CONTACTID_ALREADY_EXISTS,          N_("Contact ID already exists") },
804                 { E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED,             N_("Authentication Failed") },
805                 { E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED,           N_("Authentication Required") },
806                 { E_DATA_BOOK_STATUS_UNSUPPORTED_FIELD,                 N_("Unsupported field") },
807                 { E_DATA_BOOK_STATUS_UNSUPPORTED_AUTHENTICATION_METHOD, N_("Unsupported authentication method") },
808                 { E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE,                 N_("TLS not available") },
809                 { E_DATA_BOOK_STATUS_NO_SUCH_BOOK,                      N_("Address book does not exist") },
810                 { E_DATA_BOOK_STATUS_BOOK_REMOVED,                      N_("Book removed") },
811                 { E_DATA_BOOK_STATUS_OFFLINE_UNAVAILABLE,               N_("Not available in offline mode") },
812                 { E_DATA_BOOK_STATUS_SEARCH_SIZE_LIMIT_EXCEEDED,        N_("Search size limit exceeded") },
813                 { E_DATA_BOOK_STATUS_SEARCH_TIME_LIMIT_EXCEEDED,        N_("Search time limit exceeded") },
814                 { E_DATA_BOOK_STATUS_INVALID_QUERY,                     N_("Invalid query") },
815                 { E_DATA_BOOK_STATUS_QUERY_REFUSED,                     N_("Query refused") },
816                 { E_DATA_BOOK_STATUS_COULD_NOT_CANCEL,                  N_("Could not cancel") },
817                 /* { E_DATA_BOOK_STATUS_OTHER_ERROR,                    N_("Other error") }, */
818                 { E_DATA_BOOK_STATUS_INVALID_SERVER_VERSION,            N_("Invalid server version") },
819                 { E_DATA_BOOK_STATUS_NO_SPACE,                          N_("No space") },
820                 { E_DATA_BOOK_STATUS_INVALID_ARG,                       N_("Invalid argument") },
821                 /* Translators: The string for NOT_SUPPORTED error */
822                 { E_DATA_BOOK_STATUS_NOT_SUPPORTED,                     N_("Not supported") },
823                 { E_DATA_BOOK_STATUS_NOT_OPENED,                        N_("Backend is not opened yet") },
824                 { E_DATA_BOOK_STATUS_OUT_OF_SYNC,                       N_("Object is out of sync") }
825         };
826
827         for (i = 0; i < G_N_ELEMENTS (statuses); i++) {
828                 if (statuses[i].status == status)
829                         return _(statuses[i].msg);
830         }
831
832         return _("Other error");
833 }
834
835 /* Create the EDataBook error quark */
836 GQuark
837 e_data_book_error_quark (void)
838 {
839         #define ERR_PREFIX "org.gnome.evolution.dataserver.AddressBook."
840
841         static const GDBusErrorEntry entries[] = {
842                 { E_DATA_BOOK_STATUS_SUCCESS,                           ERR_PREFIX "Success" },
843                 { E_DATA_BOOK_STATUS_BUSY,                              ERR_PREFIX "Busy" },
844                 { E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,                ERR_PREFIX "RepositoryOffline" },
845                 { E_DATA_BOOK_STATUS_PERMISSION_DENIED,                 ERR_PREFIX "PermissionDenied" },
846                 { E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,                 ERR_PREFIX "ContactNotFound" },
847                 { E_DATA_BOOK_STATUS_CONTACTID_ALREADY_EXISTS,          ERR_PREFIX "ContactIDAlreadyExists" },
848                 { E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED,             ERR_PREFIX "AuthenticationFailed" },
849                 { E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED,           ERR_PREFIX "AuthenticationRequired" },
850                 { E_DATA_BOOK_STATUS_UNSUPPORTED_FIELD,                 ERR_PREFIX "UnsupportedField" },
851                 { E_DATA_BOOK_STATUS_UNSUPPORTED_AUTHENTICATION_METHOD, ERR_PREFIX "UnsupportedAuthenticationMethod" },
852                 { E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE,                 ERR_PREFIX "TLSNotAvailable" },
853                 { E_DATA_BOOK_STATUS_NO_SUCH_BOOK,                      ERR_PREFIX "NoSuchBook" },
854                 { E_DATA_BOOK_STATUS_BOOK_REMOVED,                      ERR_PREFIX "BookRemoved" },
855                 { E_DATA_BOOK_STATUS_OFFLINE_UNAVAILABLE,               ERR_PREFIX "OfflineUnavailable" },
856                 { E_DATA_BOOK_STATUS_SEARCH_SIZE_LIMIT_EXCEEDED,        ERR_PREFIX "SearchSizeLimitExceeded" },
857                 { E_DATA_BOOK_STATUS_SEARCH_TIME_LIMIT_EXCEEDED,        ERR_PREFIX "SearchTimeLimitExceeded" },
858                 { E_DATA_BOOK_STATUS_INVALID_QUERY,                     ERR_PREFIX "InvalidQuery" },
859                 { E_DATA_BOOK_STATUS_QUERY_REFUSED,                     ERR_PREFIX "QueryRefused" },
860                 { E_DATA_BOOK_STATUS_COULD_NOT_CANCEL,                  ERR_PREFIX "CouldNotCancel" },
861                 { E_DATA_BOOK_STATUS_OTHER_ERROR,                       ERR_PREFIX "OtherError" },
862                 { E_DATA_BOOK_STATUS_INVALID_SERVER_VERSION,            ERR_PREFIX "InvalidServerVersion" },
863                 { E_DATA_BOOK_STATUS_NO_SPACE,                          ERR_PREFIX "NoSpace" },
864                 { E_DATA_BOOK_STATUS_INVALID_ARG,                       ERR_PREFIX "InvalidArg" },
865                 { E_DATA_BOOK_STATUS_NOT_SUPPORTED,                     ERR_PREFIX "NotSupported" },
866                 { E_DATA_BOOK_STATUS_NOT_OPENED,                        ERR_PREFIX "NotOpened" },
867                 { E_DATA_BOOK_STATUS_OUT_OF_SYNC,                       ERR_PREFIX "OutOfSync" }
868         };
869
870         #undef ERR_PREFIX
871
872         static volatile gsize quark_volatile = 0;
873
874         g_dbus_error_register_error_domain ("e-data-book-error", &quark_volatile, entries, G_N_ELEMENTS (entries));
875
876         return (GQuark) quark_volatile;
877 }
878
879 /**
880  * e_data_book_create_error:
881  *
882  * Since: 2.32
883  **/
884 GError *
885 e_data_book_create_error (EDataBookStatus status,
886                           const gchar *custom_msg)
887 {
888         if (status == E_DATA_BOOK_STATUS_SUCCESS)
889                 return NULL;
890
891         return g_error_new_literal (E_DATA_BOOK_ERROR, status, custom_msg ? custom_msg : e_data_book_status_to_string (status));
892 }
893
894 /**
895  * e_data_book_create_error_fmt:
896  *
897  * Since: 2.32
898  **/
899 GError *
900 e_data_book_create_error_fmt (EDataBookStatus status,
901                               const gchar *custom_msg_fmt,
902                               ...)
903 {
904         GError *error;
905         gchar *custom_msg;
906         va_list ap;
907
908         if (!custom_msg_fmt)
909                 return e_data_book_create_error (status, NULL);
910
911         va_start (ap, custom_msg_fmt);
912         custom_msg = g_strdup_vprintf (custom_msg_fmt, ap);
913         va_end (ap);
914
915         error = e_data_book_create_error (status, custom_msg);
916
917         g_free (custom_msg);
918
919         return error;
920 }
921
922 /**
923  * e_data_book_string_slist_to_comma_string:
924  *
925  * Takes a list of strings and converts it to a comma-separated string of
926  * values; free returned pointer with g_free()
927  *
928  * Since: 3.2
929  **/
930 gchar *
931 e_data_book_string_slist_to_comma_string (const GSList *strings)
932 {
933         GString *tmp;
934         gchar *res;
935         const GSList *l;
936
937         tmp = g_string_new ("");
938         for (l = strings; l != NULL; l = l->next) {
939                 const gchar *str = l->data;
940
941                 if (!str)
942                         continue;
943
944                 if (strchr (str, ',')) {
945                         g_warning ("%s: String cannot contain comma; skipping value '%s'\n", G_STRFUNC, str);
946                         continue;
947                 }
948
949                 if (tmp->len)
950                         g_string_append_c (tmp, ',');
951                 g_string_append (tmp, str);
952         }
953
954         res = e_util_utf8_make_valid (tmp->str);
955
956         g_string_free (tmp, TRUE);
957
958         return res;
959 }
960
961 static gboolean
962 data_book_handle_open_cb (EDBusAddressBook *interface,
963                           GDBusMethodInvocation *invocation,
964                           EDataBook *book)
965 {
966         OperationData *op;
967
968         op = op_new (OP_OPEN, book, invocation);
969
970         op_dispatch (book, op);
971
972         return TRUE;
973 }
974
975 static gboolean
976 data_book_handle_refresh_cb (EDBusAddressBook *interface,
977                              GDBusMethodInvocation *invocation,
978                              EDataBook *book)
979 {
980         OperationData *op;
981
982         op = op_new (OP_REFRESH, book, invocation);
983
984         op_dispatch (book, op);
985
986         return TRUE;
987 }
988
989 static gboolean
990 data_book_handle_get_contact_cb (EDBusAddressBook *interface,
991                                  GDBusMethodInvocation *invocation,
992                                  const gchar *in_uid,
993                                  EDataBook *book)
994 {
995         OperationData *op;
996
997         op = op_new (OP_GET_CONTACT, book, invocation);
998         op->d.uid = g_strdup (in_uid);
999
1000         op_dispatch (book, op);
1001
1002         return TRUE;
1003 }
1004
1005 static gboolean
1006 data_book_handle_get_contact_list_cb (EDBusAddressBook *interface,
1007                                       GDBusMethodInvocation *invocation,
1008                                       const gchar *in_query,
1009                                       EDataBook *book)
1010 {
1011         OperationData *op;
1012
1013         op = op_new (OP_GET_CONTACTS, book, invocation);
1014         op->d.query = g_strdup (in_query);
1015
1016         op_dispatch (book, op);
1017
1018         return TRUE;
1019 }
1020
1021 static gboolean
1022 data_book_handle_get_contact_list_uids_cb (EDBusAddressBook *interface,
1023                                            GDBusMethodInvocation *invocation,
1024                                            const gchar *in_query,
1025                                            EDataBook *book)
1026 {
1027         OperationData *op;
1028
1029         op = op_new (OP_GET_CONTACTS_UIDS, book, invocation);
1030         op->d.query = g_strdup (in_query);
1031
1032         op_dispatch (book, op);
1033
1034         return TRUE;
1035 }
1036
1037 static gboolean
1038 data_book_handle_create_contacts_cb (EDBusAddressBook *interface,
1039                                      GDBusMethodInvocation *invocation,
1040                                      const gchar * const *in_vcards,
1041                                      EDataBook *book)
1042 {
1043         OperationData *op;
1044
1045         op = op_new (OP_ADD_CONTACTS, book, invocation);
1046         op->d.vcards = e_util_strv_to_slist (in_vcards);
1047
1048         op_dispatch (book, op);
1049
1050         return TRUE;
1051 }
1052
1053 static gboolean
1054 data_book_handle_modify_contacts_cb (EDBusAddressBook *interface,
1055                                      GDBusMethodInvocation *invocation,
1056                                      const gchar * const *in_vcards,
1057                                      EDataBook *book)
1058 {
1059         OperationData *op;
1060
1061         op = op_new (OP_MODIFY_CONTACTS, book, invocation);
1062         op->d.vcards = e_util_strv_to_slist (in_vcards);
1063
1064         op_dispatch (book, op);
1065
1066         return TRUE;
1067 }
1068
1069 static gboolean
1070 data_book_handle_remove_contacts_cb (EDBusAddressBook *interface,
1071                                      GDBusMethodInvocation *invocation,
1072                                      const gchar * const *in_uids,
1073                                      EDataBook *book)
1074 {
1075         OperationData *op;
1076
1077         op = op_new (OP_REMOVE_CONTACTS, book, invocation);
1078
1079         /* Allow an empty array to be removed */
1080         for (; in_uids && *in_uids; in_uids++) {
1081                 op->d.ids = g_slist_prepend (op->d.ids, g_strdup (*in_uids));
1082         }
1083
1084         op_dispatch (book, op);
1085
1086         return TRUE;
1087 }
1088
1089 static gboolean
1090 data_book_handle_get_view_cb (EDBusAddressBook *interface,
1091                               GDBusMethodInvocation *invocation,
1092                               const gchar *in_query,
1093                               EDataBook *book)
1094 {
1095         OperationData *op;
1096
1097         op = op_new (OP_GET_VIEW, book, invocation);
1098         op->d.query = g_strdup (in_query);
1099
1100         /* This operation is never queued. */
1101         e_operation_pool_push (ops_pool, op);
1102
1103         return TRUE;
1104 }
1105
1106 static gboolean
1107 data_book_handle_close_cb (EDBusAddressBook *interface,
1108                            GDBusMethodInvocation *invocation,
1109                            EDataBook *book)
1110 {
1111         OperationData *op;
1112
1113         op = op_new (OP_CLOSE, book, invocation);
1114         /* unref here makes sure the book is freed in a separate thread */
1115         g_object_unref (book);
1116
1117         /* This operation is never queued. */
1118         e_operation_pool_push (ops_pool, op);
1119
1120         return TRUE;
1121 }
1122
1123 void
1124 e_data_book_respond_open (EDataBook *book,
1125                           guint opid,
1126                           GError *error)
1127 {
1128         DirectOperationData *direct = NULL;
1129         OperationData *data;
1130         GError *copy = NULL;
1131
1132         g_return_if_fail (E_IS_DATA_BOOK (book));
1133
1134         data = op_claim (book, opid, &direct);
1135         g_return_if_fail (data != NULL);
1136
1137         /* Translators: This is prefix to a detailed error message */
1138         g_prefix_error (&error, "%s", _("Cannot open book: "));
1139
1140         /* This function is deprecated, but it's the only way to
1141          * set EBookBackend's internal 'opened' flag.  We should
1142          * be the only ones calling this. */
1143         if (error != NULL) {
1144                 data_book_convert_to_client_error (error);
1145                 copy = g_error_copy (error);
1146         }
1147         e_book_backend_notify_opened (book->priv->backend, copy);
1148
1149         if (direct) {
1150                 gboolean result = FALSE;
1151
1152                 if (error) {
1153                         g_simple_async_result_set_error (
1154                                 direct->result,
1155                                 error->domain,
1156                                 error->code,
1157                                 "%s", error->message);
1158                         g_error_free (error);
1159                 } else {
1160                         g_simple_async_result_set_check_cancellable (
1161                                 direct->result,
1162                                 direct->cancellable);
1163
1164                         if (!g_cancellable_is_cancelled (direct->cancellable))
1165                                 result = TRUE;
1166                 }
1167
1168                 g_simple_async_result_set_op_res_gboolean (direct->result, result);
1169
1170                 /* Deliver the result to the caller */
1171                 direct_operation_complete (direct);
1172         } else if (error == NULL) {
1173                 e_dbus_address_book_complete_open (
1174                         book->priv->dbus_interface,
1175                         data->invocation);
1176         } else {
1177                 g_dbus_method_invocation_take_error (
1178                         data->invocation, error);
1179         }
1180
1181         op_unref (data);
1182
1183         /* Dispatch any pending operations. */
1184         g_mutex_lock (&book->priv->open_lock);
1185
1186         if (opid == book->priv->open_opid) {
1187                 OperationData *op;
1188
1189                 book->priv->open_opid = 0;
1190
1191                 while (!g_queue_is_empty (&book->priv->open_queue)) {
1192                         op = g_queue_pop_head (&book->priv->open_queue);
1193                         e_operation_pool_push (ops_pool, op);
1194                 }
1195         }
1196
1197         g_mutex_unlock (&book->priv->open_lock);
1198 }
1199
1200 /**
1201  * e_data_book_respond_refresh:
1202  * @book: An addressbook client interface.
1203  * @error: Operation error, if any, automatically freed if passed it.
1204  *
1205  * Notifies listeners of the completion of the refresh method call.
1206  *
1207  * Since: 3.2
1208  */
1209 void
1210 e_data_book_respond_refresh (EDataBook *book,
1211                              guint32 opid,
1212                              GError *error)
1213 {
1214         OperationData *data;
1215
1216         g_return_if_fail (E_IS_DATA_BOOK (book));
1217
1218         data = op_claim (book, opid, NULL);
1219         g_return_if_fail (data != NULL);
1220
1221         /* Translators: This is prefix to a detailed error message */
1222         g_prefix_error (&error, "%s", _("Cannot refresh address book: "));
1223
1224         if (error == NULL) {
1225                 e_dbus_address_book_complete_refresh (
1226                         book->priv->dbus_interface,
1227                         data->invocation);
1228         } else {
1229                 data_book_convert_to_client_error (error);
1230                 g_dbus_method_invocation_take_error (
1231                         data->invocation, error);
1232         }
1233
1234         op_unref (data);
1235 }
1236
1237 /**
1238  * e_data_book_respond_get_backend_property:
1239  *
1240  * FIXME: Document me.
1241  *
1242  * Since: 3.2
1243  **/
1244 void
1245 e_data_book_respond_get_backend_property (EDataBook *book,
1246                                           guint32 opid,
1247                                           GError *error,
1248                                           const gchar *prop_value)
1249 {
1250         OperationData *data;
1251
1252         g_return_if_fail (E_IS_DATA_BOOK (book));
1253
1254         data = op_claim (book, opid, NULL);
1255         g_return_if_fail (data != NULL);
1256
1257         if (error == NULL) {
1258                 e_data_book_report_backend_property_changed (
1259                         book, data->d.prop_name, prop_value);
1260         } else {
1261                 /* This should never happen, since all backend property
1262                  * requests now originate from our constructed() method. */
1263                 g_warning ("%s: %s", G_STRFUNC, error->message);
1264                 g_error_free (error);
1265         }
1266
1267         op_unref (data);
1268 }
1269
1270 /**
1271  * e_data_book_respond_set_backend_property:
1272  *
1273  * FIXME: Document me.
1274  *
1275  * Since: 3.2
1276  *
1277  * Deprecated: 3.8: This function no longer does anything.
1278  **/
1279 void
1280 e_data_book_respond_set_backend_property (EDataBook *book,
1281                                           guint32 opid,
1282                                           GError *error)
1283 {
1284         /* Do nothing. */
1285 }
1286
1287 void
1288 e_data_book_respond_get_contact (EDataBook *book,
1289                                  guint32 opid,
1290                                  GError *error,
1291                                  const gchar *vcard)
1292 {
1293         DirectOperationData *direct = NULL;
1294         OperationData *data;
1295
1296         g_return_if_fail (E_IS_DATA_BOOK (book));
1297
1298         data = op_claim (book, opid, &direct);
1299         g_return_if_fail (data != NULL);
1300
1301         if (error) {
1302                 /* Translators: This is prefix to a detailed error message */
1303                 g_prefix_error (&error, "%s", _("Cannot get contact: "));
1304                 data_book_convert_to_client_error (error);
1305         }
1306
1307         if (direct) {
1308
1309                 if (error) {
1310                         g_simple_async_result_set_error (
1311                                 direct->result,
1312                                 error->domain,
1313                                 error->code,
1314                                 "%s", error->message);
1315                         g_error_free (error);
1316                 } else {
1317                         g_simple_async_result_set_check_cancellable (
1318                                 direct->result,
1319                                 direct->cancellable);
1320
1321                         if (!g_cancellable_is_cancelled (direct->cancellable)) {
1322                                 EContact *contact;
1323
1324                                 contact = e_contact_new_from_vcard (vcard);
1325
1326                                 /* Give it an EContact for the return value */
1327                                 g_simple_async_result_set_op_res_gpointer (direct->result, contact, g_object_unref);
1328                         }
1329                 }
1330
1331                 /* Deliver the result to the caller */
1332                 direct_operation_complete (direct);
1333
1334         } else if (error == NULL) {
1335                 gchar *utf8_vcard;
1336
1337                 utf8_vcard = e_util_utf8_make_valid (vcard);
1338
1339                 e_dbus_address_book_complete_get_contact (
1340                         book->priv->dbus_interface,
1341                         data->invocation,
1342                         utf8_vcard);
1343
1344                 g_free (utf8_vcard);
1345         } else {
1346                 g_dbus_method_invocation_take_error (
1347                         data->invocation, error);
1348         }
1349
1350         op_unref (data);
1351 }
1352
1353 void
1354 e_data_book_respond_get_contact_list (EDataBook *book,
1355                                       guint32 opid,
1356                                       GError *error,
1357                                       const GSList *cards)
1358 {
1359         DirectOperationData *direct = NULL;
1360         OperationData *data;
1361
1362         g_return_if_fail (E_IS_DATA_BOOK (book));
1363
1364         data = op_claim (book, opid, &direct);
1365         g_return_if_fail (data != NULL);
1366
1367         if (error) {
1368                 /* Translators: This is prefix to a detailed error message */
1369                 g_prefix_error (&error, "%s", _("Cannot get contact list: "));
1370                 data_book_convert_to_client_error (error);
1371         }
1372
1373         if (direct) {
1374
1375                 if (error) {
1376                         g_simple_async_result_set_error (
1377                                 direct->result,
1378                                 error->domain,
1379                                 error->code,
1380                                 "%s", error->message);
1381                         g_error_free (error);
1382                 } else {
1383                         g_simple_async_result_set_check_cancellable (
1384                                 direct->result,
1385                                 direct->cancellable);
1386
1387                         if (!g_cancellable_is_cancelled (direct->cancellable)) {
1388                                 EContact *contact;
1389                                 const GSList *l;
1390                                 GSList *contacts = NULL;
1391
1392                                 for (l = cards; l; l = l->next) {
1393                                         const gchar *vcard = l->data;
1394
1395                                         contact = e_contact_new_from_vcard (vcard);
1396                                         contacts = g_slist_prepend (contacts, contact);
1397                                 }
1398
1399                                 contacts = g_slist_reverse (contacts);
1400
1401                                 /* Give it an EContact for the return value */
1402                                 g_simple_async_result_set_op_res_gpointer (
1403                                         direct->result, contacts,
1404                                         (GDestroyNotify) e_util_free_object_slist);
1405                         }
1406                 }
1407
1408                 /* Deliver the result to the caller */
1409                 direct_operation_complete (direct);
1410
1411         } else if (error == NULL) {
1412                 gchar **strv;
1413                 guint length;
1414                 gint ii = 0;
1415
1416                 length = g_slist_length ((GSList *) cards);
1417                 strv = g_new0 (gchar *, length + 1);
1418
1419                 while (cards != NULL) {
1420                         strv[ii++] = e_util_utf8_make_valid (cards->data);
1421                         cards = g_slist_next ((GSList *) cards);
1422                 }
1423
1424                 e_dbus_address_book_complete_get_contact_list (
1425                         book->priv->dbus_interface,
1426                         data->invocation,
1427                         (const gchar * const *) strv);
1428
1429                 g_strfreev (strv);
1430         } else {
1431                 g_dbus_method_invocation_take_error (
1432                         data->invocation, error);
1433         }
1434
1435         op_unref (data);
1436 }
1437
1438 /**
1439  * e_data_book_respond_get_contact_list_uids:
1440  *
1441  * FIXME: Document me.
1442  *
1443  * Since: 3.2
1444  **/
1445 void
1446 e_data_book_respond_get_contact_list_uids (EDataBook *book,
1447                                            guint32 opid,
1448                                            GError *error,
1449                                            const GSList *uids)
1450 {
1451         DirectOperationData *direct = NULL;
1452         OperationData *data;
1453
1454         g_return_if_fail (E_IS_DATA_BOOK (book));
1455
1456         data = op_claim (book, opid, &direct);
1457         g_return_if_fail (data != NULL);
1458
1459         if (error) {
1460                 /* Translators: This is prefix to a detailed error message */
1461                 g_prefix_error (&error, "%s", _("Cannot get contact list uids: "));
1462                 data_book_convert_to_client_error (error);
1463         }
1464
1465         if (direct) {
1466
1467                 if (error) {
1468                         g_simple_async_result_set_error (
1469                                 direct->result,
1470                                 error->domain,
1471                                 error->code,
1472                                 "%s", error->message);
1473                         g_error_free (error);
1474                 } else {
1475                         g_simple_async_result_set_check_cancellable (
1476                                 direct->result,
1477                                 direct->cancellable);
1478
1479                         if (!g_cancellable_is_cancelled (direct->cancellable)) {
1480                                 GSList *ret_uids = NULL;
1481
1482                                 ret_uids = e_util_copy_string_slist (NULL, uids);
1483
1484                                 g_simple_async_result_set_op_res_gpointer (
1485                                         direct->result, ret_uids,
1486                                         (GDestroyNotify) e_util_free_string_slist);
1487                         }
1488                 }
1489
1490                 /* Deliver the result to the caller */
1491                 direct_operation_complete (direct);
1492
1493         } else if (error == NULL) {
1494                 gchar **strv;
1495                 guint length;
1496                 gint ii = 0;
1497
1498                 length = g_slist_length ((GSList *) uids);
1499                 strv = g_new0 (gchar *, length + 1);
1500
1501                 while (uids != NULL) {
1502                         strv[ii++] = e_util_utf8_make_valid (uids->data);
1503                         uids = g_slist_next ((GSList *) uids);
1504                 }
1505
1506                 e_dbus_address_book_complete_get_contact_list_uids (
1507                         book->priv->dbus_interface,
1508                         data->invocation,
1509                         (const gchar * const *) strv);
1510
1511                 g_strfreev (strv);
1512         } else {
1513                 g_dbus_method_invocation_take_error (
1514                         data->invocation, error);
1515         }
1516
1517         op_unref (data);
1518 }
1519
1520 /**
1521  * e_data_book_respond_create_contacts:
1522  *
1523  * FIXME: Document me!
1524  *
1525  * Since: 3.4
1526  **/
1527 void
1528 e_data_book_respond_create_contacts (EDataBook *book,
1529                                      guint32 opid,
1530                                      GError *error,
1531                                      const GSList *contacts)
1532 {
1533         OperationData *data;
1534
1535         g_return_if_fail (E_IS_DATA_BOOK (book));
1536
1537         data = op_claim (book, opid, NULL);
1538         g_return_if_fail (data != NULL);
1539
1540         /* Translators: This is prefix to a detailed error message */
1541         g_prefix_error (&error, "%s", _("Cannot add contact: "));
1542
1543         if (error == NULL) {
1544                 EBookBackend *backend;
1545                 gchar **strv;
1546                 guint length;
1547                 gint ii = 0;
1548
1549                 backend = e_data_book_get_backend (book);
1550
1551                 length = g_slist_length ((GSList *) contacts);
1552                 strv = g_new0 (gchar *, length + 1);
1553
1554                 while (contacts != NULL) {
1555                         EContact *contact = E_CONTACT (contacts->data);
1556                         const gchar *uid;
1557
1558                         uid = e_contact_get_const (contact, E_CONTACT_UID);
1559                         strv[ii++] = e_util_utf8_make_valid (uid);
1560
1561                         e_book_backend_notify_update (backend, contact);
1562
1563                         contacts = g_slist_next ((GSList *) contacts);
1564                 }
1565
1566                 e_dbus_address_book_complete_create_contacts (
1567                         book->priv->dbus_interface,
1568                         data->invocation,
1569                         (const gchar * const *) strv);
1570
1571                 e_book_backend_notify_complete (backend);
1572
1573                 g_strfreev (strv);
1574         } else {
1575                 data_book_convert_to_client_error (error);
1576                 g_dbus_method_invocation_take_error (
1577                         data->invocation, error);
1578         }
1579
1580         op_unref (data);
1581 }
1582
1583 /**
1584  * e_data_book_respond_modify_contacts:
1585  *
1586  * FIXME: Document me!
1587  *
1588  * Since: 3.4
1589  **/
1590 void
1591 e_data_book_respond_modify_contacts (EDataBook *book,
1592                                      guint32 opid,
1593                                      GError *error,
1594                                      const GSList *contacts)
1595 {
1596         OperationData *data;
1597
1598         g_return_if_fail (E_IS_DATA_BOOK (book));
1599
1600         data = op_claim (book, opid, NULL);
1601         g_return_if_fail (data != NULL);
1602
1603         /* Translators: This is prefix to a detailed error message */
1604         g_prefix_error (&error, "%s", _("Cannot modify contacts: "));
1605
1606         if (error == NULL) {
1607                 EBookBackend *backend;
1608
1609                 backend = e_data_book_get_backend (book);
1610
1611                 e_dbus_address_book_complete_modify_contacts (
1612                         book->priv->dbus_interface,
1613                         data->invocation);
1614
1615                 while (contacts != NULL) {
1616                         EContact *contact = E_CONTACT (contacts->data);
1617                         e_book_backend_notify_update (backend, contact);
1618                         contacts = g_slist_next ((GSList *) contacts);
1619                 }
1620
1621                 e_book_backend_notify_complete (backend);
1622         } else {
1623                 data_book_convert_to_client_error (error);
1624                 g_dbus_method_invocation_take_error (
1625                         data->invocation, error);
1626         }
1627
1628         op_unref (data);
1629 }
1630
1631 void
1632 e_data_book_respond_remove_contacts (EDataBook *book,
1633                                      guint32 opid,
1634                                      GError *error,
1635                                      const GSList *ids)
1636 {
1637         OperationData *data;
1638
1639         g_return_if_fail (E_IS_DATA_BOOK (book));
1640
1641         data = op_claim (book, opid, NULL);
1642         g_return_if_fail (data != NULL);
1643
1644         /* Translators: This is prefix to a detailed error message */
1645         g_prefix_error (&error, "%s", _("Cannot remove contacts: "));
1646
1647         if (error == NULL) {
1648                 EBookBackend *backend;
1649
1650                 backend = e_data_book_get_backend (book);
1651
1652                 e_dbus_address_book_complete_remove_contacts (
1653                         book->priv->dbus_interface,
1654                         data->invocation);
1655
1656                 while (ids != NULL) {
1657                         e_book_backend_notify_remove (backend, ids->data);
1658                         ids = g_slist_next ((GSList *) ids);
1659                 }
1660
1661                 e_book_backend_notify_complete (backend);
1662         } else {
1663                 data_book_convert_to_client_error (error);
1664                 g_dbus_method_invocation_take_error (
1665                         data->invocation, error);
1666         }
1667
1668         op_unref (data);
1669 }
1670
1671 /**
1672  * e_data_book_report_error:
1673  *
1674  * FIXME: Document me.
1675  *
1676  * Since: 3.2
1677  **/
1678 void
1679 e_data_book_report_error (EDataBook *book,
1680                           const gchar *message)
1681 {
1682         g_return_if_fail (E_IS_DATA_BOOK (book));
1683         g_return_if_fail (message != NULL);
1684
1685         e_dbus_address_book_emit_error (book->priv->dbus_interface, message);
1686 }
1687
1688 /**
1689  * e_data_book_report_readonly:
1690  *
1691  * FIXME: Document me.
1692  *
1693  * Since: 3.2
1694  *
1695  * Deprecated: 3.8: Use e_book_backend_set_writable() instead.
1696  **/
1697 void
1698 e_data_book_report_readonly (EDataBook *book,
1699                              gboolean readonly)
1700 {
1701         g_return_if_fail (E_IS_DATA_BOOK (book));
1702
1703         e_book_backend_set_writable (book->priv->backend, !readonly);
1704 }
1705
1706 /**
1707  * e_data_book_report_online:
1708  *
1709  * FIXME: Document me.
1710  *
1711  * Since: 3.2
1712  *
1713  * Deprecated: 3.8: Use e_backend_set_online() instead.
1714  **/
1715 void
1716 e_data_book_report_online (EDataBook *book,
1717                            gboolean is_online)
1718 {
1719         g_return_if_fail (E_IS_DATA_BOOK (book));
1720
1721         e_backend_set_online (E_BACKEND (book->priv->backend), is_online);
1722 }
1723
1724 /**
1725  * e_data_book_report_opened:
1726  *
1727  * Reports to associated client that opening phase of the book is finished.
1728  * error being NULL means successfully, otherwise reports an error which
1729  * happened during opening phase. By opening phase is meant a process
1730  * including successfull authentication to the server/storage.
1731  *
1732  * Since: 3.2
1733  *
1734  * Deprecated: 3.8: This function no longer does anything.
1735  **/
1736 void
1737 e_data_book_report_opened (EDataBook *book,
1738                            const GError *error)
1739 {
1740         /* Do nothing. */
1741 }
1742
1743 /**
1744  * e_data_book_report_backend_property_changed:
1745  *
1746  * FIXME: Document me.
1747  *
1748  * Since: 3.2
1749  **/
1750 void
1751 e_data_book_report_backend_property_changed (EDataBook *book,
1752                                              const gchar *prop_name,
1753                                              const gchar *prop_value)
1754 {
1755         EDBusAddressBook *dbus_interface;
1756         gchar **strv;
1757
1758         g_return_if_fail (E_IS_DATA_BOOK (book));
1759         g_return_if_fail (prop_name != NULL);
1760
1761         if (prop_value == NULL)
1762                 prop_value = "";
1763
1764         dbus_interface = book->priv->dbus_interface;
1765
1766         if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
1767                 strv = g_strsplit (prop_value, ",", -1);
1768                 e_dbus_address_book_set_capabilities (
1769                         dbus_interface, (const gchar * const *) strv);
1770                 g_strfreev (strv);
1771         }
1772
1773         if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION))
1774                 e_dbus_address_book_set_revision (dbus_interface, prop_value);
1775
1776         if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
1777                 strv = g_strsplit (prop_value, ",", -1);
1778                 e_dbus_address_book_set_required_fields (
1779                         dbus_interface, (const gchar * const *) strv);
1780                 g_strfreev (strv);
1781         }
1782
1783         if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
1784                 strv = g_strsplit (prop_value, ",", -1);
1785                 e_dbus_address_book_set_supported_fields (
1786                         dbus_interface, (const gchar * const *) strv);
1787                 g_strfreev (strv);
1788         }
1789
1790         /* Disregard anything else. */
1791 }
1792
1793 static gchar *
1794 data_book_interpret_locale_value (const gchar *value)
1795 {
1796         gchar *interpreted_value = NULL;
1797         gchar **split;
1798
1799         split = g_strsplit (value, "=", 2);
1800
1801         if (split && split[0] && split[1])
1802                 interpreted_value = g_strdup (split[1]);
1803
1804         g_strfreev (split);
1805
1806         if (!interpreted_value)
1807                 g_warning ("Failed to interpret locale value: %s", value);
1808
1809         return interpreted_value;
1810 }
1811
1812 static gchar *
1813 data_book_interpret_locale (const gchar * const * locale)
1814 {
1815         gint i;
1816         gchar *interpreted_locale = NULL;
1817
1818         /* Prioritize LC_COLLATE and then LANG values
1819          * in the 'locale' specified by localed.
1820          *
1821          * If localed explicitly specifies no locale, then
1822          * default to checking system locale.
1823          */
1824         if (locale) {
1825
1826                 for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
1827
1828                         if (strncmp (locale[i], "LC_COLLATE", 10))
1829                                 interpreted_locale = data_book_interpret_locale_value (locale[i]);
1830                 }
1831
1832                 for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
1833
1834                         if (strncmp (locale[i], "LANG", 4))
1835                                 interpreted_locale = data_book_interpret_locale_value (locale[i]);
1836                 }
1837         }
1838
1839         if (!interpreted_locale) {
1840                 const gchar *system_locale = setlocale (LC_COLLATE, NULL);
1841
1842                 interpreted_locale = g_strdup (system_locale);
1843         }
1844
1845         return interpreted_locale;
1846 }
1847
1848 static void
1849 data_book_locale_changed (GObject *object,
1850                           GParamSpec *pspec,
1851                           gpointer user_data)
1852 {
1853         EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object);
1854         EDataBook *book = (EDataBook *)user_data;
1855         EBookBackend *backend;
1856
1857         backend = book->priv->backend;
1858
1859         if (backend) {
1860                 const gchar * const *locale;
1861                 gchar *interpreted_locale;
1862
1863                 locale = e_dbus_locale1_get_locale (locale_proxy);
1864                 interpreted_locale = data_book_interpret_locale (locale);
1865
1866                 e_book_backend_set_locale (backend, interpreted_locale);
1867
1868                 e_dbus_address_book_set_locale (book->priv->dbus_interface, interpreted_locale);
1869
1870                 g_free (interpreted_locale);
1871         }
1872 }
1873
1874 static void
1875 data_book_localed_ready (GObject *source_object,
1876                          GAsyncResult *res,
1877                          gpointer user_data)
1878 {
1879         EDataBook *book = (EDataBook *)user_data;
1880         GError *error = NULL;
1881
1882         book->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error);
1883
1884         if (book->priv->localed_proxy == NULL) {
1885                 g_warning ("Error fetching localed proxy: %s", error->message);
1886                 g_error_free (error);
1887         }
1888
1889         if (book->priv->localed_cancel) {
1890                 g_object_unref (book->priv->localed_cancel);
1891                 book->priv->localed_cancel = NULL;
1892         }
1893
1894         if (book->priv->localed_proxy) {
1895                 g_signal_connect (book->priv->localed_proxy, "notify::locale",
1896                                   G_CALLBACK (data_book_locale_changed), book);
1897
1898                 /* Initial refresh the locale */
1899                 data_book_locale_changed (G_OBJECT (book->priv->localed_proxy), NULL, book);
1900         }
1901 }
1902
1903 static void
1904 data_book_localed_appeared (GDBusConnection *connection,
1905                             const gchar *name,
1906                             const gchar *name_owner,
1907                             gpointer user_data)
1908 {
1909         EDataBook *book = (EDataBook *)user_data;
1910
1911         book->priv->localed_cancel = g_cancellable_new ();
1912
1913         e_dbus_locale1_proxy_new (connection,
1914                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1915                                   "org.freedesktop.locale1",
1916                                   "/org/freedesktop/locale1",
1917                                   book->priv->localed_cancel,
1918                                   data_book_localed_ready,
1919                                   book);
1920 }
1921
1922 static void
1923 data_book_localed_vanished (GDBusConnection *connection,
1924                             const gchar *name,
1925                             gpointer user_data)
1926 {
1927         EDataBook *book = (EDataBook *)user_data;
1928
1929         if (book->priv->localed_cancel) {
1930                 g_cancellable_cancel (book->priv->localed_cancel);
1931                 g_object_unref (book->priv->localed_cancel);
1932                 book->priv->localed_cancel = NULL;
1933         }
1934
1935         if (book->priv->localed_proxy) {
1936                 g_object_unref (book->priv->localed_proxy);
1937                 book->priv->localed_proxy = NULL;
1938         }
1939 }
1940
1941 static void
1942 data_book_set_backend (EDataBook *book,
1943                        EBookBackend *backend)
1944 {
1945         g_return_if_fail (E_IS_BOOK_BACKEND (backend));
1946         g_return_if_fail (book->priv->backend == NULL);
1947
1948         book->priv->backend = g_object_ref (backend);
1949 }
1950
1951 static void
1952 data_book_set_connection (EDataBook *book,
1953                           GDBusConnection *connection)
1954 {
1955         g_return_if_fail (connection == NULL ||
1956                           G_IS_DBUS_CONNECTION (connection));
1957         g_return_if_fail (book->priv->connection == NULL);
1958
1959         if (connection)
1960                 book->priv->connection = g_object_ref (connection);
1961 }
1962
1963 static void
1964 data_book_set_object_path (EDataBook *book,
1965                            const gchar *object_path)
1966 {
1967         g_return_if_fail (book->priv->object_path == NULL);
1968
1969         book->priv->object_path = g_strdup (object_path);
1970 }
1971
1972 static void
1973 data_book_set_property (GObject *object,
1974                         guint property_id,
1975                         const GValue *value,
1976                         GParamSpec *pspec)
1977 {
1978         switch (property_id) {
1979                 case PROP_BACKEND:
1980                         data_book_set_backend (
1981                                 E_DATA_BOOK (object),
1982                                 g_value_get_object (value));
1983                         return;
1984
1985                 case PROP_CONNECTION:
1986                         data_book_set_connection (
1987                                 E_DATA_BOOK (object),
1988                                 g_value_get_object (value));
1989                         return;
1990
1991                 case PROP_OBJECT_PATH:
1992                         data_book_set_object_path (
1993                                 E_DATA_BOOK (object),
1994                                 g_value_get_string (value));
1995                         return;
1996         }
1997
1998         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1999 }
2000
2001 static void
2002 data_book_get_property (GObject *object,
2003                         guint property_id,
2004                         GValue *value,
2005                         GParamSpec *pspec)
2006 {
2007         switch (property_id) {
2008                 case PROP_BACKEND:
2009                         g_value_set_object (
2010                                 value,
2011                                 e_data_book_get_backend (
2012                                 E_DATA_BOOK (object)));
2013                         return;
2014
2015                 case PROP_CONNECTION:
2016                         g_value_set_object (
2017                                 value,
2018                                 e_data_book_get_connection (
2019                                 E_DATA_BOOK (object)));
2020                         return;
2021
2022                 case PROP_OBJECT_PATH:
2023                         g_value_set_string (
2024                                 value,
2025                                 e_data_book_get_object_path (
2026                                 E_DATA_BOOK (object)));
2027                         return;
2028         }
2029
2030         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2031 }
2032
2033 static void
2034 data_book_dispose (GObject *object)
2035 {
2036         EDataBookPrivate *priv;
2037
2038         priv = E_DATA_BOOK_GET_PRIVATE (object);
2039
2040         if (priv->connection != NULL) {
2041                 g_object_unref (priv->connection);
2042                 priv->connection = NULL;
2043         }
2044
2045         if (priv->backend != NULL) {
2046                 g_object_unref (priv->backend);
2047                 priv->backend = NULL;
2048         }
2049
2050         if (priv->direct_book) {
2051                 g_object_unref (priv->direct_book);
2052                 priv->direct_book = NULL;
2053         }
2054
2055         if (priv->direct_module) {
2056                 g_type_module_unuse (G_TYPE_MODULE (priv->direct_module));
2057                 priv->direct_module = NULL;
2058         }
2059
2060         if (priv->localed_cancel) {
2061                 g_cancellable_cancel (priv->localed_cancel);
2062                 g_object_unref (priv->localed_cancel);
2063                 priv->localed_cancel = NULL;
2064         }
2065
2066         if (priv->localed_proxy) {
2067                 g_object_unref (priv->localed_proxy);
2068                 priv->localed_proxy = NULL;
2069         }
2070
2071         /* Chain up to parent's dispose() metnod. */
2072         G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
2073 }
2074
2075 static void
2076 data_book_finalize (GObject *object)
2077 {
2078         EDataBookPrivate *priv;
2079
2080         priv = E_DATA_BOOK_GET_PRIVATE (object);
2081
2082         g_free (priv->object_path);
2083
2084         if (priv->pending_ops) {
2085                 g_hash_table_destroy (priv->pending_ops);
2086                 priv->pending_ops = NULL;
2087         }
2088
2089         g_rec_mutex_clear (&priv->pending_ops_lock);
2090         if (priv->direct_ops) {
2091                 g_hash_table_destroy (priv->direct_ops);
2092                 priv->direct_ops = NULL;
2093         }
2094
2095         if (priv->dbus_interface) {
2096                 g_object_unref (priv->dbus_interface);
2097                 priv->dbus_interface = NULL;
2098         }
2099
2100         g_mutex_clear (&priv->open_lock);
2101
2102         /* This should be empty now, else we leak memory. */
2103         g_warn_if_fail (g_queue_is_empty (&priv->open_queue));
2104
2105         if (priv->localed_watch_id > 0)
2106                 g_bus_unwatch_name (priv->localed_watch_id);
2107
2108         /* Chain up to parent's finalize() method. */
2109         G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object);
2110 }
2111
2112 static gboolean
2113 data_book_initable_init (GInitable *initable,
2114                          GCancellable *cancellable,
2115                          GError **error)
2116 {
2117         EDataBook *book;
2118         OperationData *op;
2119         const gchar *locale;
2120         GBusType bus_type = G_BUS_TYPE_SYSTEM;
2121
2122         book = E_DATA_BOOK (initable);
2123
2124         if (book->priv->connection != NULL && book->priv->object_path != NULL) {
2125                 book->priv->dbus_interface =
2126                         e_dbus_address_book_skeleton_new ();
2127
2128                 g_signal_connect (
2129                         book->priv->dbus_interface, "handle-open",
2130                         G_CALLBACK (data_book_handle_open_cb), book);
2131                 g_signal_connect (
2132                         book->priv->dbus_interface, "handle-refresh",
2133                         G_CALLBACK (data_book_handle_refresh_cb), book);
2134                 g_signal_connect (
2135                         book->priv->dbus_interface, "handle-get-contact",
2136                         G_CALLBACK (data_book_handle_get_contact_cb), book);
2137                 g_signal_connect (
2138                         book->priv->dbus_interface, "handle-get-contact-list",
2139                         G_CALLBACK (data_book_handle_get_contact_list_cb), book);
2140                 g_signal_connect (
2141                         book->priv->dbus_interface, "handle-get-contact-list-uids",
2142                         G_CALLBACK (data_book_handle_get_contact_list_uids_cb), book);
2143                 g_signal_connect (
2144                         book->priv->dbus_interface, "handle-create-contacts",
2145                         G_CALLBACK (data_book_handle_create_contacts_cb), book);
2146                 g_signal_connect (
2147                         book->priv->dbus_interface, "handle-remove-contacts",
2148                         G_CALLBACK (data_book_handle_remove_contacts_cb), book);
2149                 g_signal_connect (
2150                         book->priv->dbus_interface, "handle-modify-contacts",
2151                         G_CALLBACK (data_book_handle_modify_contacts_cb), book);
2152                 g_signal_connect (
2153                         book->priv->dbus_interface, "handle-get-view",
2154                         G_CALLBACK (data_book_handle_get_view_cb), book);
2155                 g_signal_connect (
2156                         book->priv->dbus_interface, "handle-close",
2157                         G_CALLBACK (data_book_handle_close_cb), book);
2158
2159                 /* This will be NULL for a backend that does not support
2160                  * direct read access. */
2161                 book->priv->direct_book =
2162                         e_book_backend_get_direct_book (book->priv->backend);
2163
2164                 if (book->priv->direct_book != NULL) {
2165                         gboolean success;
2166
2167                         success = e_data_book_direct_register_gdbus_object (
2168                                 book->priv->direct_book,
2169                                 book->priv->connection,
2170                                 book->priv->object_path,
2171                                 error);
2172                         if (!success)
2173                                 return FALSE;
2174                 }
2175
2176                 g_object_bind_property (
2177                         book->priv->backend, "cache-dir",
2178                         book->priv->dbus_interface, "cache-dir",
2179                         G_BINDING_SYNC_CREATE);
2180
2181                 g_object_bind_property (
2182                         book->priv->backend, "online",
2183                         book->priv->dbus_interface, "online",
2184                         G_BINDING_SYNC_CREATE);
2185
2186                 g_object_bind_property (
2187                         book->priv->backend, "writable",
2188                         book->priv->dbus_interface, "writable",
2189                         G_BINDING_SYNC_CREATE);
2190
2191                 /* XXX Initialize the rest of the properties by faking client
2192                  *     requests.  At present it's the only way to fish values
2193                  *     from EBookBackend's antiquated API. */
2194
2195                 op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
2196                 op->d.prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
2197                 e_book_backend_get_backend_property (
2198                         book->priv->backend, book, op->id,
2199                         op->cancellable, op->d.prop_name);
2200                 op_unref (op);
2201
2202                 op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
2203                 op->d.prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
2204                 e_book_backend_get_backend_property (
2205                         book->priv->backend, book, op->id,
2206                         op->cancellable, op->d.prop_name);
2207                 op_unref (op);
2208
2209                 op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
2210                 op->d.prop_name = BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS;
2211                 e_book_backend_get_backend_property (
2212                         book->priv->backend, book, op->id,
2213                         op->cancellable, op->d.prop_name);
2214                 op_unref (op);
2215
2216                 op = op_new (OP_GET_BACKEND_PROPERTY, book, NULL);
2217                 op->d.prop_name = BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS;
2218                 e_book_backend_get_backend_property (
2219                         book->priv->backend, book, op->id,
2220                         op->cancellable, op->d.prop_name);
2221                 op_unref (op);
2222
2223                 /* Fetch backend configured locale and set that as the initial
2224                  * value on the dbus object
2225                  */
2226                 locale = e_book_backend_get_locale (book->priv->backend);
2227                 e_dbus_address_book_set_locale (book->priv->dbus_interface, locale);
2228
2229                 /* When running tests, we pretend to be the "org.freedesktop.locale1" service
2230                  * on the session bus instead of the real location on the system bus.
2231                  */
2232                 if (g_getenv ("EDS_TESTING") != NULL)
2233                         bus_type = G_BUS_TYPE_SESSION;
2234
2235                 /* Watch system bus for locale change notifications */
2236                 book->priv->localed_watch_id =
2237                         g_bus_watch_name (bus_type,
2238                                           "org.freedesktop.locale1",
2239                                           G_BUS_NAME_WATCHER_FLAGS_NONE,
2240                                           data_book_localed_appeared,
2241                                           data_book_localed_vanished,
2242                                           book,
2243                                           NULL);
2244
2245                 return g_dbus_interface_skeleton_export (
2246                         G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
2247                         book->priv->connection,
2248                         book->priv->object_path,
2249                         error);
2250         }
2251
2252         return TRUE;
2253 }
2254
2255 static void
2256 e_data_book_class_init (EDataBookClass *class)
2257 {
2258         GObjectClass *object_class;
2259
2260         g_type_class_add_private (class, sizeof (EDataBookPrivate));
2261
2262         object_class = G_OBJECT_CLASS (class);
2263         object_class->set_property = data_book_set_property;
2264         object_class->get_property = data_book_get_property;
2265         object_class->dispose = data_book_dispose;
2266         object_class->finalize = data_book_finalize;
2267
2268         g_object_class_install_property (
2269                 object_class,
2270                 PROP_BACKEND,
2271                 g_param_spec_object (
2272                         "backend",
2273                         "Backend",
2274                         "The backend driving this connection",
2275                         E_TYPE_BOOK_BACKEND,
2276                         G_PARAM_READWRITE |
2277                         G_PARAM_CONSTRUCT_ONLY |
2278                         G_PARAM_STATIC_STRINGS));
2279
2280         g_object_class_install_property (
2281                 object_class,
2282                 PROP_CONNECTION,
2283                 g_param_spec_object (
2284                         "connection",
2285                         "Connection",
2286                         "The GDBusConnection on which to "
2287                         "export the address book interface",
2288                         G_TYPE_DBUS_CONNECTION,
2289                         G_PARAM_READWRITE |
2290                         G_PARAM_CONSTRUCT_ONLY |
2291                         G_PARAM_STATIC_STRINGS));
2292
2293         g_object_class_install_property (
2294                 object_class,
2295                 PROP_OBJECT_PATH,
2296                 g_param_spec_string (
2297                         "object-path",
2298                         "Object Path",
2299                         "The object path at which to "
2300                         "export the address book interface",
2301                         NULL,
2302                         G_PARAM_READWRITE |
2303                         G_PARAM_CONSTRUCT_ONLY |
2304                         G_PARAM_STATIC_STRINGS));
2305
2306         if (!ops_pool)
2307                 ops_pool = e_operation_pool_new (10, operation_thread, NULL);
2308 }
2309
2310 static void
2311 e_data_book_initable_init (GInitableIface *interface)
2312 {
2313         interface->init = data_book_initable_init;
2314 }
2315
2316 static void
2317 e_data_book_init (EDataBook *ebook)
2318 {
2319         ebook->priv = E_DATA_BOOK_GET_PRIVATE (ebook);
2320
2321         ebook->priv->pending_ops = g_hash_table_new_full (
2322                 (GHashFunc) g_direct_hash,
2323                 (GEqualFunc) g_direct_equal,
2324                 (GDestroyNotify) NULL,
2325                 (GDestroyNotify) op_unref);
2326         ebook->priv->direct_ops = g_hash_table_new_full (
2327                 g_direct_hash, g_direct_equal, NULL,
2328                 (GDestroyNotify) direct_operation_data_free);
2329         g_rec_mutex_init (&ebook->priv->pending_ops_lock);
2330         g_mutex_init (&ebook->priv->open_lock);
2331 }
2332
2333 /**
2334  * e_data_book_new:
2335  * @backend: an #EBookBackend
2336  * @connection: a #GDBusConnection
2337  * @object_path: object path for the D-Bus interface
2338  * @error: return location for a #GError, or %NULL
2339  *
2340  * Creates a new #EDataBook and exports the AddressBook D-Bus interface
2341  * on @connection at @object_path.  The #EDataBook handles incoming remote
2342  * method invocations and forwards them to the @backend.  If the AddressBook
2343  * interface fails to export, the function sets @error and returns %NULL.
2344  *
2345  * Returns: an #EDataBook, or %NULL on error
2346  **/
2347 EDataBook *
2348 e_data_book_new (EBookBackend *backend,
2349                  GDBusConnection *connection,
2350                  const gchar *object_path,
2351                  GError **error)
2352 {
2353         g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
2354         g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2355         g_return_val_if_fail (object_path != NULL, NULL);
2356
2357         return g_initable_new (
2358                 E_TYPE_DATA_BOOK, NULL, error,
2359                 "backend", backend,
2360                 "connection", connection,
2361                 "object-path", object_path,
2362                 NULL);
2363 }
2364
2365 /**
2366  * e_data_book_new_direct:
2367  * @registry: The #ESourceRegistry
2368  * @source: The #ESource to create a book for
2369  * @backend_path: The full path to the backend module to use
2370  * @backend_name: The #EDataFactory type name to use from the module specified by @backend_path
2371  * @config: The backend specific configuration string specified by the #EDataBookDirect
2372  * @error: (allow-none): return location for a #GError, or %NULL
2373  *
2374  * Creates an #EDataBook for Direct Read Access, the @backend_path, @backend_name and @config
2375  * parameters are fetched from an #EDataBookDirect reported over D-Bus from the server side
2376  * counter part of a given backend.
2377  *
2378  * <note><para>This API is intended for internal use only, if you want client side
2379  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2380  *
2381  * Returns: (transfer full): A newly created #EDataBook for direct read access,
2382  *          otherwise %NULL is returned and @error is set.
2383  *
2384  * Since: 3.8
2385  */
2386 EDataBook *
2387 e_data_book_new_direct (ESourceRegistry *registry,
2388                         ESource *source,
2389                         const gchar *backend_path,
2390                         const gchar *backend_name,
2391                         const gchar *config,
2392                         GError **error)
2393 {
2394         EDataBook *book = NULL;
2395         EModule *module;
2396         EBookBackend *backend;
2397         GType backend_type;
2398         GType factory_type;
2399         GTypeClass *factory_class;
2400
2401         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2402         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2403         g_return_val_if_fail (backend_path && backend_path[0], NULL);
2404         g_return_val_if_fail (backend_name && backend_name[0], NULL);
2405
2406         module = load_module (backend_path);
2407         if (!module) {
2408                 g_set_error (
2409                         error, E_CLIENT_ERROR,
2410                         E_CLIENT_ERROR_OTHER_ERROR,
2411                         "Failed to load module at specified path: %s", backend_path);
2412                 goto new_direct_finish;
2413         }
2414
2415         if (!g_type_module_use (G_TYPE_MODULE (module))) {
2416                 g_set_error (
2417                         error, E_CLIENT_ERROR,
2418                         E_CLIENT_ERROR_OTHER_ERROR,
2419                         "Failed to use EModule at path: %s", backend_path);
2420                 goto new_direct_finish;
2421         }
2422
2423         factory_type = g_type_from_name (backend_name);
2424         if (factory_type == 0) {
2425                 g_set_error (
2426                         error, E_CLIENT_ERROR,
2427                         E_CLIENT_ERROR_OTHER_ERROR,
2428                         "Failed to get backend factory '%s' from EModule at path: %s",
2429                         backend_name, backend_path);
2430                 g_type_module_unuse (G_TYPE_MODULE (module));
2431                 goto new_direct_finish;
2432         }
2433
2434         factory_class = g_type_class_ref (factory_type);
2435         backend_type  = E_BOOK_BACKEND_FACTORY_CLASS (factory_class)->backend_type;
2436         g_type_class_unref (factory_class);
2437
2438         backend = g_object_new (
2439                 backend_type,
2440                 "registry", registry,
2441                 "source", source, NULL);
2442
2443         /* The backend must be configured for direct access
2444          * before calling g_initable_init() because backends
2445          * now can open thier content at initable_init() time. */
2446         e_book_backend_configure_direct (backend, config);
2447
2448         if (!g_initable_init (G_INITABLE (backend), NULL, error)) {
2449                 g_object_unref (backend);
2450                 g_type_module_unuse (G_TYPE_MODULE (module));
2451                 goto new_direct_finish;
2452         }
2453
2454         book = g_initable_new (
2455                 E_TYPE_DATA_BOOK, NULL, error,
2456                 "backend", backend, NULL);
2457         g_object_unref (backend);
2458
2459         if (!book) {
2460                 g_type_module_unuse (G_TYPE_MODULE (module));
2461                 goto new_direct_finish;
2462         }
2463
2464         book->priv->direct_module = module;
2465
2466  new_direct_finish:
2467
2468         return book;
2469 }
2470
2471 /**
2472  * e_data_book_get_backend:
2473  * @book: an #EDataBook
2474  *
2475  * Returns the #EBookBackend to which incoming remote method invocations
2476  * are being forwarded.
2477  *
2478  * Returns: the #EBookBackend
2479  **/
2480 EBookBackend *
2481 e_data_book_get_backend (EDataBook *book)
2482 {
2483         g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
2484
2485         return book->priv->backend;
2486 }
2487
2488 /**
2489  * e_data_book_get_connection:
2490  * @book: an #EDataBook
2491  *
2492  * Returns the #GDBusConnection on which the AddressBook D-Bus interface
2493  * is exported.
2494  *
2495  * Returns: the #GDBusConnection
2496  *
2497  * Since: 3.8
2498  **/
2499 GDBusConnection *
2500 e_data_book_get_connection (EDataBook *book)
2501 {
2502         g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
2503
2504         return book->priv->connection;
2505 }
2506
2507 /**
2508  * e_data_book_get_object_path:
2509  * @book: an #EDataBook
2510  *
2511  * Returns the object path at which the AddressBook D-Bus interface is
2512  * exported.
2513  *
2514  * Returns: the object path
2515  *
2516  * Since: 3.8
2517  **/
2518 const gchar *
2519 e_data_book_get_object_path (EDataBook *book)
2520 {
2521         g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
2522
2523         return book->priv->object_path;
2524 }
2525
2526 /*************************************************************************
2527  *                        Direct Read Access APIs                        *
2528  *************************************************************************/
2529
2530 static gboolean
2531 e_data_book_open_finish (EDataBook *book,
2532                          GAsyncResult *result,
2533                          GError **error)
2534 {
2535         gboolean res;
2536
2537         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2538         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2539
2540         res = g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result));
2541         g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
2542
2543         return res;
2544 }
2545
2546 /**
2547  * e_data_book_open_sync:
2548  * @book: an #EDataBook
2549  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2550  * @error: (allow-none): return location for a #GError, or %NULL
2551  *
2552  * Opens the #EDataBook and it's backend.
2553  *
2554  * <note><para>This API is intended for internal use only, if you want client side
2555  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2556  *
2557  * Returns: %TRUE on success. If %FALSE is returned, @error will be set
2558  *
2559  * Since: 3.8
2560  */
2561 gboolean
2562 e_data_book_open_sync (EDataBook *book,
2563                        GCancellable *cancellable,
2564                        GError **error)
2565 {
2566         DirectOperationData *data = NULL;
2567         OperationData *op;
2568         gboolean result = FALSE;
2569
2570         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2571
2572         op = op_direct_new (OP_OPEN, book, cancellable, NULL, NULL, e_data_book_open_sync, TRUE, &data);
2573
2574         op_dispatch (book, op);
2575
2576         direct_operation_wait (data);
2577         result = e_data_book_open_finish (book, G_ASYNC_RESULT (data->result), error);
2578         direct_operation_data_free (data);
2579
2580         return result;
2581 }
2582
2583 static void
2584 e_data_book_respond_close (EDataBook *book,
2585                            guint opid,
2586                            GError *error)
2587 {
2588         DirectOperationData *data;
2589
2590         data = op_complete (book, opid);
2591
2592         if (data) {
2593                 gboolean result = FALSE;
2594
2595                 if (error)
2596                         g_simple_async_result_set_error (
2597                                 data->result,
2598                                 error->domain,
2599                                 error->code,
2600                                 "%s", error->message);
2601
2602                 else {
2603                         if (!g_cancellable_is_cancelled (data->cancellable))
2604                                 result = TRUE;
2605
2606                         g_simple_async_result_set_check_cancellable (
2607                                 data->result,
2608                                 data->cancellable);
2609                 }
2610
2611                 g_simple_async_result_set_op_res_gboolean (data->result, result);
2612
2613                 /* Deliver the result to the caller */
2614                 direct_operation_complete (data);
2615         }
2616
2617         if (error)
2618                 g_error_free (error);
2619 }
2620
2621 /**
2622  * e_data_book_close:
2623  * @book: an #EDataBook
2624  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2625  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2626  *            is satisfied
2627  * @user_data: (closure): data to pass to @callback
2628  *
2629  * Closes the @book and its backend.
2630  *
2631  * <note><para>This API is intended for internal use only, if you want client side
2632  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2633  *
2634  * Since: 3.8
2635  */
2636 void
2637 e_data_book_close (EDataBook *book,
2638                    GCancellable *cancellable,
2639                    GAsyncReadyCallback callback,
2640                    gpointer user_data)
2641 {
2642         OperationData *op;
2643
2644         g_return_if_fail (E_IS_DATA_BOOK (book));
2645
2646         op = op_direct_new (OP_CLOSE, book, cancellable, callback, user_data, e_data_book_close, FALSE, NULL);
2647
2648         /* This operation is never queued. */
2649         e_operation_pool_push (ops_pool, op);
2650 }
2651
2652 /**
2653  * e_data_book_close_finish:
2654  * @book: an #EDataBook
2655  * @result: a #GAsyncResult
2656  * @error: (allow-none): return location for a #GError, or %NULL
2657  *
2658  * Finishes the operation started with e_data_book_close().  If an
2659  * error occurs, then this function sets @error and returns %FALSE.
2660  *
2661  * Returns: %TRUE on success
2662  *
2663  * Since: 3.8
2664  */
2665 gboolean
2666 e_data_book_close_finish (EDataBook *book,
2667                           GAsyncResult *result,
2668                           GError **error)
2669 {
2670         gboolean res;
2671
2672         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2673         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2674
2675         res = g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result));
2676         g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
2677
2678         return res;
2679 }
2680
2681 /**
2682  * e_data_book_close_sync:
2683  * @book: an #EDataBook
2684  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2685  * @error: (allow-none): return location for a #GError, or %NULL
2686  *
2687  * Closes the @book and its backend.
2688  *
2689  * <note><para>This API is intended for internal use only, if you want client side
2690  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2691  *
2692  * Returns: %TRUE on success. If %FALSE is returned, @error will be set
2693  *
2694  * Since: 3.8
2695  */
2696 gboolean
2697 e_data_book_close_sync (EDataBook *book,
2698                         GCancellable *cancellable,
2699                         GError **error)
2700 {
2701         DirectOperationData *data = NULL;
2702         OperationData *op;
2703         gboolean result = FALSE;
2704
2705         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2706
2707         op = op_direct_new (OP_CLOSE, book, cancellable, NULL, NULL, e_data_book_close_sync, TRUE, &data);
2708
2709         /* This operation is never queued. */
2710         e_operation_pool_push (ops_pool, op);
2711
2712         direct_operation_wait (data);
2713         result = e_data_book_close_finish (book, G_ASYNC_RESULT (data->result), error);
2714         direct_operation_data_free (data);
2715
2716         return result;
2717 }
2718
2719 /**
2720  * e_data_book_get_contact:
2721  * @book: an #EDataBook
2722  * @uid: a unique string ID specifying the contact
2723  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2724  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2725  *            is satisfied
2726  * @user_data: (closure): data to pass to @callback
2727  *
2728  * Retrieves #EContact from the @book for the gived @uid.
2729  * The call is finished by e_data_book_get_contact_finish()
2730  * from the @callback.
2731  *
2732  * <note><para>This API is intended for internal use only, if you want client side
2733  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2734  *
2735  * Since: 3.8
2736  */
2737 void
2738 e_data_book_get_contact (EDataBook *book,
2739                          const gchar *uid,
2740                          GCancellable *cancellable,
2741                          GAsyncReadyCallback callback,
2742                          gpointer user_data)
2743 {
2744         OperationData *op;
2745
2746         g_return_if_fail (E_IS_DATA_BOOK (book));
2747         g_return_if_fail (uid && uid[0]);
2748
2749         op = op_direct_new (OP_GET_CONTACT, book, cancellable, callback, user_data, e_data_book_get_contact, FALSE, NULL);
2750         op->d.uid = g_strdup (uid);
2751
2752         op_dispatch (book, op);
2753 }
2754
2755 /**
2756  * e_data_book_get_contact_finish:
2757  * @book: an #EDataBook
2758  * @result: a #GAsyncResult
2759  * @contact: return location for the fetched #EContact
2760  * @error: (allow-none): return location for a #GError, or %NULL
2761  *
2762  * Finishes the operation started with e_data_book_get_contact().  If an
2763  * error occurs, then this function sets @error and returns %FALSE.
2764  *
2765  * Returns: %TRUE on success
2766  *
2767  * Since: 3.8
2768  */
2769 gboolean
2770 e_data_book_get_contact_finish (EDataBook *book,
2771                                 GAsyncResult *result,
2772                                 EContact **contact,
2773                                 GError **error)
2774 {
2775         EContact *ret_contact;
2776
2777         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2778         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2779
2780         ret_contact = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
2781         g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
2782
2783         if (contact) {
2784                 if (ret_contact)
2785                         *contact = g_object_ref (ret_contact);
2786                 else
2787                         *contact = NULL;
2788         }
2789
2790         return ret_contact != NULL;
2791 }
2792
2793 /**
2794  * e_data_book_get_contact_sync:
2795  * @book: an #EDataBook
2796  * @uid: a unique string ID specifying the contact
2797  * @contact: return location for the fetched #EContact
2798  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2799  * @error: (allow-none): return location for a #GError, or %NULL
2800  *
2801  * Retrieves an #EContact from the @book for the gived @uid.
2802  *
2803  * <note><para>This API is intended for internal use only, if you want client side
2804  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2805  *
2806  * Returns: %TRUE on success. If %FALSE is returned, @error will be set
2807  *
2808  * Since: 3.8
2809  */
2810 gboolean
2811 e_data_book_get_contact_sync (EDataBook *book,
2812                               const gchar *uid,
2813                               EContact **contact,
2814                               GCancellable *cancellable,
2815                               GError **error)
2816 {
2817         DirectOperationData *data = NULL;
2818         OperationData *op;
2819         gboolean result = FALSE;
2820
2821         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2822         g_return_val_if_fail (uid && uid[0], FALSE);
2823
2824         op = op_direct_new (OP_GET_CONTACT, book, cancellable, NULL, NULL, e_data_book_get_contact_sync, TRUE, &data);
2825         op->d.uid = g_strdup (uid);
2826
2827         op_dispatch (book, op);
2828
2829         direct_operation_wait (data);
2830         result = e_data_book_get_contact_finish (book, G_ASYNC_RESULT (data->result), contact, error);
2831         direct_operation_data_free (data);
2832
2833         return result;
2834 }
2835
2836 /**
2837  * e_data_book_get_contacts:
2838  * @book: an #EDataBook
2839  * @sexp: an S-expression representing the query
2840  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2841  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2842  *            is satisfied
2843  * @user_data: (closure): data to pass to @callback
2844  *
2845  * Query @book with @sexp, receiving a list of contacts which
2846  * matched. The call is finished by e_data_book_get_contacts_finish()
2847  * from the @callback.
2848  *
2849  * <note><para>This API is intended for internal use only, if you want client side
2850  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2851  *
2852  * Since: 3.8
2853  */
2854 void
2855 e_data_book_get_contacts (EDataBook *book,
2856                           const gchar *sexp,
2857                           GCancellable *cancellable,
2858                           GAsyncReadyCallback callback,
2859                           gpointer user_data)
2860 {
2861         OperationData *op;
2862
2863         g_return_if_fail (E_IS_DATA_BOOK (book));
2864
2865         op = op_direct_new (OP_GET_CONTACTS, book, cancellable, callback, user_data, e_data_book_get_contacts, FALSE, NULL);
2866         op->d.query = g_strdup (sexp);
2867
2868         op_dispatch (book, op);
2869 }
2870
2871 /**
2872  * e_data_book_get_contacts_finish:
2873  * @book: an #EDataBook
2874  * @result: a #GAsyncResult
2875  * @contacts: (element-type EContact) (out): a #GSList of matched #EContacts
2876  * @error: (allow-none): return location for a #GError, or %NULL
2877  *
2878  * Finishes the operation started with e_data_book_get_contacts(). If an
2879  * error occurs, then this function sets @error and returns %FALSE.
2880  *
2881  * Returns: %TRUE on success
2882  *
2883  * Since: 3.8
2884  */
2885 gboolean
2886 e_data_book_get_contacts_finish (EDataBook *book,
2887                                  GAsyncResult *result,
2888                                  GSList **contacts,
2889                                  GError **error)
2890 {
2891         GSList *ret_contacts;
2892
2893         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2894         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2895
2896         ret_contacts = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
2897
2898         if (contacts) {
2899                 if (ret_contacts)
2900                         *contacts = e_util_copy_object_slist (NULL, ret_contacts);
2901                 else
2902                         *contacts = NULL;
2903         }
2904
2905         /* If there was an error, the return is FALSE, otherwise
2906          * the call was successfull even if no results were found
2907          */
2908         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
2909                 return FALSE;
2910
2911         return TRUE;
2912 }
2913
2914 /**
2915  * e_data_book_get_contacts_sync:
2916  * @book: an #EDataBook
2917  * @sexp: an S-expression representing the query
2918  * @contacts: (element-type EContact) (out): a #GSList of matched #EContacts
2919  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2920  * @error: (allow-none): return location for a #GError, or %NULL
2921  *
2922  * Query @book with @sexp, receiving a list of contacts which
2923  * matched.
2924  *
2925  * <note><para>This API is intended for internal use only, if you want client side
2926  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2927  *
2928  * Returns: %TRUE on success. If %FALSE is returned, @error will be set
2929  *
2930  * Since: 3.8
2931  */
2932 gboolean
2933 e_data_book_get_contacts_sync (EDataBook *book,
2934                                const gchar *sexp,
2935                                GSList **contacts,
2936                                GCancellable *cancellable,
2937                                GError **error)
2938 {
2939         DirectOperationData *data = NULL;
2940         OperationData *op;
2941         gboolean result = FALSE;
2942
2943         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
2944
2945         op = op_direct_new (OP_GET_CONTACTS, book, cancellable, NULL, NULL, e_data_book_get_contacts_sync, TRUE, &data);
2946         op->d.query = g_strdup (sexp);
2947
2948         op_dispatch (book, op);
2949
2950         direct_operation_wait (data);
2951         result = e_data_book_get_contacts_finish (book, G_ASYNC_RESULT (data->result), contacts, error);
2952         direct_operation_data_free (data);
2953
2954         return result;
2955 }
2956
2957 /**
2958  * e_data_book_get_contacts_uids:
2959  * @book: an #EDataBook
2960  * @sexp: an S-expression representing the query
2961  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2962  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2963  *            is satisfied
2964  * @user_data: (closure): data to pass to @callback
2965  *
2966  * Query @book with @sexp, receiving a list of contacts UIDs which
2967  * matched. The call is finished by e_data_book_get_contacts_uids_finish()
2968  * from the @callback.
2969  *
2970  * <note><para>This API is intended for internal use only, if you want client side
2971  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
2972  *
2973  * Since: 3.8
2974  */
2975 void
2976 e_data_book_get_contacts_uids (EDataBook *book,
2977                                const gchar *sexp,
2978                                GCancellable *cancellable,
2979                                GAsyncReadyCallback callback,
2980                                gpointer user_data)
2981 {
2982         OperationData *op;
2983
2984         g_return_if_fail (E_IS_DATA_BOOK (book));
2985
2986         op = op_direct_new (OP_GET_CONTACTS_UIDS, book, cancellable, callback, user_data, e_data_book_get_contacts_uids, FALSE, NULL);
2987         op->d.query = g_strdup (sexp);
2988
2989         op_dispatch (book, op);
2990 }
2991
2992 /**
2993  * e_data_book_get_contacts_uids_finish:
2994  * @book: an #EDataBook
2995  * @result: a #GAsyncResult
2996  * @contacts_uids: (element-type utf8) (out): a #GSList of matched contact UIDs stored as strings
2997  * @error: (allow-none): return location for a #GError, or %NULL
2998  *
2999  * Finishes the operation started with e_data_book_get_contacts_uids(). If an
3000  * error occurs, then this function sets @error and returns %FALSE.
3001  *
3002  * Returns: %TRUE on success
3003  *
3004  * Since: 3.8
3005  */
3006 gboolean
3007 e_data_book_get_contacts_uids_finish (EDataBook *book,
3008                                       GAsyncResult *result,
3009                                       GSList **contacts_uids,
3010                                       GError **error)
3011 {
3012         GSList *ret_uids;
3013
3014         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
3015         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3016
3017         ret_uids = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
3018
3019         if (contacts_uids) {
3020                 if (ret_uids)
3021                         *contacts_uids = e_util_copy_string_slist (NULL, ret_uids);
3022                 else
3023                         *contacts_uids = NULL;
3024         }
3025
3026         /* If there was an error, the return is FALSE, otherwise
3027          * the call was successfull even if no results were found
3028          */
3029         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
3030                 return FALSE;
3031
3032         return TRUE;
3033 }
3034
3035 /**
3036  * e_data_book_get_contacts_uids_sync:
3037  * @book: an #EDataBook
3038  * @sexp: an S-expression representing the query
3039  * @contacts_uids: (element-type utf8) (out): a #GSList of matched contact UIDs stored as strings
3040  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
3041  * @error: (allow-none): return location for a #GError, or %NULL
3042  *
3043  * Query @book with @sexp, receiving a list of contacts UIDs which
3044  * matched. 
3045  *
3046  * <note><para>This API is intended for internal use only, if you want client side
3047  * direct read access then use e_book_client_connect_direct_sync() instead</para></note>
3048  *
3049  * Returns: %TRUE on success. If %FALSE is returned, @error will be set
3050  *
3051  * Since: 3.8
3052  */
3053 gboolean
3054 e_data_book_get_contacts_uids_sync (EDataBook *book,
3055                                     const gchar *sexp,
3056                                     GSList **contacts_uids,
3057                                     GCancellable *cancellable,
3058                                     GError **error)
3059 {
3060         DirectOperationData *data = NULL;
3061         OperationData *op;
3062         gboolean result = FALSE;
3063
3064         g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
3065
3066         op = op_direct_new (OP_GET_CONTACTS_UIDS, book, cancellable, NULL, NULL, e_data_book_get_contacts_uids_sync, TRUE, &data);
3067         op->d.query = g_strdup (sexp);
3068
3069         op_dispatch (book, op);
3070
3071         direct_operation_wait (data);
3072         result = e_data_book_get_contacts_uids_finish (book, G_ASYNC_RESULT (data->result), contacts_uids, error);
3073         direct_operation_data_free (data);
3074
3075         return result;
3076 }