Make use of G_DEFINE_QUARK()
[platform/upstream/evolution-data-server.git] / addressbook / libebook / e-book-client.c
1 /*
2  * e-book-client.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  *
18  * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib/gi18n-lib.h>
27 #include <gio/gio.h>
28
29 #include <libedataserver/libedataserver.h>
30 #include <libedataserver/e-client-private.h>
31
32 #include "e-book-client.h"
33 #include "e-contact.h"
34 #include "e-name-western.h"
35
36 #include "e-gdbus-book.h"
37 #include "e-gdbus-book-factory.h"
38
39 #define E_BOOK_CLIENT_GET_PRIVATE(obj) \
40         (G_TYPE_INSTANCE_GET_PRIVATE \
41         ((obj), E_TYPE_BOOK_CLIENT, EBookClientPrivate))
42
43 struct _EBookClientPrivate {
44         GDBusProxy *dbus_proxy;
45         guint gone_signal_id;
46 };
47
48 G_DEFINE_TYPE (EBookClient, e_book_client, E_TYPE_CLIENT)
49
50 /*
51  * Well-known book backend properties:
52  * @BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS: Retrieves comma-separated list
53  *   of required fields by the backend. Use e_client_util_parse_comma_strings()
54  *   to parse returned string value into a #GSList. These fields are required
55  *   to be filled in for all contacts.
56  * @BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS: Retrieves comma-separated list
57  *   of supported fields by the backend. Use e_client_util_parse_comma_strings()
58  *   to parse returned string value into a #GSList. These fields can be
59  *   stored for contacts.
60  *
61  * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
62  *   @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
63  *   @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
64  */
65
66 G_DEFINE_QUARK (e-book-client-error-quark, e_book_client_error)
67
68 /**
69  * e_book_client_error_to_string:
70  *
71  * FIXME: Document me.
72  *
73  * Since: 3.2
74  **/
75 const gchar *
76 e_book_client_error_to_string (EBookClientError code)
77 {
78         switch (code) {
79         case E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK:
80                 return _("No such book");
81         case E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND:
82                 return _("Contact not found");
83         case E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS:
84                 return _("Contact ID already exists");
85         case E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE:
86                 return _("No such source");
87         case E_BOOK_CLIENT_ERROR_NO_SPACE:
88                 return _("No space");
89         }
90
91         return _("Unknown error");
92 }
93
94 /**
95  * e_book_client_error_create:
96  * @code: an #EBookClientError code to create
97  * @custom_msg: custom message to use for the error; can be %NULL
98  *
99  * Returns: a new #GError containing an E_BOOK_CLIENT_ERROR of the given
100  * @code. If the @custom_msg is NULL, then the error message is
101  * the one returned from e_book_client_error_to_string() for the @code,
102  * otherwise the given message is used.
103  *
104  * Returned pointer should be freed with g_error_free().
105  *
106  * Since: 3.2
107  **/
108 GError *
109 e_book_client_error_create (EBookClientError code,
110                             const gchar *custom_msg)
111 {
112         return g_error_new_literal (E_BOOK_CLIENT_ERROR, code, custom_msg ? custom_msg : e_book_client_error_to_string (code));
113 }
114
115 /*
116  * If the specified GError is a remote error, then create a new error
117  * representing the remote error.  If the error is anything else, then
118  * leave it alone.
119  */
120 static gboolean
121 unwrap_dbus_error (GError *error,
122                    GError **client_error)
123 {
124         #define err(a,b) "org.gnome.evolution.dataserver.AddressBook." a, b
125         static EClientErrorsList book_errors[] = {
126                 { err ("Success",                               -1) },
127                 { err ("ContactNotFound",                       E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND) },
128                 { err ("ContactIDAlreadyExists",                E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS) },
129                 { err ("NoSuchBook",                            E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK) },
130                 { err ("BookRemoved",                           E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE) },
131                 { err ("NoSpace",                               E_BOOK_CLIENT_ERROR_NO_SPACE) }
132         }, cl_errors[] = {
133                 { err ("Busy",                                  E_CLIENT_ERROR_BUSY) },
134                 { err ("RepositoryOffline",                     E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
135                 { err ("OfflineUnavailable",                    E_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
136                 { err ("PermissionDenied",                      E_CLIENT_ERROR_PERMISSION_DENIED) },
137                 { err ("AuthenticationFailed",                  E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
138                 { err ("AuthenticationRequired",                E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
139                 { err ("CouldNotCancel",                        E_CLIENT_ERROR_COULD_NOT_CANCEL) },
140                 { err ("InvalidArg",                            E_CLIENT_ERROR_INVALID_ARG) },
141                 { err ("NotSupported",                          E_CLIENT_ERROR_NOT_SUPPORTED) },
142                 { err ("UnsupportedAuthenticationMethod",       E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) },
143                 { err ("TLSNotAvailable",                       E_CLIENT_ERROR_TLS_NOT_AVAILABLE) },
144                 { err ("SearchSizeLimitExceeded",               E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED) },
145                 { err ("SearchTimeLimitExceeded",               E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED) },
146                 { err ("InvalidQuery",                          E_CLIENT_ERROR_INVALID_QUERY) },
147                 { err ("QueryRefused",                          E_CLIENT_ERROR_QUERY_REFUSED) },
148                 { err ("NotOpened",                             E_CLIENT_ERROR_NOT_OPENED) },
149                 { err ("UnsupportedField",                      E_CLIENT_ERROR_OTHER_ERROR) },
150                 { err ("InvalidServerVersion",                  E_CLIENT_ERROR_OTHER_ERROR) },
151                 { err ("OtherError",                            E_CLIENT_ERROR_OTHER_ERROR) }
152         };
153         #undef err
154
155         if (error == NULL)
156                 return TRUE;
157
158         if (!e_client_util_unwrap_dbus_error (error, client_error, book_errors, G_N_ELEMENTS (book_errors), E_BOOK_CLIENT_ERROR, TRUE))
159                 e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
160
161         return FALSE;
162 }
163
164 static void
165 set_proxy_gone_error (GError **error)
166 {
167         /* do not translate this string, it should ideally never happen */
168         g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, "D-Bus book proxy gone");
169 }
170
171 static guint active_book_clients = 0, book_connection_closed_id = 0;
172 static EGdbusBookFactory *book_factory = NULL;
173 static GRecMutex book_factory_lock;
174 #define LOCK_FACTORY()   g_rec_mutex_lock (&book_factory_lock)
175 #define UNLOCK_FACTORY() g_rec_mutex_unlock (&book_factory_lock)
176
177 static void gdbus_book_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
178
179 static void
180 gdbus_book_factory_disconnect (GDBusConnection *connection)
181 {
182         LOCK_FACTORY ();
183
184         if (!connection && book_factory)
185                 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
186
187         if (connection && book_connection_closed_id) {
188                 g_dbus_connection_signal_unsubscribe (connection, book_connection_closed_id);
189                 g_signal_handlers_disconnect_by_func (connection, gdbus_book_factory_closed_cb, NULL);
190         }
191
192         if (book_factory != NULL)
193                 g_object_unref (book_factory);
194
195         book_connection_closed_id = 0;
196         book_factory = NULL;
197
198         UNLOCK_FACTORY ();
199 }
200
201 static void
202 gdbus_book_factory_closed_cb (GDBusConnection *connection,
203                               gboolean remote_peer_vanished,
204                               GError *error,
205                               gpointer user_data)
206 {
207         GError *err = NULL;
208
209         LOCK_FACTORY ();
210
211         gdbus_book_factory_disconnect (connection);
212
213         if (error)
214                 unwrap_dbus_error (g_error_copy (error), &err);
215
216         if (err) {
217                 g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
218                 g_error_free (err);
219         } else if (active_book_clients) {
220                 g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
221         }
222
223         UNLOCK_FACTORY ();
224 }
225
226 static void
227 gdbus_book_factory_connection_gone_cb (GDBusConnection *connection,
228                                        const gchar *sender_name,
229                                        const gchar *object_path,
230                                        const gchar *interface_name,
231                                        const gchar *signal_name,
232                                        GVariant *parameters,
233                                        gpointer user_data)
234 {
235         /* signal subscription takes care of correct parameters,
236          * thus just do what is to be done here */
237         gdbus_book_factory_closed_cb (connection, TRUE, NULL, user_data);
238 }
239
240 static gboolean
241 gdbus_book_factory_activate (GCancellable *cancellable,
242                              GError **error)
243 {
244         GDBusConnection *connection;
245
246         LOCK_FACTORY ();
247
248         if (G_LIKELY (book_factory != NULL)) {
249                 UNLOCK_FACTORY ();
250                 return TRUE;
251         }
252
253         book_factory = e_gdbus_book_factory_proxy_new_for_bus_sync (
254                 G_BUS_TYPE_SESSION,
255                 G_DBUS_PROXY_FLAGS_NONE,
256                 ADDRESS_BOOK_DBUS_SERVICE_NAME,
257                 "/org/gnome/evolution/dataserver/AddressBookFactory",
258                 cancellable, error);
259
260         if (book_factory == NULL) {
261                 UNLOCK_FACTORY ();
262                 return FALSE;
263         }
264
265         connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
266         book_connection_closed_id = g_dbus_connection_signal_subscribe (
267                 connection,
268                 NULL,                                           /* sender */
269                 "org.freedesktop.DBus",                         /* interface */
270                 "NameOwnerChanged",                             /* member */
271                 "/org/freedesktop/DBus",                        /* object_path */
272                 "org.gnome.evolution.dataserver.AddressBook",   /* arg0 */
273                 G_DBUS_SIGNAL_FLAGS_NONE,
274                 gdbus_book_factory_connection_gone_cb, NULL, NULL);
275
276         g_signal_connect (
277                 connection, "closed",
278                 G_CALLBACK (gdbus_book_factory_closed_cb), NULL);
279
280         UNLOCK_FACTORY ();
281
282         return TRUE;
283 }
284
285 static void gdbus_book_client_disconnect (EBookClient *client);
286
287 /*
288  * Called when the addressbook server dies.
289  */
290 static void
291 gdbus_book_client_closed_cb (GDBusConnection *connection,
292                              gboolean remote_peer_vanished,
293                              GError *error,
294                              EBookClient *client)
295 {
296         GError *err = NULL;
297
298         g_assert (E_IS_BOOK_CLIENT (client));
299
300         if (error)
301                 unwrap_dbus_error (g_error_copy (error), &err);
302
303         if (err) {
304                 g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
305                 g_error_free (err);
306         } else {
307                 g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
308         }
309
310         gdbus_book_client_disconnect (client);
311
312         e_client_emit_backend_died (E_CLIENT (client));
313 }
314
315 static void
316 gdbus_book_client_connection_gone_cb (GDBusConnection *connection,
317                                       const gchar *sender_name,
318                                       const gchar *object_path,
319                                       const gchar *interface_name,
320                                       const gchar *signal_name,
321                                       GVariant *parameters,
322                                       gpointer user_data)
323 {
324         /* signal subscription takes care of correct parameters,
325          * thus just do what is to be done here */
326         gdbus_book_client_closed_cb (connection, TRUE, NULL, user_data);
327 }
328
329 static void
330 gdbus_book_client_disconnect (EBookClient *client)
331 {
332         g_return_if_fail (E_IS_BOOK_CLIENT (client));
333
334         /* Ensure that everything relevant is NULL */
335         LOCK_FACTORY ();
336
337         if (client->priv->dbus_proxy != NULL) {
338                 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->dbus_proxy));
339
340                 g_signal_handlers_disconnect_by_func (connection, gdbus_book_client_closed_cb, client);
341                 g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
342                 client->priv->gone_signal_id = 0;
343
344                 e_gdbus_book_call_close_sync (
345                         client->priv->dbus_proxy, NULL, NULL);
346                 g_object_unref (client->priv->dbus_proxy);
347                 client->priv->dbus_proxy = NULL;
348         }
349
350         UNLOCK_FACTORY ();
351 }
352
353 static void
354 backend_error_cb (EGdbusBook *dbus_proxy,
355                   const gchar *message,
356                   EBookClient *client)
357 {
358         g_return_if_fail (E_IS_BOOK_CLIENT (client));
359         g_return_if_fail (message != NULL);
360
361         e_client_emit_backend_error (E_CLIENT (client), message);
362 }
363
364 static void
365 readonly_cb (EGdbusBook *dbus_proxy,
366              gboolean readonly,
367              EBookClient *client)
368 {
369         g_return_if_fail (E_IS_BOOK_CLIENT (client));
370
371         e_client_set_readonly (E_CLIENT (client), readonly);
372 }
373
374 static void
375 online_cb (EGdbusBook *dbus_proxy,
376            gboolean is_online,
377            EBookClient *client)
378 {
379         g_return_if_fail (E_IS_BOOK_CLIENT (client));
380
381         e_client_set_online (E_CLIENT (client), is_online);
382 }
383
384 static void
385 opened_cb (EGdbusBook *dbus_proxy,
386            const gchar * const *error_strv,
387            EBookClient *client)
388 {
389         GError *error = NULL;
390
391         g_return_if_fail (E_IS_BOOK_CLIENT (client));
392         g_return_if_fail (error_strv != NULL);
393         g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
394
395         e_client_emit_opened (E_CLIENT (client), error);
396
397         if (error)
398                 g_error_free (error);
399 }
400
401 static void
402 backend_property_changed_cb (EGdbusBook *dbus_proxy,
403                              const gchar * const *name_value_strv,
404                              EBookClient *client)
405 {
406         gchar *prop_name = NULL, *prop_value = NULL;
407
408         g_return_if_fail (E_IS_BOOK_CLIENT (client));
409         g_return_if_fail (name_value_strv != NULL);
410         g_return_if_fail (e_gdbus_templates_decode_two_strings (name_value_strv, &prop_name, &prop_value));
411         g_return_if_fail (prop_name != NULL);
412         g_return_if_fail (*prop_name);
413         g_return_if_fail (prop_value != NULL);
414
415         e_client_emit_backend_property_changed (E_CLIENT (client), prop_name, prop_value);
416
417         g_free (prop_name);
418         g_free (prop_value);
419 }
420
421 /*
422  * Converts a GSList of EContact objects into a NULL-terminated array of
423  * valid UTF-8 vcard strings, suitable for sending over DBus.
424  */
425 static gchar **
426 contact_slist_to_utf8_vcard_array (GSList *contacts)
427 {
428         gchar **array;
429         const GSList *l;
430         gint i = 0;
431
432         array = g_new0 (gchar *, g_slist_length (contacts) + 1);
433         for (l = contacts; l != NULL; l = l->next) {
434                 gchar *vcard = e_vcard_to_string (E_VCARD (l->data), EVC_FORMAT_VCARD_30);
435                 array[i++] = e_util_utf8_make_valid (vcard);
436                 g_free (vcard);
437         }
438
439         return array;
440 }
441
442 static gboolean
443 book_client_get_backend_property_from_cache_finish (EClient *client,
444                                                     GAsyncResult *result,
445                                                     gchar **prop_value,
446                                                     GError **error)
447 {
448         GSimpleAsyncResult *simple;
449         GError *local_error = NULL;
450
451         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
452         g_return_val_if_fail (result != NULL, FALSE);
453         g_return_val_if_fail (prop_value != NULL, FALSE);
454         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), book_client_get_backend_property_from_cache_finish), FALSE);
455
456         simple = G_SIMPLE_ASYNC_RESULT (result);
457
458         if (g_simple_async_result_propagate_error (simple, &local_error)) {
459                 e_client_unwrap_dbus_error (client, local_error, error);
460                 return FALSE;
461         }
462
463         *prop_value = g_strdup (g_simple_async_result_get_op_res_gpointer (simple));
464
465         return *prop_value != NULL;
466 }
467
468 static void
469 book_client_dispose (GObject *object)
470 {
471         EClient *client;
472
473         client = E_CLIENT (object);
474
475         e_client_cancel_all (client);
476
477         gdbus_book_client_disconnect (E_BOOK_CLIENT (client));
478
479         /* Chain up to parent's dispose() method. */
480         G_OBJECT_CLASS (e_book_client_parent_class)->dispose (object);
481 }
482
483 static void
484 book_client_finalize (GObject *object)
485 {
486         /* Chain up to parent's finalize() method. */
487         G_OBJECT_CLASS (e_book_client_parent_class)->finalize (object);
488
489         LOCK_FACTORY ();
490         active_book_clients--;
491         if (!active_book_clients)
492                 gdbus_book_factory_disconnect (NULL);
493         UNLOCK_FACTORY ();
494 }
495
496 static GDBusProxy *
497 book_client_get_dbus_proxy (EClient *client)
498 {
499         EBookClientPrivate *priv;
500
501         priv = E_BOOK_CLIENT_GET_PRIVATE (client);
502
503         return G_DBUS_PROXY (priv->dbus_proxy);
504 }
505
506 static void
507 book_client_unwrap_dbus_error (EClient *client,
508                                GError *dbus_error,
509                                GError **out_error)
510 {
511         unwrap_dbus_error (dbus_error, out_error);
512 }
513
514 static void
515 book_client_retrieve_capabilities (EClient *client,
516                                    GCancellable *cancellable,
517                                    GAsyncReadyCallback callback,
518                                    gpointer user_data)
519 {
520         g_return_if_fail (E_IS_BOOK_CLIENT (client));
521
522         e_client_get_backend_property (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, cancellable, callback, user_data);
523 }
524
525 static gboolean
526 book_client_retrieve_capabilities_finish (EClient *client,
527                                           GAsyncResult *result,
528                                           gchar **capabilities,
529                                           GError **error)
530 {
531         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
532
533         return e_client_get_backend_property_finish (client, result, capabilities, error);
534 }
535
536 static gboolean
537 book_client_retrieve_capabilities_sync (EClient *client,
538                                         gchar **capabilities,
539                                         GCancellable *cancellable,
540                                         GError **error)
541 {
542         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
543
544         return e_client_get_backend_property_sync (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, capabilities, cancellable, error);
545 }
546
547 static void
548 book_client_get_backend_property (EClient *client,
549                                   const gchar *prop_name,
550                                   GCancellable *cancellable,
551                                   GAsyncReadyCallback callback,
552                                   gpointer user_data)
553 {
554         gchar *prop_value;
555
556         prop_value = e_client_get_backend_property_from_cache (client, prop_name);
557         if (prop_value) {
558                 e_client_finish_async_without_dbus (
559                         client, cancellable, callback, user_data,
560                         book_client_get_backend_property_from_cache_finish,
561                         prop_value, g_free);
562         } else {
563                 e_client_proxy_call_string_with_res_op_data (
564                         client, prop_name,
565                         cancellable, callback, user_data,
566                         book_client_get_backend_property, prop_name,
567                         e_gdbus_book_call_get_backend_property,
568                         NULL, NULL,
569                         e_gdbus_book_call_get_backend_property_finish,
570                         NULL, NULL);
571         }
572 }
573
574 static gboolean
575 book_client_get_backend_property_finish (EClient *client,
576                                          GAsyncResult *result,
577                                          gchar **prop_value,
578                                          GError **error)
579 {
580         gchar *str = NULL;
581         gboolean res;
582
583         g_return_val_if_fail (prop_value != NULL, FALSE);
584
585         if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == book_client_get_backend_property_from_cache_finish) {
586                 res = book_client_get_backend_property_from_cache_finish (client, result, &str, error);
587         } else {
588                 res = e_client_proxy_call_finish_string (
589                         client, result, &str, error,
590                         book_client_get_backend_property);
591                 if (res && str) {
592                         const gchar *prop_name = g_object_get_data (G_OBJECT (result), "res-op-data");
593
594                         if (prop_name && *prop_name)
595                                 e_client_update_backend_property_cache (client, prop_name, str);
596                 }
597         }
598
599         *prop_value = str;
600
601         return res;
602 }
603
604 static gboolean
605 book_client_get_backend_property_sync (EClient *client,
606                                        const gchar *prop_name,
607                                        gchar **prop_value,
608                                        GCancellable *cancellable,
609                                        GError **error)
610 {
611         EBookClient *book_client;
612         gchar *prop_val;
613         gboolean res;
614
615         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
616
617         book_client = E_BOOK_CLIENT (client);
618
619         if (book_client->priv->dbus_proxy == NULL) {
620                 set_proxy_gone_error (error);
621                 return FALSE;
622         }
623
624         prop_val = e_client_get_backend_property_from_cache (client, prop_name);
625         if (prop_val) {
626                 g_return_val_if_fail (prop_value != NULL, FALSE);
627
628                 *prop_value = prop_val;
629
630                 return TRUE;
631         }
632
633         res = e_client_proxy_call_sync_string__string (
634                 client, prop_name, prop_value, cancellable, error,
635                 e_gdbus_book_call_get_backend_property_sync);
636
637         if (res && prop_value)
638                 e_client_update_backend_property_cache (
639                         client, prop_name, *prop_value);
640
641         return res;
642 }
643
644 static void
645 book_client_set_backend_property (EClient *client,
646                                   const gchar *prop_name,
647                                   const gchar *prop_value,
648                                   GCancellable *cancellable,
649                                   GAsyncReadyCallback callback,
650                                   gpointer user_data)
651 {
652         gchar **prop_name_value;
653
654         prop_name_value = e_gdbus_book_encode_set_backend_property (prop_name, prop_value);
655
656         e_client_proxy_call_strv (
657                 client, (const gchar * const *) prop_name_value,
658                 cancellable, callback, user_data,
659                 book_client_set_backend_property,
660                 e_gdbus_book_call_set_backend_property,
661                 e_gdbus_book_call_set_backend_property_finish,
662                 NULL, NULL, NULL, NULL);
663
664         g_strfreev (prop_name_value);
665 }
666
667 static gboolean
668 book_client_set_backend_property_finish (EClient *client,
669                                          GAsyncResult *result,
670                                          GError **error)
671 {
672         return e_client_proxy_call_finish_void (
673                 client, result, error,
674                 book_client_set_backend_property);
675 }
676
677 static gboolean
678 book_client_set_backend_property_sync (EClient *client,
679                                        const gchar *prop_name,
680                                        const gchar *prop_value,
681                                        GCancellable *cancellable,
682                                        GError **error)
683 {
684         EBookClient *book_client;
685         gboolean res;
686         gchar **prop_name_value;
687
688         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
689
690         book_client = E_BOOK_CLIENT (client);
691
692         if (book_client->priv->dbus_proxy == NULL) {
693                 set_proxy_gone_error (error);
694                 return FALSE;
695         }
696
697         prop_name_value = e_gdbus_book_encode_set_backend_property (prop_name, prop_value);
698         res = e_client_proxy_call_sync_strv__void (
699                 client, (const gchar * const *) prop_name_value,
700                 cancellable, error,
701                 e_gdbus_book_call_set_backend_property_sync);
702         g_strfreev (prop_name_value);
703
704         return res;
705 }
706
707 static void
708 book_client_open (EClient *client,
709                   gboolean only_if_exists,
710                   GCancellable *cancellable,
711                   GAsyncReadyCallback callback,
712                   gpointer user_data)
713 {
714         e_client_proxy_call_boolean (
715                 client, only_if_exists,
716                 cancellable, callback, user_data,
717                 book_client_open,
718                 e_gdbus_book_call_open,
719                 e_gdbus_book_call_open_finish,
720                 NULL, NULL, NULL, NULL);
721 }
722
723 static gboolean
724 book_client_open_finish (EClient *client,
725                          GAsyncResult *result,
726                          GError **error)
727 {
728         return e_client_proxy_call_finish_void (
729                 client, result, error, book_client_open);
730 }
731
732 static gboolean
733 book_client_open_sync (EClient *client,
734                        gboolean only_if_exists,
735                        GCancellable *cancellable,
736                        GError **error)
737 {
738         EBookClient *book_client;
739
740         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
741
742         book_client = E_BOOK_CLIENT (client);
743
744         if (book_client->priv->dbus_proxy == NULL) {
745                 set_proxy_gone_error (error);
746                 return FALSE;
747         }
748
749         return e_client_proxy_call_sync_boolean__void (
750                 client, only_if_exists, cancellable, error,
751                 e_gdbus_book_call_open_sync);
752 }
753
754 static void
755 book_client_refresh (EClient *client,
756                      GCancellable *cancellable,
757                      GAsyncReadyCallback callback,
758                      gpointer user_data)
759 {
760         e_client_proxy_call_void (
761                 client, cancellable, callback, user_data,
762                 book_client_refresh,
763                 e_gdbus_book_call_refresh,
764                 e_gdbus_book_call_refresh_finish,
765                 NULL, NULL, NULL, NULL);
766 }
767
768 static gboolean
769 book_client_refresh_finish (EClient *client,
770                             GAsyncResult *result,
771                             GError **error)
772 {
773         return e_client_proxy_call_finish_void (
774                 client, result, error, book_client_refresh);
775 }
776
777 static gboolean
778 book_client_refresh_sync (EClient *client,
779                           GCancellable *cancellable,
780                           GError **error)
781 {
782         EBookClient *book_client;
783
784         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
785
786         book_client = E_BOOK_CLIENT (client);
787
788         if (book_client->priv->dbus_proxy == NULL) {
789                 set_proxy_gone_error (error);
790                 return FALSE;
791         }
792
793         return e_client_proxy_call_sync_void__void (
794                 client, cancellable, error,
795                 e_gdbus_book_call_refresh_sync);
796 }
797
798 static void
799 e_book_client_class_init (EBookClientClass *class)
800 {
801         GObjectClass *object_class;
802         EClientClass *client_class;
803
804         g_type_class_add_private (class, sizeof (EBookClientPrivate));
805
806         object_class = G_OBJECT_CLASS (class);
807         object_class->dispose = book_client_dispose;
808         object_class->finalize = book_client_finalize;
809
810         client_class = E_CLIENT_CLASS (class);
811         client_class->get_dbus_proxy                    = book_client_get_dbus_proxy;
812         client_class->unwrap_dbus_error                 = book_client_unwrap_dbus_error;
813         client_class->retrieve_capabilities             = book_client_retrieve_capabilities;
814         client_class->retrieve_capabilities_finish      = book_client_retrieve_capabilities_finish;
815         client_class->retrieve_capabilities_sync        = book_client_retrieve_capabilities_sync;
816         client_class->get_backend_property              = book_client_get_backend_property;
817         client_class->get_backend_property_finish       = book_client_get_backend_property_finish;
818         client_class->get_backend_property_sync         = book_client_get_backend_property_sync;
819         client_class->set_backend_property              = book_client_set_backend_property;
820         client_class->set_backend_property_finish       = book_client_set_backend_property_finish;
821         client_class->set_backend_property_sync         = book_client_set_backend_property_sync;
822         client_class->open                              = book_client_open;
823         client_class->open_finish                       = book_client_open_finish;
824         client_class->open_sync                         = book_client_open_sync;
825         client_class->refresh                           = book_client_refresh;
826         client_class->refresh_finish                    = book_client_refresh_finish;
827         client_class->refresh_sync                      = book_client_refresh_sync;
828 }
829
830 static void
831 e_book_client_init (EBookClient *client)
832 {
833         LOCK_FACTORY ();
834         active_book_clients++;
835         UNLOCK_FACTORY ();
836
837         client->priv = E_BOOK_CLIENT_GET_PRIVATE (client);
838 }
839
840 /**
841  * e_book_client_new:
842  * @source: An #ESource pointer
843  * @error: A #GError pointer
844  *
845  * Creates a new #EBookClient corresponding to the given source.  There are
846  * only two operations that are valid on this book at this point:
847  * e_client_open(), and e_client_remove().
848  *
849  * Returns: a new but unopened #EBookClient.
850  *
851  * Since: 3.2
852  **/
853 EBookClient *
854 e_book_client_new (ESource *source,
855                    GError **error)
856 {
857         EBookClient *client;
858         GError *err = NULL;
859         GDBusConnection *connection;
860         const gchar *uid;
861         gchar *object_path = NULL;
862
863         g_return_val_if_fail (source != NULL, NULL);
864         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
865
866         LOCK_FACTORY ();
867         /* XXX Oops, e_book_client_new() forgot to take a GCancellable. */
868         if (!gdbus_book_factory_activate (NULL, &err)) {
869                 UNLOCK_FACTORY ();
870                 if (err) {
871                         unwrap_dbus_error (err, &err);
872                         g_warning ("%s: Failed to run book factory: %s", G_STRFUNC, err->message);
873                         g_propagate_error (error, err);
874                 } else {
875                         g_warning ("%s: Failed to run book factory: Unknown error", G_STRFUNC);
876                         g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Failed to run book factory"));
877                 }
878
879                 return NULL;
880         }
881
882         uid = e_source_get_uid (source);
883
884         client = g_object_new (E_TYPE_BOOK_CLIENT, "source", source, NULL);
885         UNLOCK_FACTORY ();
886
887         e_gdbus_book_factory_call_get_book_sync (
888                 G_DBUS_PROXY (book_factory), uid, &object_path, NULL, &err);
889
890         /* Sanity check. */
891         g_return_val_if_fail (
892                 ((object_path != NULL) && (err == NULL)) ||
893                 ((object_path == NULL) && (err != NULL)), NULL);
894
895         if (err != NULL) {
896                 unwrap_dbus_error (err, &err);
897                 g_propagate_error (error, err);
898                 g_object_unref (client);
899                 return NULL;
900         }
901
902         connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory));
903
904         client->priv->dbus_proxy = G_DBUS_PROXY (e_gdbus_book_proxy_new_sync (
905                 connection,
906                 G_DBUS_PROXY_FLAGS_NONE,
907                 ADDRESS_BOOK_DBUS_SERVICE_NAME,
908                 object_path,
909                 NULL, &err));
910
911         g_free (object_path);
912
913         /* Sanity check. */
914         g_return_val_if_fail (
915                 ((client->priv->dbus_proxy != NULL) && (err == NULL)) ||
916                 ((client->priv->dbus_proxy == NULL) && (err != NULL)), NULL);
917
918         if (err != NULL) {
919                 unwrap_dbus_error (err, &err);
920                 g_propagate_error (error, err);
921                 g_object_unref (client);
922                 return NULL;
923         }
924
925         client->priv->gone_signal_id = g_dbus_connection_signal_subscribe (
926                 connection,
927                 "org.freedesktop.DBus",                         /* sender */
928                 "org.freedesktop.DBus",                         /* interface */
929                 "NameOwnerChanged",                             /* member */
930                 "/org/freedesktop/DBus",                        /* object_path */
931                 "org.gnome.evolution.dataserver.AddressBook",   /* arg0 */
932                 G_DBUS_SIGNAL_FLAGS_NONE,
933                 gdbus_book_client_connection_gone_cb, client, NULL);
934
935         g_signal_connect (
936                 connection, "closed",
937                 G_CALLBACK (gdbus_book_client_closed_cb), client);
938
939         g_signal_connect (
940                 client->priv->dbus_proxy, "backend_error",
941                 G_CALLBACK (backend_error_cb), client);
942         g_signal_connect (
943                 client->priv->dbus_proxy, "readonly",
944                 G_CALLBACK (readonly_cb), client);
945         g_signal_connect (
946                 client->priv->dbus_proxy, "online",
947                 G_CALLBACK (online_cb), client);
948         g_signal_connect (
949                 client->priv->dbus_proxy, "opened",
950                 G_CALLBACK (opened_cb), client);
951         g_signal_connect (
952                 client->priv->dbus_proxy, "backend-property-changed",
953                 G_CALLBACK (backend_property_changed_cb), client);
954
955         return client;
956 }
957
958 #define SELF_UID_PATH_ID "org.gnome.evolution-data-server.addressbook"
959 #define SELF_UID_KEY "self-contact-uid"
960
961 static EContact *
962 make_me_card (void)
963 {
964         GString *vcard;
965         const gchar *s;
966         EContact *contact;
967
968         vcard = g_string_new ("BEGIN:VCARD\nVERSION:3.0\n");
969
970         s = g_get_user_name ();
971         if (s)
972                 g_string_append_printf (vcard, "NICKNAME:%s\n", s);
973
974         s = g_get_real_name ();
975         if (s && strcmp (s, "Unknown") != 0) {
976                 ENameWestern *western;
977
978                 g_string_append_printf (vcard, "FN:%s\n", s);
979
980                 western = e_name_western_parse (s);
981                 g_string_append_printf (
982                         vcard, "N:%s;%s;%s;%s;%s\n",
983                         western->last ? western->last : "",
984                         western->first ? western->first : "",
985                         western->middle ? western->middle : "",
986                         western->prefix ? western->prefix : "",
987                         western->suffix ? western->suffix : "");
988                 e_name_western_free (western);
989         }
990         g_string_append (vcard, "END:VCARD");
991
992         contact = e_contact_new_from_vcard (vcard->str);
993
994         g_string_free (vcard, TRUE);
995
996         return contact;
997 }
998
999 /**
1000  * e_book_client_get_self:
1001  * @registry: an #ESourceRegistry
1002  * @contact: (out): an #EContact pointer to set
1003  * @client: (out): an #EBookClient pointer to set
1004  * @error: a #GError to set on failure
1005  *
1006  * Get the #EContact referring to the user of the address book
1007  * and set it in @contact and @client.
1008  *
1009  * Returns: %TRUE if successful, otherwise %FALSE.
1010  *
1011  * Since: 3.2
1012  **/
1013 gboolean
1014 e_book_client_get_self (ESourceRegistry *registry,
1015                         EContact **contact,
1016                         EBookClient **client,
1017                         GError **error)
1018 {
1019         ESource *source;
1020         GError *local_error = NULL;
1021         GSettings *settings;
1022         gchar *uid;
1023
1024         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1025         g_return_val_if_fail (contact != NULL, FALSE);
1026         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1027
1028         source = e_source_registry_ref_builtin_address_book (registry);
1029         *client = e_book_client_new (source, &local_error);
1030         g_object_unref (source);
1031
1032         if (!*client) {
1033                 g_propagate_error (error, local_error);
1034                 return FALSE;
1035         }
1036
1037         if (!e_client_open_sync (E_CLIENT (*client), FALSE, NULL, &local_error)) {
1038                 g_object_unref (*client);
1039                 *client = NULL;
1040                 g_propagate_error (error, local_error);
1041
1042                 return FALSE;
1043         }
1044
1045         settings = g_settings_new (SELF_UID_PATH_ID);
1046         uid = g_settings_get_string (settings, SELF_UID_KEY);
1047         g_object_unref (settings);
1048
1049         if (uid) {
1050                 gboolean got;
1051
1052                 /* Don't care about errors because we'll create a new card on failure */
1053                 got = e_book_client_get_contact_sync (*client, uid, contact, NULL, NULL);
1054                 g_free (uid);
1055                 if (got)
1056                         return TRUE;
1057         }
1058
1059         uid = NULL;
1060         *contact = make_me_card ();
1061         if (!e_book_client_add_contact_sync (*client, *contact, &uid, NULL, &local_error)) {
1062                 g_object_unref (*client);
1063                 *client = NULL;
1064                 g_object_unref (*contact);
1065                 *contact = NULL;
1066                 g_propagate_error (error, local_error);
1067                 return FALSE;
1068         }
1069
1070         if (uid) {
1071                 e_contact_set (*contact, E_CONTACT_UID, uid);
1072                 g_free (uid);
1073         }
1074
1075         e_book_client_set_self (*client, *contact, NULL);
1076
1077         return TRUE;
1078 }
1079
1080 /**
1081  * e_book_client_set_self:
1082  * @client: an #EBookClient
1083  * @contact: an #EContact
1084  * @error: a #GError to set on failure
1085  *
1086  * Specify that @contact residing in @client is the #EContact that
1087  * refers to the user of the address book.
1088  *
1089  * Returns: %TRUE if successful, %FALSE otherwise.
1090  *
1091  * Since: 3.2
1092  **/
1093 gboolean
1094 e_book_client_set_self (EBookClient *client,
1095                         EContact *contact,
1096                         GError **error)
1097 {
1098         GSettings *settings;
1099
1100         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1101         g_return_val_if_fail (contact != NULL, FALSE);
1102         g_return_val_if_fail (e_contact_get_const (contact, E_CONTACT_UID) != NULL, FALSE);
1103
1104         settings = g_settings_new (SELF_UID_PATH_ID);
1105         g_settings_set_string (settings, SELF_UID_KEY, e_contact_get_const (contact, E_CONTACT_UID));
1106         g_object_unref (settings);
1107
1108         return TRUE;
1109 }
1110
1111 /**
1112  * e_book_client_is_self:
1113  * @contact: an #EContact
1114  *
1115  * Check if @contact is the user of the address book.
1116  *
1117  * Returns: %TRUE if @contact is the user, %FALSE otherwise.
1118  *
1119  * Since: 3.2
1120  **/
1121 gboolean
1122 e_book_client_is_self (EContact *contact)
1123 {
1124         GSettings *settings;
1125         gchar *uid;
1126         gboolean is_self;
1127
1128         g_return_val_if_fail (contact && E_IS_CONTACT (contact), FALSE);
1129
1130         settings = g_settings_new (SELF_UID_PATH_ID);
1131         uid = g_settings_get_string (settings, SELF_UID_KEY);
1132         g_object_unref (settings);
1133
1134         is_self = uid && !g_strcmp0 (uid, e_contact_get_const (contact, E_CONTACT_UID));
1135
1136         g_free (uid);
1137
1138         return is_self;
1139 }
1140
1141 /**
1142  * e_book_client_add_contact:
1143  * @client: an #EBookClient
1144  * @contact: an #EContact
1145  * @cancellable: a #GCancellable; can be %NULL
1146  * @callback: callback to call when a result is ready
1147  * @user_data: user data for the @callback
1148  *
1149  * Adds @contact to @client.
1150  * The call is finished by e_book_client_add_contact_finish()
1151  * from the @callback.
1152  *
1153  * Since: 3.2
1154  **/
1155 void
1156 e_book_client_add_contact (EBookClient *client,
1157                            /* const */ EContact *contact,
1158                            GCancellable *cancellable,
1159                            GAsyncReadyCallback callback,
1160                            gpointer user_data)
1161 {
1162         gchar *vcard, *gdbus_vcard = NULL;
1163         const gchar *strv[2];
1164
1165         g_return_if_fail (contact != NULL);
1166         g_return_if_fail (E_IS_CONTACT (contact));
1167
1168         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1169         strv[0] = e_util_ensure_gdbus_string (vcard, &gdbus_vcard);
1170         strv[1] = NULL;
1171
1172         g_return_if_fail (strv[0] != NULL);
1173
1174         e_client_proxy_call_strv (
1175                 E_CLIENT (client),
1176                 strv, cancellable, callback, user_data,
1177                 e_book_client_add_contact,
1178                 e_gdbus_book_call_add_contacts,
1179                 NULL, NULL, NULL,
1180                 e_gdbus_book_call_add_contacts_finish,
1181                 NULL);
1182
1183         g_free (vcard);
1184         g_free (gdbus_vcard);
1185 }
1186
1187 /**
1188  * e_book_client_add_contact_finish:
1189  * @client: an #EBookClient
1190  * @result: a #GAsyncResult
1191  * @added_uid: (out): UID of a newly added contact; can be %NULL
1192  * @error: (out): a #GError to set an error, if any
1193  *
1194  * Finishes previous call of e_book_client_add_contact() and
1195  * sets @added_uid to a UID of a newly added contact.
1196  * This string should be freed with g_free().
1197  *
1198  * Note: This is not modifying original #EContact.
1199  *
1200  * Returns: %TRUE if successful, %FALSE otherwise.
1201  *
1202  * Since: 3.2
1203  **/
1204 gboolean
1205 e_book_client_add_contact_finish (EBookClient *client,
1206                                   GAsyncResult *result,
1207                                   gchar **added_uid,
1208                                   GError **error)
1209 {
1210         gboolean res;
1211         gchar **out_uids = NULL;
1212
1213         res = e_client_proxy_call_finish_strv (
1214                 E_CLIENT (client), result, &out_uids, error,
1215                 e_book_client_add_contact);
1216
1217         if (res && out_uids && added_uid) {
1218                 *added_uid = g_strdup (out_uids[0]);
1219         } else {
1220                 if (added_uid)
1221                         *added_uid = NULL;
1222         }
1223         g_strfreev (out_uids);
1224
1225         return res;
1226 }
1227
1228 /**
1229  * e_book_client_add_contact_sync:
1230  * @client: an #EBookClient
1231  * @contact: an #EContact
1232  * @added_uid: (out): UID of a newly added contact; can be %NULL
1233  * @cancellable: a #GCancellable; can be %NULL
1234  * @error: (out): a #GError to set an error, if any
1235  *
1236  * Adds @contact to @client and
1237  * sets @added_uid to a UID of a newly added contact.
1238  * This string should be freed with g_free().
1239  *
1240  * Note: This is not modifying original @contact, thus if it's needed,
1241  * then use e_contact_set (contact, E_CONTACT_UID, new_uid).
1242  *
1243  * Returns: %TRUE if successful, %FALSE otherwise.
1244  *
1245  * Since: 3.2
1246  **/
1247 gboolean
1248 e_book_client_add_contact_sync (EBookClient *client,
1249                                 /* const */ EContact *contact,
1250                                 gchar **added_uid,
1251                                 GCancellable *cancellable,
1252                                 GError **error)
1253 {
1254         gboolean res;
1255         gchar *vcard, *gdbus_vcard = NULL, **out_uids = NULL;
1256         const gchar *strv[2];
1257
1258         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1259
1260         if (client->priv->dbus_proxy == NULL) {
1261                 set_proxy_gone_error (error);
1262                 return FALSE;
1263         }
1264
1265         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1266         strv[0] = e_util_ensure_gdbus_string (vcard, &gdbus_vcard);
1267         strv[1] = NULL;
1268
1269         g_return_val_if_fail (strv[0] != NULL, FALSE);
1270
1271         res = e_client_proxy_call_sync_strv__strv (
1272                 E_CLIENT (client), strv, &out_uids, cancellable, error,
1273                 e_gdbus_book_call_add_contacts_sync);
1274
1275         if (res && out_uids && added_uid) {
1276                 *added_uid = g_strdup (out_uids[0]);
1277         } else {
1278                 if (added_uid)
1279                         *added_uid = NULL;
1280         }
1281
1282         g_strfreev (out_uids);
1283         g_free (vcard);
1284         g_free (gdbus_vcard);
1285
1286         return res;
1287 }
1288
1289 /**
1290  * e_book_client_add_contacts:
1291  * @client: an #EBookClient
1292  * @contacts: (element-type EContact): a #GSList of #EContact objects to add
1293  * @cancellable: (allow-none): a #GCancellable; can be %NULL
1294  * @callback: callback to call when a result is ready
1295  * @user_data: user data for the @callback
1296  *
1297  * Adds @contacts to @client.
1298  * The call is finished by e_book_client_add_contacts_finish()
1299  * from the @callback.
1300  *
1301  * Since: 3.4
1302  **/
1303 void
1304 e_book_client_add_contacts (EBookClient *client,
1305                             /* const */ GSList *contacts,
1306                             GCancellable *cancellable,
1307                             GAsyncReadyCallback callback,
1308                             gpointer user_data)
1309 {
1310         gchar **array;
1311
1312         g_return_if_fail (contacts != NULL);
1313
1314         array = contact_slist_to_utf8_vcard_array (contacts);
1315
1316         e_client_proxy_call_strv (
1317                 E_CLIENT (client),
1318                 (const gchar * const *) array,
1319                 cancellable, callback, user_data,
1320                 e_book_client_add_contacts,
1321                 e_gdbus_book_call_add_contacts,
1322                 NULL, NULL, NULL,
1323                 e_gdbus_book_call_add_contacts_finish,
1324                 NULL);
1325
1326         g_strfreev (array);
1327 }
1328
1329 /**
1330  * e_book_client_add_contacts_finish:
1331  * @client: an #EBookClient
1332  * @result: a #GAsyncResult
1333  * @added_uids: (out) (element-type utf8) (allow-none): UIDs of newly added
1334  * contacts; can be %NULL
1335  * @error: (out): a #GError to set an error, if any
1336  *
1337  * Finishes previous call of e_book_client_add_contacts() and
1338  * sets @added_uids to the UIDs of newly added contacts if successful.
1339  * This #GSList should be freed with e_client_util_free_string_slist().
1340  *
1341  * If any of the contacts cannot be inserted, all of the insertions will be
1342  * reverted and this method will return %FALSE.
1343  *
1344  * Note: This is not modifying original #EContact objects.
1345  *
1346  * Returns: %TRUE if successful, %FALSE otherwise.
1347  *
1348  * Since: 3.4
1349  **/
1350 gboolean
1351 e_book_client_add_contacts_finish (EBookClient *client,
1352                                    GAsyncResult *result,
1353                                    GSList **added_uids,
1354                                    GError **error)
1355 {
1356         gboolean res;
1357         gchar **out_uids = NULL;
1358
1359         res = e_client_proxy_call_finish_strv (
1360                 E_CLIENT (client), result, &out_uids, error,
1361                 e_book_client_add_contacts);
1362
1363         if (res && out_uids && added_uids) {
1364                 *added_uids = e_client_util_strv_to_slist ((const gchar * const*) out_uids);
1365         } else {
1366                 if (added_uids)
1367                         *added_uids = NULL;
1368         }
1369
1370         g_strfreev (out_uids);
1371
1372         return res;
1373 }
1374
1375 /**
1376  * e_book_client_add_contacts_sync:
1377  * @client: an #EBookClient
1378  * @contacts: (element-type EContact): a #GSList of #EContact objects to add
1379  * @added_uids: (out) (element-type utf8) (allow-none): UIDs of newly added
1380  * contacts; can be %NULL
1381  * @cancellable: a #GCancellable; can be %NULL
1382  * @error: (out): a #GError to set an error, if any
1383  *
1384  * Adds @contacts to @client and
1385  * sets @added_uids to the UIDs of newly added contacts if successful.
1386  * This #GSList should be freed with e_client_util_free_string_slist().
1387  *
1388  * If any of the contacts cannot be inserted, all of the insertions will be
1389  * reverted and this method will return %FALSE.
1390  *
1391  * Note: This is not modifying original @contacts, thus if it's needed,
1392  * then use e_contact_set (contact, E_CONTACT_UID, new_uid).
1393  *
1394  * Returns: %TRUE if successful, %FALSE otherwise.
1395  *
1396  * Since: 3.4
1397  **/
1398 gboolean
1399 e_book_client_add_contacts_sync (EBookClient *client,
1400                                  /* const */ GSList *contacts,
1401                                  GSList **added_uids,
1402                                  GCancellable *cancellable,
1403                                  GError **error)
1404 {
1405         gboolean res;
1406         gchar **array, **out_uids = NULL;
1407
1408         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1409
1410         if (client->priv->dbus_proxy == NULL) {
1411                 set_proxy_gone_error (error);
1412                 return FALSE;
1413         }
1414
1415         array = contact_slist_to_utf8_vcard_array (contacts);
1416
1417         res = e_client_proxy_call_sync_strv__strv (
1418                 E_CLIENT (client),
1419                 (const gchar * const *) array,
1420                 &out_uids, cancellable, error,
1421                 e_gdbus_book_call_add_contacts_sync);
1422
1423         if (res && out_uids && added_uids) {
1424                 *added_uids = e_client_util_strv_to_slist ((const gchar * const*) out_uids);
1425         } else {
1426                 if (added_uids)
1427                         *added_uids = NULL;
1428         }
1429
1430         g_strfreev (out_uids);
1431         g_strfreev (array);
1432
1433         return res;
1434 }
1435
1436 /**
1437  * e_book_client_modify_contact:
1438  * @client: an #EBookClient
1439  * @contact: an #EContact
1440  * @cancellable: a #GCancellable; can be %NULL
1441  * @callback: callback to call when a result is ready
1442  * @user_data: user data for the @callback
1443  *
1444  * Applies the changes made to @contact to the stored version in @client.
1445  * The call is finished by e_book_client_modify_contact_finish()
1446  * from the @callback.
1447  *
1448  * Since: 3.2
1449  **/
1450 void
1451 e_book_client_modify_contact (EBookClient *client,
1452                               /* const */ EContact *contact,
1453                               GCancellable *cancellable,
1454                               GAsyncReadyCallback callback,
1455                               gpointer user_data)
1456 {
1457         gchar *vcard, *gdbus_vcard = NULL;
1458         const gchar *strv[2];
1459
1460         g_return_if_fail (contact != NULL);
1461         g_return_if_fail (E_IS_CONTACT (contact));
1462
1463         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1464         strv[0] = e_util_ensure_gdbus_string (vcard, &gdbus_vcard);
1465         strv[1] = NULL;
1466
1467         g_return_if_fail (strv[0] != NULL);
1468
1469         e_client_proxy_call_strv (
1470                 E_CLIENT (client),
1471                 strv, cancellable, callback, user_data,
1472                 e_book_client_modify_contact,
1473                 e_gdbus_book_call_modify_contacts,
1474                 e_gdbus_book_call_modify_contacts_finish,
1475                 NULL, NULL, NULL, NULL);
1476
1477         g_free (vcard);
1478         g_free (gdbus_vcard);
1479 }
1480
1481 /**
1482  * e_book_client_modify_contact_finish:
1483  * @client: an #EBookClient
1484  * @result: a #GAsyncResult
1485  * @error: (out): a #GError to set an error, if any
1486  *
1487  * Finishes previous call of e_book_client_modify_contact().
1488  *
1489  * Returns: %TRUE if successful, %FALSE otherwise.
1490  *
1491  * Since: 3.2
1492  **/
1493 gboolean
1494 e_book_client_modify_contact_finish (EBookClient *client,
1495                                      GAsyncResult *result,
1496                                      GError **error)
1497 {
1498         return e_client_proxy_call_finish_void (
1499                 E_CLIENT (client), result, error,
1500                 e_book_client_modify_contact);
1501 }
1502
1503 /**
1504  * e_book_client_modify_contact_sync:
1505  * @client: an #EBookClient
1506  * @contact: an #EContact
1507  * @cancellable: a #GCancellable; can be %NULL
1508  * @error: (out): a #GError to set an error, if any
1509  *
1510  * Applies the changes made to @contact to the stored version in @client.
1511  *
1512  * Returns: %TRUE if successful, %FALSE otherwise.
1513  *
1514  * Since: 3.2
1515  **/
1516 gboolean
1517 e_book_client_modify_contact_sync (EBookClient *client,
1518                                    /* const */ EContact *contact,
1519                                    GCancellable *cancellable,
1520                                    GError **error)
1521 {
1522         gboolean res;
1523         gchar *vcard, *gdbus_vcard = NULL;
1524         const gchar *strv[2];
1525
1526         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1527
1528         if (client->priv->dbus_proxy == NULL) {
1529                 set_proxy_gone_error (error);
1530                 return FALSE;
1531         }
1532
1533         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1534         strv[0] = e_util_ensure_gdbus_string (vcard, &gdbus_vcard);
1535         strv[1] = NULL;
1536
1537         g_return_val_if_fail (strv[0] != NULL, FALSE);
1538
1539         res = e_client_proxy_call_sync_strv__void (
1540                 E_CLIENT (client),
1541                 strv, cancellable, error,
1542                 e_gdbus_book_call_modify_contacts_sync);
1543
1544         g_free (vcard);
1545         g_free (gdbus_vcard);
1546
1547         return res;
1548 }
1549
1550 /**
1551  * e_book_client_modify_contacts:
1552  * @client: an #EBookClient
1553  * @contacts: (element-type EContact): a #GSList of #EContact objects
1554  * @cancellable: (allow-none): a #GCancellable; can be %NULL
1555  * @callback: callback to call when a result is ready
1556  * @user_data: user data for the @callback
1557  *
1558  * Applies the changes made to @contacts to the stored versions in @client.
1559  * The call is finished by e_book_client_modify_contacts_finish()
1560  * from the @callback.
1561  *
1562  * Since: 3.4
1563  **/
1564 void
1565 e_book_client_modify_contacts (EBookClient *client,
1566                                /* const */ GSList *contacts,
1567                                GCancellable *cancellable,
1568                                GAsyncReadyCallback callback,
1569                                gpointer user_data)
1570 {
1571         gchar **array;
1572
1573         g_return_if_fail (contacts != NULL);
1574
1575         array = contact_slist_to_utf8_vcard_array (contacts);
1576
1577         e_client_proxy_call_strv (
1578                 E_CLIENT (client),
1579                 (const gchar * const *) array,
1580                 cancellable, callback, user_data,
1581                 e_book_client_modify_contacts,
1582                 e_gdbus_book_call_modify_contacts,
1583                 e_gdbus_book_call_modify_contacts_finish,
1584                 NULL, NULL, NULL, NULL);
1585
1586         g_strfreev (array);
1587 }
1588
1589 /**
1590  * e_book_client_modify_contacts_finish:
1591  * @client: an #EBookClient
1592  * @result: a #GAsyncResult
1593  * @error: (out): a #GError to set an error, if any
1594  *
1595  * Finishes previous call of e_book_client_modify_contacts().
1596  *
1597  * Returns: %TRUE if successful, %FALSE otherwise.
1598  *
1599  * Since: 3.4
1600  **/
1601 gboolean
1602 e_book_client_modify_contacts_finish (EBookClient *client,
1603                                       GAsyncResult *result,
1604                                       GError **error)
1605 {
1606         return e_client_proxy_call_finish_void (
1607                 E_CLIENT (client), result, error,
1608                 e_book_client_modify_contacts);
1609 }
1610
1611 /**
1612  * e_book_client_modify_contacts_sync:
1613  * @client: an #EBookClient
1614  * @contacts: (element-type EContact): a #GSList of #EContact objects
1615  * @cancellable: (allow-none): a #GCancellable; can be %NULL
1616  * @error: (out): a #GError to set an error, if any
1617  *
1618  * Applies the changes made to @contacts to the stored versions in @client.
1619  *
1620  * Returns: %TRUE if successful, %FALSE otherwise.
1621  *
1622  * Since: 3.4
1623  **/
1624 gboolean
1625 e_book_client_modify_contacts_sync (EBookClient *client,
1626                                     /* const */ GSList *contacts,
1627                                     GCancellable *cancellable,
1628                                     GError **error)
1629 {
1630         gboolean res;
1631         gchar **array;
1632
1633         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1634         g_return_val_if_fail (contacts != NULL, FALSE);
1635
1636         if (client->priv->dbus_proxy == NULL) {
1637                 set_proxy_gone_error (error);
1638                 return FALSE;
1639         }
1640
1641         array = contact_slist_to_utf8_vcard_array (contacts);
1642
1643         res = e_client_proxy_call_sync_strv__void (
1644                 E_CLIENT (client),
1645                 (const gchar * const *) array,
1646                 cancellable, error,
1647                 e_gdbus_book_call_modify_contacts_sync);
1648
1649         g_strfreev (array);
1650
1651         return res;
1652 }
1653
1654 /**
1655  * e_book_client_remove_contact:
1656  * @client: an #EBookClient
1657  * @contact: an #EContact
1658  * @cancellable: a #GCancellable; can be %NULL
1659  * @callback: callback to call when a result is ready
1660  * @user_data: user data for the @callback
1661  *
1662  * Removes @contact from the @client.
1663  * The call is finished by e_book_client_remove_contact_finish()
1664  * from the @callback.
1665  *
1666  * Since: 3.2
1667  **/
1668 void
1669 e_book_client_remove_contact (EBookClient *client,
1670                               /* const */ EContact *contact,
1671                               GCancellable *cancellable,
1672                               GAsyncReadyCallback callback,
1673                               gpointer user_data)
1674 {
1675         const gchar *uid, *safe_uid;
1676         const gchar *strv[2];
1677         gchar *gdbus_uid = NULL;
1678
1679         g_return_if_fail (contact != NULL);
1680         g_return_if_fail (E_IS_CONTACT (contact));
1681
1682         uid = e_contact_get_const ( E_CONTACT (contact), E_CONTACT_UID);
1683         g_return_if_fail (uid != NULL);
1684
1685         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
1686         g_return_if_fail (safe_uid != NULL);
1687
1688         strv[0] = safe_uid;
1689         strv[1] = NULL;
1690
1691         e_client_proxy_call_strv (
1692                 E_CLIENT (client),
1693                 strv, cancellable, callback, user_data,
1694                 e_book_client_remove_contact,
1695                 e_gdbus_book_call_remove_contacts,
1696                 e_gdbus_book_call_remove_contacts_finish,
1697                 NULL, NULL, NULL, NULL);
1698
1699         g_free (gdbus_uid);
1700 }
1701
1702 /**
1703  * e_book_client_remove_contact_finish:
1704  * @client: an #EBookClient
1705  * @result: a #GAsyncResult
1706  * @error: (out): a #GError to set an error, if any
1707  *
1708  * Finishes previous call of e_book_client_remove_contact().
1709  *
1710  * Returns: %TRUE if successful, %FALSE otherwise.
1711  *
1712  * Since: 3.2
1713  **/
1714 gboolean
1715 e_book_client_remove_contact_finish (EBookClient *client,
1716                                      GAsyncResult *result,
1717                                      GError **error)
1718 {
1719         return e_client_proxy_call_finish_void (
1720                 E_CLIENT (client), result, error,
1721                 e_book_client_remove_contact);
1722 }
1723
1724 /**
1725  * e_book_client_remove_contact_sync:
1726  * @client: an #EBookClient
1727  * @contact: an #EContact
1728  * @cancellable: a #GCancellable; can be %NULL
1729  * @error: (out): a #GError to set an error, if any
1730  *
1731  * Removes @contact from the @client.
1732  *
1733  * Returns: %TRUE if successful, %FALSE otherwise.
1734  *
1735  * Since: 3.2
1736  **/
1737 gboolean
1738 e_book_client_remove_contact_sync (EBookClient *client,
1739                                    /* const */ EContact *contact,
1740                                    GCancellable *cancellable,
1741                                    GError **error)
1742 {
1743         gboolean res;
1744         const gchar *strv[2];
1745         const gchar *uid, *safe_uid;
1746         gchar *gdbus_uid = NULL;
1747
1748         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1749         g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
1750
1751         if (client->priv->dbus_proxy == NULL) {
1752                 set_proxy_gone_error (error);
1753                 return FALSE;
1754         }
1755
1756         uid = e_contact_get_const (E_CONTACT (contact), E_CONTACT_UID);
1757         g_return_val_if_fail (uid != NULL, FALSE);
1758
1759         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
1760         g_return_val_if_fail (safe_uid != NULL, FALSE);
1761
1762         strv[0] = safe_uid;
1763         strv[1] = NULL;
1764
1765         res = e_client_proxy_call_sync_strv__void (
1766                 E_CLIENT (client),
1767                 strv, cancellable, error,
1768                 e_gdbus_book_call_remove_contacts_sync);
1769
1770         g_free (gdbus_uid);
1771
1772         return res;
1773 }
1774
1775 /**
1776  * e_book_client_remove_contact_by_uid:
1777  * @client: an #EBookClient
1778  * @uid: a UID of a contact to remove
1779  * @cancellable: a #GCancellable; can be %NULL
1780  * @callback: callback to call when a result is ready
1781  * @user_data: user data for the @callback
1782  *
1783  * Removes contact with @uid from the @client.
1784  * The call is finished by e_book_client_remove_contact_by_uid_finish()
1785  * from the @callback.
1786  *
1787  * Since: 3.2
1788  **/
1789 void
1790 e_book_client_remove_contact_by_uid (EBookClient *client,
1791                                      const gchar *uid,
1792                                      GCancellable *cancellable,
1793                                      GAsyncReadyCallback callback,
1794                                      gpointer user_data)
1795 {
1796         const gchar *safe_uid;
1797         gchar *gdbus_uid = NULL;
1798         const gchar *strv[2];
1799
1800         g_return_if_fail (uid != NULL);
1801
1802         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
1803         g_return_if_fail (safe_uid != NULL);
1804
1805         strv[0] = safe_uid;
1806         strv[1] = NULL;
1807
1808         e_client_proxy_call_strv (
1809                 E_CLIENT (client),
1810                 strv, cancellable, callback, user_data,
1811                 e_book_client_remove_contact_by_uid,
1812                 e_gdbus_book_call_remove_contacts,
1813                 e_gdbus_book_call_remove_contacts_finish,
1814                 NULL, NULL, NULL, NULL);
1815
1816         g_free (gdbus_uid);
1817 }
1818
1819 /**
1820  * e_book_client_remove_contact_by_uid_finish:
1821  * @client: an #EBookClient
1822  * @result: a #GAsyncResult
1823  * @error: (out): a #GError to set an error, if any
1824  *
1825  * Finishes previous call of e_book_client_remove_contact_by_uid().
1826  *
1827  * Returns: %TRUE if successful, %FALSE otherwise.
1828  *
1829  * Since: 3.2
1830  **/
1831 gboolean
1832 e_book_client_remove_contact_by_uid_finish (EBookClient *client,
1833                                             GAsyncResult *result,
1834                                             GError **error)
1835 {
1836         return e_client_proxy_call_finish_void (
1837                 E_CLIENT (client), result, error,
1838                 e_book_client_remove_contact_by_uid);
1839 }
1840
1841 /**
1842  * e_book_client_remove_contact_by_uid_sync:
1843  * @client: an #EBookClient
1844  * @uid: a UID of a contact to remove
1845  * @cancellable: a #GCancellable; can be %NULL
1846  * @error: (out): a #GError to set an error, if any
1847  *
1848  * Removes contact with @uid from the @client.
1849  *
1850  * Returns: %TRUE if successful, %FALSE otherwise.
1851  *
1852  * Since: 3.2
1853  **/
1854 gboolean
1855 e_book_client_remove_contact_by_uid_sync (EBookClient *client,
1856                                           const gchar *uid,
1857                                           GCancellable *cancellable,
1858                                           GError **error)
1859 {
1860         gboolean res;
1861         const gchar *safe_uid;
1862         gchar *gdbus_uid = NULL;
1863         const gchar *strv[2];
1864
1865         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1866         g_return_val_if_fail (uid != NULL, FALSE);
1867
1868         if (client->priv->dbus_proxy == NULL) {
1869                 set_proxy_gone_error (error);
1870                 return FALSE;
1871         }
1872
1873         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
1874         g_return_val_if_fail (safe_uid != NULL, FALSE);
1875
1876         strv[0] = safe_uid;
1877         strv[1] = NULL;
1878
1879         res = e_client_proxy_call_sync_strv__void (
1880                 E_CLIENT (client), strv, cancellable, error,
1881                 e_gdbus_book_call_remove_contacts_sync);
1882
1883         g_free (gdbus_uid);
1884
1885         return res;
1886 }
1887
1888 /**
1889  * e_book_client_remove_contacts:
1890  * @client: an #EBookClient
1891  * @uids: (element-type utf8): a #GSList of UIDs to remove
1892  * @cancellable: a #GCancellable; can be %NULL
1893  * @callback: callback to call when a result is ready
1894  * @user_data: user data for the @callback
1895  *
1896  * Removes the contacts with uids from the list @uids from @client.  This is
1897  * always more efficient than calling e_book_client_remove_contact() if you
1898  * have more than one uid to remove, as some backends can implement it
1899  * as a batch request.
1900  * The call is finished by e_book_client_remove_contacts_finish()
1901  * from the @callback.
1902  *
1903  * Since: 3.2
1904  **/
1905 void
1906 e_book_client_remove_contacts (EBookClient *client,
1907                                const GSList *uids,
1908                                GCancellable *cancellable,
1909                                GAsyncReadyCallback callback,
1910                                gpointer user_data)
1911 {
1912         gchar **strv;
1913
1914         g_return_if_fail (uids != NULL);
1915
1916         strv = e_client_util_slist_to_strv (uids);
1917         g_return_if_fail (strv != NULL);
1918
1919         e_client_proxy_call_strv (
1920                 E_CLIENT (client),
1921                 (const gchar * const *) strv,
1922                 cancellable, callback, user_data,
1923                 e_book_client_remove_contacts,
1924                 e_gdbus_book_call_remove_contacts,
1925                 e_gdbus_book_call_remove_contacts_finish,
1926                 NULL, NULL, NULL, NULL);
1927
1928         g_strfreev (strv);
1929 }
1930
1931 /**
1932  * e_book_client_remove_contacts_finish:
1933  * @client: an #EBookClient
1934  * @result: a #GAsyncResult
1935  * @error: (out): a #GError to set an error, if any
1936  *
1937  * Finishes previous call of e_book_client_remove_contacts().
1938  *
1939  * Returns: %TRUE if successful, %FALSE otherwise.
1940  *
1941  * Since: 3.2
1942  **/
1943 gboolean
1944 e_book_client_remove_contacts_finish (EBookClient *client,
1945                                       GAsyncResult *result,
1946                                       GError **error)
1947 {
1948         return e_client_proxy_call_finish_void (
1949                 E_CLIENT (client), result, error,
1950                 e_book_client_remove_contacts);
1951 }
1952
1953 /**
1954  * e_book_client_remove_contacts_sync:
1955  * @client: an #EBookClient
1956  * @uids: (element-type utf8): a #GSList of UIDs to remove
1957  * @cancellable: a #GCancellable; can be %NULL
1958  * @error: (out): a #GError to set an error, if any
1959  *
1960  * Removes the contacts with uids from the list @uids from @client.  This is
1961  * always more efficient than calling e_book_client_remove_contact() if you
1962  * have more than one uid to remove, as some backends can implement it
1963  * as a batch request.
1964  *
1965  * Returns: %TRUE if successful, %FALSE otherwise.
1966  *
1967  * Since: 3.2
1968  **/
1969 gboolean
1970 e_book_client_remove_contacts_sync (EBookClient *client,
1971                                     const GSList *uids,
1972                                     GCancellable *cancellable,
1973                                     GError **error)
1974 {
1975         gboolean res;
1976         gchar **strv;
1977
1978         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
1979         g_return_val_if_fail (uids != NULL, FALSE);
1980
1981         if (client->priv->dbus_proxy == NULL) {
1982                 set_proxy_gone_error (error);
1983                 return FALSE;
1984         }
1985
1986         strv = e_client_util_slist_to_strv (uids);
1987         g_return_val_if_fail (strv != NULL, FALSE);
1988
1989         res = e_client_proxy_call_sync_strv__void (
1990                 E_CLIENT (client), (const gchar * const *) strv,
1991                 cancellable, error,
1992                 e_gdbus_book_call_remove_contacts_sync);
1993
1994         g_strfreev (strv);
1995
1996         return res;
1997 }
1998
1999 /**
2000  * e_book_client_get_contact:
2001  * @client: an #EBookClient
2002  * @uid: a unique string ID specifying the contact
2003  * @cancellable: a #GCancellable; can be %NULL
2004  * @callback: callback to call when a result is ready
2005  * @user_data: user data for the @callback
2006  *
2007  * Receive #EContact from the @client for the gived @uid.
2008  * The call is finished by e_book_client_get_contact_finish()
2009  * from the @callback.
2010  *
2011  * Since: 3.2
2012  **/
2013 void
2014 e_book_client_get_contact (EBookClient *client,
2015                            const gchar *uid,
2016                            GCancellable *cancellable,
2017                            GAsyncReadyCallback callback,
2018                            gpointer user_data)
2019 {
2020         const gchar *safe_uid;
2021         gchar *gdbus_uid = NULL;
2022
2023         g_return_if_fail (uid != NULL);
2024
2025         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
2026         g_return_if_fail (safe_uid != NULL);
2027
2028         e_client_proxy_call_string (
2029                 E_CLIENT (client),
2030                 safe_uid, cancellable, callback, user_data,
2031                 e_book_client_get_contact,
2032                 e_gdbus_book_call_get_contact,
2033                 NULL, NULL,
2034                 e_gdbus_book_call_get_contact_finish,
2035                 NULL, NULL);
2036
2037         g_free (gdbus_uid);
2038 }
2039
2040 /**
2041  * e_book_client_get_contact_finish:
2042  * @client: an #EBookClient
2043  * @result: a #GAsyncResult
2044  * @contact: (out): an #EContact for previously given uid
2045  * @error: (out): a #GError to set an error, if any
2046  *
2047  * Finishes previous call of e_book_client_get_contact().
2048  * If successful, then the @contact is set to newly allocated
2049  * #EContact, which should be freed with g_object_unref().
2050  *
2051  * Returns: %TRUE if successful, %FALSE otherwise.
2052  *
2053  * Since: 3.2
2054  **/
2055 gboolean
2056 e_book_client_get_contact_finish (EBookClient *client,
2057                                   GAsyncResult *result,
2058                                   EContact **contact,
2059                                   GError **error)
2060 {
2061         gboolean res;
2062         gchar *vcard = NULL;
2063
2064         g_return_val_if_fail (contact != NULL, FALSE);
2065
2066         res = e_client_proxy_call_finish_string (
2067                 E_CLIENT (client),
2068                 result, &vcard, error,
2069                 e_book_client_get_contact);
2070
2071         if (vcard && res)
2072                 *contact = e_contact_new_from_vcard (vcard);
2073         else
2074                 *contact = NULL;
2075
2076         g_free (vcard);
2077
2078         return res;
2079 }
2080
2081 /**
2082  * e_book_client_get_contact_sync:
2083  * @client: an #EBookClient
2084  * @uid: a unique string ID specifying the contact
2085  * @contact: (out): an #EContact for given @uid
2086  * @cancellable: a #GCancellable; can be %NULL
2087  * @error: (out): a #GError to set an error, if any
2088  *
2089  * Receive #EContact from the @client for the gived @uid.
2090  * If successful, then the @contact is set to newly allocated
2091  * #EContact, which should be freed with g_object_unref().
2092  *
2093  * Returns: %TRUE if successful, %FALSE otherwise.
2094  *
2095  * Since: 3.2
2096  **/
2097 gboolean
2098 e_book_client_get_contact_sync (EBookClient *client,
2099                                 const gchar *uid,
2100                                 EContact **contact,
2101                                 GCancellable *cancellable,
2102                                 GError **error)
2103 {
2104         gboolean res;
2105         const gchar *safe_uid;
2106         gchar *vcard = NULL, *gdbus_uid = NULL;
2107
2108         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
2109         g_return_val_if_fail (uid != NULL, FALSE);
2110         g_return_val_if_fail (contact != NULL, FALSE);
2111
2112         if (client->priv->dbus_proxy == NULL) {
2113                 set_proxy_gone_error (error);
2114                 return FALSE;
2115         }
2116
2117         safe_uid = e_util_ensure_gdbus_string (uid, &gdbus_uid);
2118         g_return_val_if_fail (safe_uid != NULL, FALSE);
2119
2120         res = e_client_proxy_call_sync_string__string (
2121                 E_CLIENT (client),
2122                 safe_uid, &vcard, cancellable, error,
2123                 e_gdbus_book_call_get_contact_sync);
2124
2125         if (vcard && res)
2126                 *contact = e_contact_new_from_vcard_with_uid (vcard, safe_uid);
2127         else
2128                 *contact = NULL;
2129
2130         g_free (gdbus_uid);
2131         g_free (vcard);
2132
2133         return res;
2134 }
2135
2136 /**
2137  * e_book_client_get_contacts:
2138  * @client: an #EBookClient
2139  * @sexp: an S-expression representing the query
2140  * @cancellable: a #GCancellable; can be %NULL
2141  * @callback: callback to call when a result is ready
2142  * @user_data: user data for the @callback
2143  *
2144  * Query @client with @sexp, receiving a list of contacts which
2145  * matched. The call is finished by e_book_client_get_contacts_finish()
2146  * from the @callback.
2147  *
2148  * Note: @sexp can be obtained through #EBookQuery, by converting it
2149  * to a string with e_book_query_to_string().
2150  *
2151  * Since: 3.2
2152  **/
2153 void
2154 e_book_client_get_contacts (EBookClient *client,
2155                             const gchar *sexp,
2156                             GCancellable *cancellable,
2157                             GAsyncReadyCallback callback,
2158                             gpointer user_data)
2159 {
2160         gchar *gdbus_sexp = NULL;
2161
2162         g_return_if_fail (sexp != NULL);
2163
2164         e_client_proxy_call_string (
2165                 E_CLIENT (client),
2166                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2167                 cancellable, callback, user_data,
2168                 e_book_client_get_contacts,
2169                 e_gdbus_book_call_get_contact_list,
2170                 NULL, NULL, NULL,
2171                 e_gdbus_book_call_get_contact_list_finish,
2172                 NULL);
2173
2174         g_free (gdbus_sexp);
2175 }
2176
2177 /**
2178  * e_book_client_get_contacts_finish:
2179  * @client: an #EBookClient
2180  * @result: a #GAsyncResult
2181  * @contacts: (element-type EContact) (out): a #GSList of matched #EContact-s
2182  * @error: (out): a #GError to set an error, if any
2183  *
2184  * Finishes previous call of e_book_client_get_contacts().
2185  * If successful, then the @contacts is set to newly allocated list of #EContact-s,
2186  * which should be freed with e_client_util_free_object_slist().
2187  *
2188  * Returns: %TRUE if successful, %FALSE otherwise.
2189  *
2190  * Since: 3.2
2191  **/
2192 gboolean
2193 e_book_client_get_contacts_finish (EBookClient *client,
2194                                    GAsyncResult *result,
2195                                    GSList **contacts,
2196                                    GError **error)
2197 {
2198         gboolean res;
2199         gchar **vcards = NULL;
2200
2201         g_return_val_if_fail (contacts != NULL, FALSE);
2202
2203         res = e_client_proxy_call_finish_strv (
2204                 E_CLIENT (client),
2205                 result, &vcards, error,
2206                 e_book_client_get_contacts);
2207
2208         if (vcards && res) {
2209                 gint ii;
2210                 GSList *slist = NULL;
2211
2212                 for (ii = 0; vcards[ii]; ii++) {
2213                         slist = g_slist_prepend (slist, e_contact_new_from_vcard (vcards[ii]));
2214                 }
2215
2216                 *contacts = g_slist_reverse (slist);
2217         } else {
2218                 *contacts = NULL;
2219         }
2220
2221         g_strfreev (vcards);
2222
2223         return res;
2224 }
2225
2226 /**
2227  * e_book_client_get_contacts_sync:
2228  * @client: an #EBookClient
2229  * @sexp: an S-expression representing the query
2230  * @contacts: (element-type EContact) (out): a #GSList of matched #EContact-s
2231  * @cancellable: a #GCancellable; can be %NULL
2232  * @error: (out): a #GError to set an error, if any
2233  *
2234  * Query @client with @sexp, receiving a list of contacts which matched.
2235  * If successful, then the @contacts is set to newly allocated #GSList of
2236  * #EContact-s, which should be freed with e_client_util_free_object_slist().
2237  *
2238  * Note: @sexp can be obtained through #EBookQuery, by converting it
2239  * to a string with e_book_query_to_string().
2240  *
2241  * Returns: %TRUE if successful, %FALSE otherwise.
2242  *
2243  * Since: 3.2
2244  **/
2245 gboolean
2246 e_book_client_get_contacts_sync (EBookClient *client,
2247                                  const gchar *sexp,
2248                                  GSList **contacts,
2249                                  GCancellable *cancellable,
2250                                  GError **error)
2251 {
2252         gboolean res;
2253         gchar *gdbus_sexp = NULL;
2254         gchar **vcards = NULL;
2255
2256         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
2257         g_return_val_if_fail (sexp != NULL, FALSE);
2258         g_return_val_if_fail (contacts != NULL, FALSE);
2259
2260         if (client->priv->dbus_proxy == NULL) {
2261                 set_proxy_gone_error (error);
2262                 return FALSE;
2263         }
2264
2265         res = e_client_proxy_call_sync_string__strv (
2266                 E_CLIENT (client),
2267                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2268                 &vcards, cancellable, error,
2269                 e_gdbus_book_call_get_contact_list_sync);
2270
2271         if (vcards && res) {
2272                 gint ii;
2273                 GSList *slist = NULL;
2274
2275                 for (ii = 0; vcards[ii]; ii++) {
2276                         slist = g_slist_prepend (slist, e_contact_new_from_vcard (vcards[ii]));
2277                 }
2278
2279                 *contacts = g_slist_reverse (slist);
2280         } else {
2281                 *contacts = NULL;
2282         }
2283
2284         g_free (gdbus_sexp);
2285         g_strfreev (vcards);
2286
2287         return res;
2288 }
2289
2290 /**
2291  * e_book_client_get_contacts_uids:
2292  * @client: an #EBookClient
2293  * @sexp: an S-expression representing the query
2294  * @cancellable: a #GCancellable; can be %NULL
2295  * @callback: callback to call when a result is ready
2296  * @user_data: user data for the @callback
2297  *
2298  * Query @client with @sexp, receiving a list of contacts UIDs which
2299  * matched. The call is finished by e_book_client_get_contacts_uids_finish()
2300  * from the @callback.
2301  *
2302  * Note: @sexp can be obtained through #EBookQuery, by converting it
2303  * to a string with e_book_query_to_string().
2304  *
2305  * Since: 3.2
2306  **/
2307 void
2308 e_book_client_get_contacts_uids (EBookClient *client,
2309                                  const gchar *sexp,
2310                                  GCancellable *cancellable,
2311                                  GAsyncReadyCallback callback,
2312                                  gpointer user_data)
2313 {
2314         gchar *gdbus_sexp = NULL;
2315
2316         g_return_if_fail (sexp != NULL);
2317
2318         e_client_proxy_call_string (
2319                 E_CLIENT (client),
2320                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2321                 cancellable, callback, user_data,
2322                 e_book_client_get_contacts_uids,
2323                 e_gdbus_book_call_get_contact_list_uids,
2324                 NULL, NULL, NULL,
2325                 e_gdbus_book_call_get_contact_list_uids_finish,
2326                 NULL);
2327
2328         g_free (gdbus_sexp);
2329 }
2330
2331 /**
2332  * e_book_client_get_contacts_uids_finish:
2333  * @client: an #EBookClient
2334  * @result: a #GAsyncResult
2335  * @contacts_uids: (element-type utf8) (out): a #GSList of matched contacts UIDs stored as strings
2336  * @error: (out): a #GError to set an error, if any
2337  *
2338  * Finishes previous call of e_book_client_get_contacts_uids().
2339  * If successful, then the @contacts_uids is set to newly allocated list
2340  * of UID strings, which should be freed with e_client_util_free_string_slist().
2341  *
2342  * Returns: %TRUE if successful, %FALSE otherwise.
2343  *
2344  * Since: 3.2
2345  **/
2346 gboolean
2347 e_book_client_get_contacts_uids_finish (EBookClient *client,
2348                                         GAsyncResult *result,
2349                                         GSList **contacts_uids,
2350                                         GError **error)
2351 {
2352         gboolean res;
2353         gchar **uids = NULL;
2354
2355         g_return_val_if_fail (contacts_uids != NULL, FALSE);
2356
2357         res = e_client_proxy_call_finish_strv (
2358                 E_CLIENT (client),
2359                 result, &uids, error,
2360                 e_book_client_get_contacts_uids);
2361
2362         if (uids && res) {
2363                 gint ii;
2364                 GSList *slist = NULL;
2365
2366                 for (ii = 0; uids[ii]; ii++) {
2367                         slist = g_slist_prepend (slist, g_strdup (uids[ii]));
2368                 }
2369
2370                 *contacts_uids = g_slist_reverse (slist);
2371         } else {
2372                 *contacts_uids = NULL;
2373         }
2374
2375         g_strfreev (uids);
2376
2377         return res;
2378 }
2379
2380 /**
2381  * e_book_client_get_contacts_uids_sync:
2382  * @client: an #EBookClient
2383  * @sexp: an S-expression representing the query
2384  * @contacts_uids: (element-type utf8) (out): a #GSList of matched contacts UIDs stored as strings
2385  * @cancellable: a #GCancellable; can be %NULL
2386  * @error: (out): a #GError to set an error, if any
2387  *
2388  * Query @client with @sexp, receiving a list of contacts UIDs which matched.
2389  * If successful, then the @contacts_uids is set to newly allocated list
2390  * of UID strings, which should be freed with e_client_util_free_string_slist().
2391  *
2392  * Note: @sexp can be obtained through #EBookQuery, by converting it
2393  * to a string with e_book_query_to_string().
2394  *
2395  * Returns: %TRUE if successful, %FALSE otherwise.
2396  *
2397  * Since: 3.2
2398  **/
2399 gboolean
2400 e_book_client_get_contacts_uids_sync (EBookClient *client,
2401                                       const gchar *sexp,
2402                                       GSList **contacts_uids,
2403                                       GCancellable *cancellable,
2404                                       GError **error)
2405 {
2406         gboolean res;
2407         gchar *gdbus_sexp = NULL;
2408         gchar **uids = NULL;
2409
2410         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
2411         g_return_val_if_fail (sexp != NULL, FALSE);
2412         g_return_val_if_fail (contacts_uids != NULL, FALSE);
2413
2414         if (client->priv->dbus_proxy == NULL) {
2415                 set_proxy_gone_error (error);
2416                 return FALSE;
2417         }
2418
2419         res = e_client_proxy_call_sync_string__strv (
2420                 E_CLIENT (client),
2421                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2422                 &uids, cancellable, error,
2423                 e_gdbus_book_call_get_contact_list_uids_sync);
2424
2425         if (uids && res) {
2426                 gint ii;
2427                 GSList *slist = NULL;
2428
2429                 for (ii = 0; uids[ii]; ii++) {
2430                         slist = g_slist_prepend (slist, g_strdup (uids[ii]));
2431                 }
2432
2433                 *contacts_uids = g_slist_reverse (slist);
2434         } else {
2435                 *contacts_uids = NULL;
2436         }
2437
2438         g_free (gdbus_sexp);
2439         g_strfreev (uids);
2440
2441         return res;
2442 }
2443
2444 /**
2445  * e_book_client_get_view:
2446  * @client: an #EBookClient
2447  * @sexp: an S-expression representing the query
2448  * @cancellable: a #GCancellable; can be %NULL
2449  * @callback: callback to call when a result is ready
2450  * @user_data: user data for the @callback
2451  *
2452  * Query @client with @sexp, creating an #EBookClientView.
2453  * The call is finished by e_book_client_get_view_finish()
2454  * from the @callback.
2455  *
2456  * Note: @sexp can be obtained through #EBookQuery, by converting it
2457  * to a string with e_book_query_to_string().
2458  *
2459  * Since: 3.2
2460  **/
2461 void
2462 e_book_client_get_view (EBookClient *client,
2463                         const gchar *sexp,
2464                         GCancellable *cancellable,
2465                         GAsyncReadyCallback callback,
2466                         gpointer user_data)
2467 {
2468         gchar *gdbus_sexp = NULL;
2469
2470         g_return_if_fail (sexp != NULL);
2471
2472         e_client_proxy_call_string (
2473                 E_CLIENT (client),
2474                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2475                 cancellable, callback, user_data,
2476                 e_book_client_get_view,
2477                 e_gdbus_book_call_get_view,
2478                 NULL, NULL,
2479                 e_gdbus_book_call_get_view_finish, NULL, NULL);
2480
2481         g_free (gdbus_sexp);
2482 }
2483
2484 static gboolean
2485 complete_get_view (EBookClient *client,
2486                    gboolean res,
2487                    gchar *view_path,
2488                    EBookClientView **view,
2489                    GError **error)
2490 {
2491         g_return_val_if_fail (view != NULL, FALSE);
2492
2493         if (view_path && res && book_factory) {
2494                 GDBusConnection *connection;
2495                 GError *local_error = NULL;
2496
2497                 connection = g_dbus_proxy_get_connection (
2498                         G_DBUS_PROXY (book_factory));
2499
2500                 *view = g_initable_new (
2501                         E_TYPE_BOOK_CLIENT_VIEW,
2502                         NULL, &local_error,
2503                         "client", client,
2504                         "connection", connection,
2505                         "object-path", view_path,
2506                         NULL);
2507
2508                 if (local_error != NULL) {
2509                         unwrap_dbus_error (local_error, error);
2510                         res = FALSE;
2511                 }
2512         } else {
2513                 *view = NULL;
2514                 res = FALSE;
2515         }
2516
2517         if (!*view && error && !*error)
2518                 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
2519
2520         g_free (view_path);
2521
2522         return res;
2523 }
2524
2525 /**
2526  * e_book_client_get_view_finish:
2527  * @client: an #EBookClient
2528  * @result: a #GAsyncResult
2529  * @view: (out): an #EBookClientView
2530  * @error: (out): a #GError to set an error, if any
2531  *
2532  * Finishes previous call of e_book_client_get_view().
2533  * If successful, then the @view is set to newly allocated #EBookClientView,
2534  * which should be freed with g_object_unref().
2535  *
2536  * Returns: %TRUE if successful, %FALSE otherwise.
2537  *
2538  * Since: 3.2
2539  **/
2540 gboolean
2541 e_book_client_get_view_finish (EBookClient *client,
2542                                GAsyncResult *result,
2543                                EBookClientView **view,
2544                                GError **error)
2545 {
2546         gboolean res;
2547         gchar *view_path = NULL;
2548
2549         g_return_val_if_fail (view != NULL, FALSE);
2550
2551         res = e_client_proxy_call_finish_string (
2552                 E_CLIENT (client),
2553                 result, &view_path, error,
2554                 e_book_client_get_view);
2555
2556         return complete_get_view (client, res, view_path, view, error);
2557 }
2558
2559 /**
2560  * e_book_client_get_view_sync:
2561  * @client: an #EBookClient
2562  * @sexp: an S-expression representing the query
2563  * @view: (out) an #EBookClientView
2564  * @cancellable: a #GCancellable; can be %NULL
2565  * @error: (out): a #GError to set an error, if any
2566  *
2567  * Query @client with @sexp, creating an #EBookClientView.
2568  * If successful, then the @view is set to newly allocated #EBookClientView,
2569  * which should be freed with g_object_unref().
2570  *
2571  * Note: @sexp can be obtained through #EBookQuery, by converting it
2572  * to a string with e_book_query_to_string().
2573  *
2574  * Returns: %TRUE if successful, %FALSE otherwise.
2575  *
2576  * Since: 3.2
2577  **/
2578 gboolean
2579 e_book_client_get_view_sync (EBookClient *client,
2580                              const gchar *sexp,
2581                              EBookClientView **view,
2582                              GCancellable *cancellable,
2583                              GError **error)
2584 {
2585         gboolean res;
2586         gchar *gdbus_sexp = NULL;
2587         gchar *view_path = NULL;
2588
2589         g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
2590         g_return_val_if_fail (sexp != NULL, FALSE);
2591         g_return_val_if_fail (view != NULL, FALSE);
2592
2593         if (client->priv->dbus_proxy == NULL) {
2594                 set_proxy_gone_error (error);
2595                 return FALSE;
2596         }
2597
2598         res = e_client_proxy_call_sync_string__string (
2599                 E_CLIENT (client),
2600                 e_util_ensure_gdbus_string (sexp, &gdbus_sexp),
2601                 &view_path, cancellable, error,
2602                 e_gdbus_book_call_get_view_sync);
2603
2604         g_free (gdbus_sexp);
2605
2606         return complete_get_view (client, res, view_path, view, error);
2607 }
2608