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