EClient: Add default implementations for async virtual methods.
[platform/upstream/evolution-data-server.git] / libedataserver / e-client.c
1 /*
2  * e-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/e-data-server-util.h>
30
31 #include "e-gdbus-marshallers.h"
32
33 #include "e-client.h"
34 #include "e-client-private.h"
35
36 #define E_CLIENT_GET_PRIVATE(obj) \
37         (G_TYPE_INSTANCE_GET_PRIVATE \
38         ((obj), E_TYPE_CLIENT, EClientPrivate))
39
40 typedef struct _AsyncContext AsyncContext;
41
42 struct _EClientPrivate {
43         GRecMutex prop_mutex;
44
45         ESource *source;
46         gchar *uri;
47         gboolean online;
48         gboolean readonly;
49         gboolean capabilities_retrieved;
50         GSList *capabilities;
51
52         GHashTable *backend_property_cache;
53
54         GRecMutex ops_mutex;
55         guint32 last_opid;
56         GHashTable *ops; /* opid to GCancellable */
57 };
58
59 struct _AsyncContext {
60         gchar *capabilities;
61         gchar *prop_name;
62         gchar *prop_value;
63         gboolean only_if_exists;
64 };
65
66 enum {
67         PROP_0,
68         PROP_SOURCE,
69         PROP_CAPABILITIES,
70         PROP_READONLY,
71         PROP_ONLINE,
72         PROP_OPENED
73 };
74
75 enum {
76         OPENED,
77         BACKEND_ERROR,
78         BACKEND_DIED,
79         BACKEND_PROPERTY_CHANGED,
80         LAST_SIGNAL
81 };
82
83 static guint signals[LAST_SIGNAL];
84
85 G_DEFINE_ABSTRACT_TYPE (EClient, e_client, G_TYPE_OBJECT)
86
87 static void
88 async_context_free (AsyncContext *async_context)
89 {
90         g_free (async_context->capabilities);
91         g_free (async_context->prop_name);
92         g_free (async_context->prop_value);
93
94         g_slice_free (AsyncContext, async_context);
95 }
96
97 /*
98  * Well-known client backend properties, which are common for each #EClient:
99  * @CLIENT_BACKEND_PROPERTY_OPENED: Is set to "TRUE" or "FALSE" depending
100  *   whether the backend is fully opened.
101  * @CLIENT_BACKEND_PROPERTY_OPENING: Is set to "TRUE" or "FALSE" depending
102  *   whether the backend is processing its opening phase.
103  * @CLIENT_BACKEND_PROPERTY_ONLINE: Is set to "TRUE" or "FALSE" depending
104  *   on the backend's loaded state. See also e_client_is_online().
105  * @CLIENT_BACKEND_PROPERTY_READONLY: Is set to "TRUE" or "FALSE" depending
106  *   on the backend's readonly state. See also e_client_is_readonly().
107  * @CLIENT_BACKEND_PROPERTY_CACHE_DIR: Local folder with cached data used
108  *   by the backend.
109  * @CLIENT_BACKEND_PROPERTY_CAPABILITIES: Retrieves comma-separated list
110  *   of capabilities supported by the backend. Preferred method of retreiving
111  *   and working with capabilities is e_client_get_capabilities() and
112  *   e_client_check_capability().
113  */
114
115 G_DEFINE_QUARK (e-client-error-quark, e_client_error)
116
117 /**
118  * e_client_error_to_string:
119  *
120  * FIXME: Document me.
121  *
122  * Since: 3.2
123  **/
124 const gchar *
125 e_client_error_to_string (EClientError code)
126 {
127         switch (code) {
128         case E_CLIENT_ERROR_INVALID_ARG:
129                 return _("Invalid argument");
130         case E_CLIENT_ERROR_BUSY:
131                 return _("Backend is busy");
132         case E_CLIENT_ERROR_SOURCE_NOT_LOADED:
133                 return _("Source not loaded");
134         case E_CLIENT_ERROR_SOURCE_ALREADY_LOADED:
135                 return _("Source already loaded");
136         case E_CLIENT_ERROR_AUTHENTICATION_FAILED:
137                 return _("Authentication failed");
138         case E_CLIENT_ERROR_AUTHENTICATION_REQUIRED:
139                 return _("Authentication required");
140         case E_CLIENT_ERROR_REPOSITORY_OFFLINE:
141                 return _("Repository offline");
142         case E_CLIENT_ERROR_OFFLINE_UNAVAILABLE:
143                 /* Translators: This means that the EClient does not support offline mode, or
144                  * it's not set to by a user, thus it is unavailable while user is not connected. */
145                 return _("Offline unavailable");
146         case E_CLIENT_ERROR_PERMISSION_DENIED:
147                 return _("Permission denied");
148         case E_CLIENT_ERROR_CANCELLED:
149                 return _("Cancelled");
150         case E_CLIENT_ERROR_COULD_NOT_CANCEL:
151                 return _("Could not cancel");
152         case E_CLIENT_ERROR_NOT_SUPPORTED:
153                 return _("Not supported");
154         case E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD:
155                 return _("Unsupported authentication method");
156         case E_CLIENT_ERROR_TLS_NOT_AVAILABLE:
157                 return _("TLS not available");
158         case E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED:
159                 return _("Search size limit exceeded");
160         case E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED:
161                 return _("Search time limit exceeded");
162         case E_CLIENT_ERROR_INVALID_QUERY:
163                 return _("Invalid query");
164         case E_CLIENT_ERROR_QUERY_REFUSED:
165                 return _("Query refused");
166         case E_CLIENT_ERROR_DBUS_ERROR:
167                 return _("D-Bus error");
168         case E_CLIENT_ERROR_OTHER_ERROR:
169                 return _("Other error");
170         case E_CLIENT_ERROR_NOT_OPENED:
171                 return _("Backend is not opened yet");
172         }
173
174         return _("Unknown error");
175 }
176
177 /**
178  * e_client_error_create:
179  * @code: an #EClientError code to create
180  * @custom_msg: custom message to use for the error; can be %NULL
181  *
182  * Returns: a new #GError containing an E_CLIENT_ERROR of the given
183  * @code. If the @custom_msg is NULL, then the error message is
184  * the one returned from e_client_error_to_string() for the @code,
185  * otherwise the given message is used.
186  *
187  * Returned pointer should be freed with g_error_free().
188  *
189  * Since: 3.2
190  **/
191 GError *
192 e_client_error_create (EClientError code,
193                        const gchar *custom_msg)
194 {
195         return g_error_new_literal (E_CLIENT_ERROR, code, custom_msg ? custom_msg : e_client_error_to_string (code));
196 }
197
198 static void client_set_source (EClient *client, ESource *source);
199
200 static void
201 e_client_init (EClient *client)
202 {
203         client->priv = E_CLIENT_GET_PRIVATE (client);
204
205         client->priv->readonly = TRUE;
206
207         g_rec_mutex_init (&client->priv->prop_mutex);
208         client->priv->backend_property_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
209
210         g_rec_mutex_init (&client->priv->ops_mutex);
211         client->priv->last_opid = 0;
212         client->priv->ops = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
213 }
214
215 static void
216 client_dispose (GObject *object)
217 {
218         EClient *client;
219
220         client = E_CLIENT (object);
221
222         e_client_cancel_all (client);
223
224         /* Chain up to parent's dispose() method. */
225         G_OBJECT_CLASS (e_client_parent_class)->dispose (object);
226 }
227
228 static void
229 client_finalize (GObject *object)
230 {
231         EClient *client;
232         EClientPrivate *priv;
233
234         client = E_CLIENT (object);
235
236         priv = client->priv;
237
238         g_rec_mutex_lock (&priv->prop_mutex);
239
240         if (priv->source) {
241                 g_object_unref (priv->source);
242                 priv->source = NULL;
243         }
244
245         if (priv->uri) {
246                 g_free (priv->uri);
247                 priv->uri = NULL;
248         }
249
250         if (priv->capabilities) {
251                 g_slist_foreach (priv->capabilities, (GFunc) g_free, NULL);
252                 g_slist_free (priv->capabilities);
253                 priv->capabilities = NULL;
254         }
255
256         if (priv->backend_property_cache) {
257                 g_hash_table_destroy (priv->backend_property_cache);
258                 priv->backend_property_cache = NULL;
259         }
260
261         if (priv->ops) {
262                 g_hash_table_destroy (priv->ops);
263                 priv->ops = NULL;
264         }
265
266         g_rec_mutex_unlock (&priv->prop_mutex);
267         g_rec_mutex_clear (&priv->prop_mutex);
268         g_rec_mutex_clear (&priv->ops_mutex);
269
270         /* Chain up to parent's finalize() method. */
271         G_OBJECT_CLASS (e_client_parent_class)->finalize (object);
272 }
273
274 static void
275 client_set_property (GObject *object,
276                      guint property_id,
277                      const GValue *value,
278                      GParamSpec *pspec)
279 {
280         switch (property_id) {
281                 case PROP_SOURCE:
282                         client_set_source (E_CLIENT (object), g_value_get_object (value));
283                         return;
284
285                 case PROP_ONLINE:
286                         e_client_set_online (E_CLIENT (object), g_value_get_boolean (value));
287                         return;
288         }
289
290         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
291 }
292
293 static void
294 client_get_property (GObject *object,
295                      guint property_id,
296                      GValue *value,
297                      GParamSpec *pspec)
298 {
299         switch (property_id) {
300                 case PROP_SOURCE:
301                         g_value_set_object (value, e_client_get_source (E_CLIENT (object)));
302                         return;
303
304                 case PROP_CAPABILITIES:
305                         g_value_set_pointer (value, (gpointer) e_client_get_capabilities (E_CLIENT (object)));
306                         return;
307
308                 case PROP_READONLY:
309                         g_value_set_boolean (value, e_client_is_readonly (E_CLIENT (object)));
310                         return;
311
312                 case PROP_ONLINE:
313                         g_value_set_boolean (value, e_client_is_online (E_CLIENT (object)));
314                         return;
315
316                 case PROP_OPENED:
317                         g_value_set_boolean (value, e_client_is_opened (E_CLIENT (object)));
318                         return;
319         }
320
321         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
322 }
323
324 /* Helper for client_retrieve_capabilities() */
325 static void
326 client_retrieve_capabilities_thread (GSimpleAsyncResult *simple,
327                                      GObject *source_object,
328                                      GCancellable *cancellable)
329 {
330         AsyncContext *async_context;
331         GError *error = NULL;
332
333         async_context = g_simple_async_result_get_op_res_gpointer (simple);
334
335         e_client_retrieve_capabilities_sync (
336                 E_CLIENT (source_object),
337                 &async_context->capabilities,
338                 cancellable, &error);
339
340         if (error != NULL)
341                 g_simple_async_result_take_error (simple, error);
342 }
343
344 static void
345 client_retrieve_capabilities (EClient *client,
346                               GCancellable *cancellable,
347                               GAsyncReadyCallback callback,
348                               gpointer user_data)
349 {
350         GSimpleAsyncResult *simple;
351         AsyncContext *async_context;
352
353         async_context = g_slice_new0 (AsyncContext);
354
355         simple = g_simple_async_result_new (
356                 G_OBJECT (client), callback,
357                 user_data, client_retrieve_capabilities);
358
359         g_simple_async_result_set_check_cancellable (simple, cancellable);
360
361         g_simple_async_result_set_op_res_gpointer (
362                 simple, async_context, (GDestroyNotify) async_context_free);
363
364         g_simple_async_result_run_in_thread (
365                 simple, client_retrieve_capabilities_thread,
366                 G_PRIORITY_DEFAULT, cancellable);
367
368         g_object_unref (simple);
369 }
370
371 static gboolean
372 client_retrieve_capabilities_finish (EClient *client,
373                                      GAsyncResult *result,
374                                      gchar **capabilities,
375                                      GError **error)
376 {
377         GSimpleAsyncResult *simple;
378         AsyncContext *async_context;
379
380         g_return_val_if_fail (
381                 g_simple_async_result_is_valid (
382                 result, G_OBJECT (client),
383                 client_retrieve_capabilities), FALSE);
384
385         simple = G_SIMPLE_ASYNC_RESULT (result);
386         async_context = g_simple_async_result_get_op_res_gpointer (simple);
387
388         if (g_simple_async_result_propagate_error (simple, error))
389                 return FALSE;
390
391         g_return_val_if_fail (async_context->capabilities != NULL, FALSE);
392
393         if (capabilities != NULL) {
394                 *capabilities = async_context->capabilities;
395                 async_context->capabilities = NULL;
396         }
397
398         return TRUE;
399 }
400
401 /* Helper for client_get_backend_property() */
402 static void
403 client_get_backend_property_thread (GSimpleAsyncResult *simple,
404                                     GObject *source_object,
405                                     GCancellable *cancellable)
406 {
407         AsyncContext *async_context;
408         GError *error = NULL;
409
410         async_context = g_simple_async_result_get_op_res_gpointer (simple);
411
412         e_client_get_backend_property_sync (
413                 E_CLIENT (source_object),
414                 async_context->prop_name,
415                 &async_context->prop_value,
416                 cancellable, &error);
417
418         if (error != NULL)
419                 g_simple_async_result_take_error (simple, error);
420 }
421
422 static void
423 client_get_backend_property (EClient *client,
424                              const gchar *prop_name,
425                              GCancellable *cancellable,
426                              GAsyncReadyCallback callback,
427                              gpointer user_data)
428 {
429         GSimpleAsyncResult *simple;
430         AsyncContext *async_context;
431
432         async_context = g_slice_new0 (AsyncContext);
433         async_context->prop_name = g_strdup (prop_name);
434
435         simple = g_simple_async_result_new (
436                 G_OBJECT (client), callback,
437                 user_data, client_get_backend_property);
438
439         g_simple_async_result_set_check_cancellable (simple, cancellable);
440
441         g_simple_async_result_set_op_res_gpointer (
442                 simple, async_context, (GDestroyNotify) async_context_free);
443
444         g_simple_async_result_run_in_thread (
445                 simple, client_get_backend_property_thread,
446                 G_PRIORITY_DEFAULT, cancellable);
447
448         g_object_unref (simple);
449 }
450
451 static gboolean
452 client_get_backend_property_finish (EClient *client,
453                                     GAsyncResult *result,
454                                     gchar **prop_value,
455                                     GError **error)
456 {
457         GSimpleAsyncResult *simple;
458         AsyncContext *async_context;
459
460         g_return_val_if_fail (
461                 g_simple_async_result_is_valid (
462                 result, G_OBJECT (client),
463                 client_get_backend_property), FALSE);
464
465         simple = G_SIMPLE_ASYNC_RESULT (result);
466         async_context = g_simple_async_result_get_op_res_gpointer (simple);
467
468         if (g_simple_async_result_propagate_error (simple, error))
469                 return FALSE;
470
471         g_return_val_if_fail (async_context->prop_value != NULL, FALSE);
472
473         if (prop_value != NULL) {
474                 *prop_value = async_context->prop_value;
475                 async_context->prop_value = NULL;
476         }
477
478         return TRUE;
479 }
480
481 /* Helper for client_set_backend_property() */
482 static void
483 client_set_backend_property_thread (GSimpleAsyncResult *simple,
484                                     GObject *source_object,
485                                     GCancellable *cancellable)
486 {
487         AsyncContext *async_context;
488         GError *error = NULL;
489
490         async_context = g_simple_async_result_get_op_res_gpointer (simple);
491
492         e_client_set_backend_property_sync (
493                 E_CLIENT (source_object),
494                 async_context->prop_name,
495                 async_context->prop_value,
496                 cancellable, &error);
497
498         if (error != NULL)
499                 g_simple_async_result_take_error (simple, error);
500 }
501
502 static void
503 client_set_backend_property (EClient *client,
504                              const gchar *prop_name,
505                              const gchar *prop_value,
506                              GCancellable *cancellable,
507                              GAsyncReadyCallback callback,
508                              gpointer user_data)
509 {
510         GSimpleAsyncResult *simple;
511         AsyncContext *async_context;
512
513         async_context = g_slice_new0 (AsyncContext);
514         async_context->prop_name = g_strdup (prop_name);
515         async_context->prop_value = g_strdup (prop_value);
516
517         simple = g_simple_async_result_new (
518                 G_OBJECT (client), callback,
519                 user_data, client_set_backend_property);
520
521         g_simple_async_result_set_check_cancellable (simple, cancellable);
522
523         g_simple_async_result_set_op_res_gpointer (
524                 simple, async_context, (GDestroyNotify) async_context_free);
525
526         g_simple_async_result_run_in_thread (
527                 simple, client_set_backend_property_thread,
528                 G_PRIORITY_DEFAULT, cancellable);
529
530         g_object_unref (simple);
531 }
532
533 static gboolean
534 client_set_backend_property_finish (EClient *client,
535                                     GAsyncResult *result,
536                                     GError **error)
537 {
538         GSimpleAsyncResult *simple;
539
540         g_return_val_if_fail (
541                 g_simple_async_result_is_valid (
542                 result, G_OBJECT (client),
543                 client_set_backend_property), FALSE);
544
545         simple = G_SIMPLE_ASYNC_RESULT (result);
546
547         /* Assume success unless a GError is set. */
548         return !g_simple_async_result_propagate_error (simple, error);
549 }
550
551 /* Helper for client_open() */
552 static void
553 client_open_thread (GSimpleAsyncResult *simple,
554                     GObject *source_object,
555                     GCancellable *cancellable)
556 {
557         AsyncContext *async_context;
558         GError *error = NULL;
559
560         async_context = g_simple_async_result_get_op_res_gpointer (simple);
561
562         e_client_open_sync (
563                 E_CLIENT (source_object),
564                 async_context->only_if_exists,
565                 cancellable, &error);
566
567         if (error != NULL)
568                 g_simple_async_result_take_error (simple, error);
569 }
570
571 static void
572 client_open (EClient *client,
573              gboolean only_if_exists,
574              GCancellable *cancellable,
575              GAsyncReadyCallback callback,
576              gpointer user_data)
577 {
578         GSimpleAsyncResult *simple;
579         AsyncContext *async_context;
580
581         async_context = g_slice_new0 (AsyncContext);
582         async_context->only_if_exists = only_if_exists;
583
584         simple = g_simple_async_result_new (
585                 G_OBJECT (client), callback, user_data, client_open);
586
587         g_simple_async_result_set_check_cancellable (simple, cancellable);
588
589         g_simple_async_result_set_op_res_gpointer (
590                 simple, async_context, (GDestroyNotify) async_context_free);
591
592         g_simple_async_result_run_in_thread (
593                 simple, client_open_thread,
594                 G_PRIORITY_DEFAULT, cancellable);
595
596         g_object_unref (simple);
597 }
598
599 static gboolean
600 client_open_finish (EClient *client,
601                     GAsyncResult *result,
602                     GError **error)
603 {
604         GSimpleAsyncResult *simple;
605
606         g_return_val_if_fail (
607                 g_simple_async_result_is_valid (
608                 result, G_OBJECT (client), client_open), FALSE);
609
610         simple = G_SIMPLE_ASYNC_RESULT (result);
611
612         /* Assume success unless a GError is set. */
613         return !g_simple_async_result_propagate_error (simple, error);
614 }
615
616 /* Helper for client_remove() */
617 static void
618 client_remove_thread (GSimpleAsyncResult *simple,
619                       GObject *source_object,
620                       GCancellable *cancellable)
621 {
622         GError *error = NULL;
623
624         e_client_remove_sync (
625                 E_CLIENT (source_object), cancellable, &error);
626
627         if (error != NULL)
628                 g_simple_async_result_take_error (simple, error);
629 }
630
631 static void
632 client_remove (EClient *client,
633                GCancellable *cancellable,
634                GAsyncReadyCallback callback,
635                gpointer user_data)
636 {
637         GSimpleAsyncResult *simple;
638
639         simple = g_simple_async_result_new (
640                 G_OBJECT (client), callback, user_data, client_remove);
641
642         g_simple_async_result_set_check_cancellable (simple, cancellable);
643
644         g_simple_async_result_run_in_thread (
645                 simple, client_remove_thread,
646                 G_PRIORITY_DEFAULT, cancellable);
647
648         g_object_unref (simple);
649 }
650
651 static gboolean
652 client_remove_finish (EClient *client,
653                       GAsyncResult *result,
654                       GError **error)
655 {
656         GSimpleAsyncResult *simple;
657
658         g_return_val_if_fail (
659                 g_simple_async_result_is_valid (
660                 result, G_OBJECT (client), client_remove), FALSE);
661
662         simple = G_SIMPLE_ASYNC_RESULT (result);
663
664         /* Assume success unless a GError is set. */
665         return !g_simple_async_result_propagate_error (simple, error);
666 }
667
668 static gboolean
669 client_remove_sync (EClient *client,
670                     GCancellable *cancellable,
671                     GError **error)
672 {
673         ESource *source;
674
675         source = e_client_get_source (client);
676
677         return e_source_remove_sync (source, cancellable, error);
678 }
679
680 /* Helper for client_refresh() */
681 static void
682 client_refresh_thread (GSimpleAsyncResult *simple,
683                        GObject *source_object,
684                        GCancellable *cancellable)
685 {
686         GError *error = NULL;
687
688         e_client_refresh_sync (
689                 E_CLIENT (source_object), cancellable, &error);
690
691         if (error != NULL)
692                 g_simple_async_result_take_error (simple, error);
693 }
694
695 static void
696 client_refresh (EClient *client,
697                 GCancellable *cancellable,
698                 GAsyncReadyCallback callback,
699                 gpointer user_data)
700 {
701         GSimpleAsyncResult *simple;
702
703         simple = g_simple_async_result_new (
704                 G_OBJECT (client), callback, user_data, client_refresh);
705
706         g_simple_async_result_set_check_cancellable (simple, cancellable);
707
708         g_simple_async_result_run_in_thread (
709                 simple, client_refresh_thread,
710                 G_PRIORITY_DEFAULT, cancellable);
711
712         g_object_unref (simple);
713 }
714
715 static gboolean
716 client_refresh_finish (EClient *client,
717                        GAsyncResult *result,
718                        GError **error)
719 {
720         GSimpleAsyncResult *simple;
721
722         g_return_val_if_fail (
723                 g_simple_async_result_is_valid (
724                 result, G_OBJECT (client), client_refresh), FALSE);
725
726         simple = G_SIMPLE_ASYNC_RESULT (result);
727
728         /* Assume success unless a GError is set. */
729         return !g_simple_async_result_propagate_error (simple, error);
730 }
731
732 static void
733 e_client_class_init (EClientClass *class)
734 {
735         GObjectClass *object_class;
736
737         g_type_class_add_private (class, sizeof (EClientPrivate));
738
739         object_class = G_OBJECT_CLASS (class);
740         object_class->set_property = client_set_property;
741         object_class->get_property = client_get_property;
742         object_class->dispose = client_dispose;
743         object_class->finalize = client_finalize;
744
745         class->retrieve_capabilities = client_retrieve_capabilities;
746         class->retrieve_capabilities_finish = client_retrieve_capabilities_finish;
747         class->get_backend_property = client_get_backend_property;
748         class->get_backend_property_finish = client_get_backend_property_finish;
749         class->set_backend_property = client_set_backend_property;
750         class->set_backend_property_finish = client_set_backend_property_finish;
751         class->open = client_open;
752         class->open_finish = client_open_finish;
753         class->remove = client_remove;
754         class->remove_finish = client_remove_finish;
755         class->remove_sync = client_remove_sync;
756         class->refresh = client_refresh;
757         class->refresh_finish = client_refresh_finish;
758
759         g_object_class_install_property (
760                 object_class,
761                 PROP_SOURCE,
762                 g_param_spec_object (
763                         "source",
764                         NULL,
765                         NULL,
766                         E_TYPE_SOURCE,
767                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
768
769         g_object_class_install_property (
770                 object_class,
771                 PROP_CAPABILITIES,
772                 g_param_spec_pointer (
773                         "capabilities",
774                         NULL,
775                         NULL,
776                         G_PARAM_READABLE));
777
778         g_object_class_install_property (
779                 object_class,
780                 PROP_READONLY,
781                 g_param_spec_boolean (
782                         "readonly",
783                         NULL,
784                         NULL,
785                         FALSE,
786                         G_PARAM_READABLE));
787
788         g_object_class_install_property (
789                 object_class,
790                 PROP_ONLINE,
791                 g_param_spec_boolean (
792                         "online",
793                         NULL,
794                         NULL,
795                         FALSE,
796                         G_PARAM_READWRITE));
797
798         g_object_class_install_property (
799                 object_class,
800                 PROP_OPENED,
801                 g_param_spec_boolean (
802                         "opened",
803                         NULL,
804                         NULL,
805                         FALSE,
806                         G_PARAM_READABLE));
807
808         signals[OPENED] = g_signal_new (
809                 "opened",
810                 G_OBJECT_CLASS_TYPE (class),
811                 G_SIGNAL_RUN_LAST,
812                 G_STRUCT_OFFSET (EClientClass, opened),
813                 NULL, NULL,
814                 g_cclosure_marshal_VOID__BOXED,
815                 G_TYPE_NONE, 1,
816                 G_TYPE_ERROR);
817
818         signals[BACKEND_ERROR] = g_signal_new (
819                 "backend-error",
820                 G_OBJECT_CLASS_TYPE (class),
821                 G_SIGNAL_RUN_FIRST,
822                 G_STRUCT_OFFSET (EClientClass, backend_error),
823                 NULL, NULL,
824                 g_cclosure_marshal_VOID__STRING,
825                 G_TYPE_NONE, 1,
826                 G_TYPE_STRING);
827
828         signals[BACKEND_DIED] = g_signal_new (
829                 "backend-died",
830                 G_OBJECT_CLASS_TYPE (class),
831                 G_SIGNAL_RUN_LAST,
832                 G_STRUCT_OFFSET (EClientClass, backend_died),
833                 NULL, NULL,
834                 g_cclosure_marshal_VOID__VOID,
835                 G_TYPE_NONE, 0);
836
837         signals[BACKEND_PROPERTY_CHANGED] = g_signal_new (
838                 "backend-property-changed",
839                 G_OBJECT_CLASS_TYPE (class),
840                 G_SIGNAL_RUN_LAST,
841                 G_STRUCT_OFFSET (EClientClass, backend_property_changed),
842                 NULL, NULL,
843                 e_gdbus_marshallers_VOID__STRING_STRING,
844                 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
845 }
846
847 static void
848 client_set_source (EClient *client,
849                    ESource *source)
850 {
851         g_return_if_fail (E_IS_CLIENT (client));
852         g_return_if_fail (E_IS_SOURCE (source));
853
854         g_object_ref (source);
855
856         if (client->priv->source)
857                 g_object_unref (client->priv->source);
858
859         client->priv->source = source;
860 }
861
862 /**
863  * e_client_get_source:
864  * @client: an #EClient
865  *
866  * Get the #ESource that this client has assigned.
867  *
868  * Returns: (transfer none): The source.
869  *
870  * Since: 3.2
871  **/
872 ESource *
873 e_client_get_source (EClient *client)
874 {
875         g_return_val_if_fail (E_IS_CLIENT (client), NULL);
876
877         return client->priv->source;
878 }
879
880 static void
881 client_ensure_capabilities (EClient *client)
882 {
883         gchar *capabilities;
884
885         g_return_if_fail (E_IS_CLIENT (client));
886
887         if (client->priv->capabilities_retrieved || client->priv->capabilities)
888                 return;
889
890         g_rec_mutex_lock (&client->priv->prop_mutex);
891
892         capabilities = NULL;
893         e_client_retrieve_capabilities_sync (client, &capabilities, NULL, NULL);
894         /* e_client_set_capabilities is called inside the previous function */
895         g_free (capabilities);
896
897         client->priv->capabilities_retrieved = TRUE;
898
899         g_rec_mutex_unlock (&client->priv->prop_mutex);
900 }
901
902 /**
903  * e_client_get_capabilities:
904  * @client: an #EClient
905  *
906  * Get list of strings with capabilities advertised by a backend.
907  * This list, together with inner strings, is owned by the @client.
908  * To check for individual capabilities use e_client_check_capability().
909  *
910  * Returns: (element-type utf8) (transfer none): #GSList of const strings
911  *          of capabilities
912  *
913  * Since: 3.2
914  **/
915 const GSList *
916 e_client_get_capabilities (EClient *client)
917 {
918         g_return_val_if_fail (E_IS_CLIENT (client), NULL);
919
920         client_ensure_capabilities (client);
921
922         return client->priv->capabilities;
923 }
924
925 /**
926  * e_client_check_capability:
927  * @client: an #EClient
928  * @capability: a capability
929  *
930  * Check if backend supports particular capability.
931  * To get all capabilities use e_client_get_capabilities().
932  *
933  * Returns: #GSList of const strings of capabilities
934  *
935  * Since: 3.2
936  **/
937 gboolean
938 e_client_check_capability (EClient *client,
939                            const gchar *capability)
940 {
941         GSList *iter;
942
943         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
944         g_return_val_if_fail (capability, FALSE);
945
946         g_rec_mutex_lock (&client->priv->prop_mutex);
947
948         client_ensure_capabilities (client);
949
950         for (iter = client->priv->capabilities; iter; iter = g_slist_next (iter)) {
951                 const gchar *cap = iter->data;
952
953                 if (cap && g_ascii_strcasecmp (cap, capability) == 0) {
954                         g_rec_mutex_unlock (&client->priv->prop_mutex);
955                         return TRUE;
956                 }
957         }
958
959         g_rec_mutex_unlock (&client->priv->prop_mutex);
960
961         return FALSE;
962 }
963
964 /**
965  * e_client_check_refresh_supported:
966  * @client: A client.
967  *
968  * Checks whether a client supports explicit refreshing
969  * (see e_client_refresh()).
970  *
971  * Returns: TRUE if the client supports refreshing, FALSE otherwise.
972  *
973  * Since: 3.2
974  **/
975 gboolean
976 e_client_check_refresh_supported (EClient *client)
977 {
978         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
979
980         return e_client_check_capability (client, "refresh-supported");
981 }
982
983 /* capabilities - comma-separated list of capabilities; can be NULL to unset */
984 void
985 e_client_set_capabilities (EClient *client,
986                            const gchar *capabilities)
987 {
988         g_return_if_fail (E_IS_CLIENT (client));
989
990         g_rec_mutex_lock (&client->priv->prop_mutex);
991
992         if (!capabilities)
993                 client->priv->capabilities_retrieved = FALSE;
994
995         g_slist_foreach (client->priv->capabilities, (GFunc) g_free, NULL);
996         g_slist_free (client->priv->capabilities);
997         client->priv->capabilities = e_client_util_parse_comma_strings (capabilities);
998
999         g_rec_mutex_unlock (&client->priv->prop_mutex);
1000
1001         g_object_notify (G_OBJECT (client), "capabilities");
1002 }
1003
1004 /**
1005  * e_client_is_readonly:
1006  * @client: an #EClient
1007  *
1008  * Check if this @client is read-only.
1009  *
1010  * Returns: %TRUE if this @client is read-only, otherwise %FALSE.
1011  *
1012  * Since: 3.2
1013  **/
1014 gboolean
1015 e_client_is_readonly (EClient *client)
1016 {
1017         g_return_val_if_fail (E_IS_CLIENT (client), TRUE);
1018
1019         return client->priv->readonly;
1020 }
1021
1022 void
1023 e_client_set_readonly (EClient *client,
1024                        gboolean readonly)
1025 {
1026         g_return_if_fail (E_IS_CLIENT (client));
1027
1028         g_rec_mutex_lock (&client->priv->prop_mutex);
1029         if (client->priv->readonly == readonly) {
1030                 g_rec_mutex_unlock (&client->priv->prop_mutex);
1031                 return;
1032         }
1033
1034         client->priv->readonly = readonly;
1035
1036         g_rec_mutex_unlock (&client->priv->prop_mutex);
1037
1038         g_object_notify (G_OBJECT (client), "readonly");
1039 }
1040
1041 /**
1042  * e_client_is_online:
1043  * @client: an #EClient
1044  *
1045  * Check if this @client is connected.
1046  *
1047  * Returns: %TRUE if this @client is connected, otherwise %FALSE.
1048  *
1049  * Since: 3.2
1050  **/
1051 gboolean
1052 e_client_is_online (EClient *client)
1053 {
1054         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1055
1056         return client->priv->online;
1057 }
1058
1059 void
1060 e_client_set_online (EClient *client,
1061                      gboolean is_online)
1062 {
1063         g_return_if_fail (E_IS_CLIENT (client));
1064
1065         /* newly connected/disconnected => make sure capabilities will be correct */
1066         e_client_set_capabilities (client, NULL);
1067
1068         g_rec_mutex_lock (&client->priv->prop_mutex);
1069         if (client->priv->online == is_online) {
1070                 g_rec_mutex_unlock (&client->priv->prop_mutex);
1071                 return;
1072         }
1073
1074         client->priv->online = is_online;
1075
1076         g_rec_mutex_unlock (&client->priv->prop_mutex);
1077
1078         g_object_notify (G_OBJECT (client), "online");
1079 }
1080
1081 /**
1082  * e_client_is_opened:
1083  * @client: an #EClient
1084  *
1085  * Check if this @client is fully opened. This includes
1086  * everything from e_client_open() call up to the authentication,
1087  * if required by a backend. Client cannot do any other operation
1088  * during the opening phase except of authenticate or cancel it.
1089  * Every other operation results in an %E_CLIENT_ERROR_BUSY error.
1090  *
1091  * Returns: always %TRUE
1092  *
1093  * Since: 3.2.
1094  *
1095  * Deprecated: 3.8: Clients don't need to care if they're fully opened
1096  *                  anymore.  This function always returns %TRUE.
1097  **/
1098 gboolean
1099 e_client_is_opened (EClient *client)
1100 {
1101         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1102
1103         return TRUE;
1104 }
1105
1106 /*
1107  * client_cancel_op:
1108  * @client: an #EClient
1109  * @opid: asynchronous operation ID
1110  *
1111  * Cancels particular asynchronous operation. The @opid is returned from
1112  * an e_client_register_op(). The function does nothing if the asynchronous
1113  * operation doesn't exist any more.
1114  *
1115  * Since: 3.2
1116  */
1117 static void
1118 client_cancel_op (EClient *client,
1119                   guint32 opid)
1120 {
1121         GCancellable *cancellable;
1122
1123         g_return_if_fail (E_IS_CLIENT (client));
1124         g_return_if_fail (client->priv->ops != NULL);
1125
1126         g_rec_mutex_lock (&client->priv->ops_mutex);
1127
1128         cancellable = g_hash_table_lookup (client->priv->ops, GINT_TO_POINTER (opid));
1129         if (cancellable)
1130                 g_cancellable_cancel (cancellable);
1131
1132         g_rec_mutex_unlock (&client->priv->ops_mutex);
1133 }
1134
1135 static void
1136 gather_opids_cb (gpointer opid,
1137                  gpointer cancellable,
1138                  gpointer ids_list)
1139 {
1140         GSList **ids = ids_list;
1141
1142         g_return_if_fail (ids_list != NULL);
1143
1144         *ids = g_slist_prepend (*ids, opid);
1145 }
1146
1147 static void
1148 cancel_op_cb (gpointer opid,
1149               gpointer client)
1150 {
1151         client_cancel_op (client, GPOINTER_TO_INT (opid));
1152 }
1153
1154 /**
1155  * e_client_cancel_all:
1156  * @client: an #EClient
1157  *
1158  * Cancels all pending operations started on @client.
1159  *
1160  * Since: 3.2
1161  **/
1162 void
1163 e_client_cancel_all (EClient *client)
1164 {
1165         GSList *opids = NULL;
1166
1167         g_return_if_fail (E_IS_CLIENT (client));
1168         g_return_if_fail (client->priv->ops != NULL);
1169
1170         g_rec_mutex_lock (&client->priv->ops_mutex);
1171
1172         g_hash_table_foreach (client->priv->ops, gather_opids_cb, &opids);
1173
1174         g_slist_foreach (opids, cancel_op_cb, client);
1175         g_slist_free (opids);
1176
1177         g_rec_mutex_unlock (&client->priv->ops_mutex);
1178 }
1179
1180 guint32
1181 e_client_register_op (EClient *client,
1182                       GCancellable *cancellable)
1183 {
1184         guint32 opid;
1185
1186         g_return_val_if_fail (E_IS_CLIENT (client), 0);
1187         g_return_val_if_fail (client->priv->ops != NULL, 0);
1188         g_return_val_if_fail (cancellable != NULL, 0);
1189
1190         g_rec_mutex_lock (&client->priv->ops_mutex);
1191
1192         client->priv->last_opid++;
1193         if (!client->priv->last_opid)
1194                 client->priv->last_opid++;
1195
1196         while (g_hash_table_lookup (client->priv->ops, GINT_TO_POINTER (client->priv->last_opid)))
1197                 client->priv->last_opid++;
1198
1199         g_return_val_if_fail (client->priv->last_opid != 0, 0);
1200
1201         opid = client->priv->last_opid;
1202         g_hash_table_insert (client->priv->ops, GINT_TO_POINTER (opid), g_object_ref (cancellable));
1203
1204         g_rec_mutex_unlock (&client->priv->ops_mutex);
1205
1206         return opid;
1207 }
1208
1209 void
1210 e_client_unregister_op (EClient *client,
1211                         guint32 opid)
1212 {
1213         g_return_if_fail (E_IS_CLIENT (client));
1214         g_return_if_fail (client->priv->ops != NULL);
1215
1216         g_rec_mutex_lock (&client->priv->ops_mutex);
1217         g_hash_table_remove (client->priv->ops, GINT_TO_POINTER (opid));
1218         g_rec_mutex_unlock (&client->priv->ops_mutex);
1219 }
1220
1221 void
1222 e_client_emit_opened (EClient *client,
1223                       const GError *dbus_error)
1224 {
1225         GError *local_error = NULL;
1226
1227         g_return_if_fail (E_IS_CLIENT (client));
1228
1229         if (dbus_error) {
1230                 local_error = g_error_copy (dbus_error);
1231                 e_client_unwrap_dbus_error (client, local_error, &local_error);
1232         }
1233
1234         g_object_notify (G_OBJECT (client), "opened");
1235         g_signal_emit (client, signals[OPENED], 0, local_error);
1236
1237         if (local_error)
1238                 g_error_free (local_error);
1239 }
1240
1241 void
1242 e_client_emit_backend_error (EClient *client,
1243                              const gchar *error_msg)
1244 {
1245         g_return_if_fail (E_IS_CLIENT (client));
1246         g_return_if_fail (error_msg != NULL);
1247
1248         g_signal_emit (client, signals[BACKEND_ERROR], 0, error_msg);
1249 }
1250
1251 void
1252 e_client_emit_backend_died (EClient *client)
1253 {
1254         g_return_if_fail (E_IS_CLIENT (client));
1255
1256         g_signal_emit (client, signals[BACKEND_DIED], 0);
1257 }
1258
1259 void
1260 e_client_emit_backend_property_changed (EClient *client,
1261                                         const gchar *prop_name,
1262                                         const gchar *prop_value)
1263 {
1264         g_return_if_fail (E_IS_CLIENT (client));
1265         g_return_if_fail (prop_name != NULL);
1266         g_return_if_fail (*prop_name);
1267         g_return_if_fail (prop_value != NULL);
1268
1269         e_client_update_backend_property_cache (client, prop_name, prop_value);
1270
1271         g_signal_emit (client, signals[BACKEND_PROPERTY_CHANGED], 0, prop_name, prop_value);
1272 }
1273
1274 void
1275 e_client_update_backend_property_cache (EClient *client,
1276                                         const gchar *prop_name,
1277                                         const gchar *prop_value)
1278 {
1279         g_return_if_fail (E_IS_CLIENT (client));
1280         g_return_if_fail (prop_name != NULL);
1281         g_return_if_fail (*prop_name);
1282         g_return_if_fail (prop_value != NULL);
1283
1284         g_rec_mutex_lock (&client->priv->prop_mutex);
1285
1286         if (client->priv->backend_property_cache)
1287                 g_hash_table_insert (client->priv->backend_property_cache, g_strdup (prop_name), g_strdup (prop_value));
1288
1289         g_rec_mutex_unlock (&client->priv->prop_mutex);
1290 }
1291
1292 gchar *
1293 e_client_get_backend_property_from_cache (EClient *client,
1294                                           const gchar *prop_name)
1295 {
1296         gchar *prop_value = NULL;
1297
1298         g_return_val_if_fail (E_IS_CLIENT (client), NULL);
1299         g_return_val_if_fail (prop_name != NULL, NULL);
1300         g_return_val_if_fail (*prop_name, NULL);
1301
1302         g_rec_mutex_lock (&client->priv->prop_mutex);
1303
1304         if (client->priv->backend_property_cache)
1305                 prop_value = g_strdup (g_hash_table_lookup (client->priv->backend_property_cache, prop_name));
1306
1307         g_rec_mutex_unlock (&client->priv->prop_mutex);
1308
1309         return prop_value;
1310 }
1311
1312 /**
1313  * e_client_retrieve_capabilities:
1314  * @client: an #EClient
1315  * @cancellable: a #GCancellable; can be %NULL
1316  * @callback: callback to call when a result is ready
1317  * @user_data: user data for the @callback
1318  *
1319  * Initiates retrieval of capabilities on the @client. This is usually
1320  * required only once, after the @client is opened. The returned value
1321  * is cached and any subsequent call of e_client_get_capabilities() and
1322  * e_client_check_capability() is using the cached value.
1323  * The call is finished by e_client_retrieve_capabilities_finish()
1324  * from the @callback.
1325  *
1326  * Since: 3.2
1327  **/
1328 void
1329 e_client_retrieve_capabilities (EClient *client,
1330                                 GCancellable *cancellable,
1331                                 GAsyncReadyCallback callback,
1332                                 gpointer user_data)
1333 {
1334         EClientClass *class;
1335
1336         g_return_if_fail (E_IS_CLIENT (client));
1337         g_return_if_fail (callback != NULL);
1338
1339         class = E_CLIENT_GET_CLASS (client);
1340         g_return_if_fail (class != NULL);
1341         g_return_if_fail (class->retrieve_capabilities != NULL);
1342
1343         class->retrieve_capabilities (client, cancellable, callback, user_data);
1344 }
1345
1346 /**
1347  * e_client_retrieve_capabilities_finish:
1348  * @client: an #EClient
1349  * @result: a #GAsyncResult
1350  * @capabilities: (out): Comma-separated list of capabilities of the @client
1351  * @error: (out): a #GError to set an error, if any
1352  *
1353  * Finishes previous call of e_client_retrieve_capabilities().
1354  * Returned value of @capabilities should be freed with g_free(),
1355  * when no longer needed.
1356  *
1357  * Returns: %TRUE if successful, %FALSE otherwise.
1358  *
1359  * Since: 3.2
1360  **/
1361 gboolean
1362 e_client_retrieve_capabilities_finish (EClient *client,
1363                                        GAsyncResult *result,
1364                                        gchar **capabilities,
1365                                        GError **error)
1366 {
1367         EClientClass *class;
1368         gboolean res;
1369
1370         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1371         g_return_val_if_fail (capabilities != NULL, FALSE);
1372
1373         class = E_CLIENT_GET_CLASS (client);
1374         g_return_val_if_fail (class != NULL, FALSE);
1375         g_return_val_if_fail (class->retrieve_capabilities_finish != NULL, FALSE);
1376
1377         *capabilities = NULL;
1378         res = class->retrieve_capabilities_finish (client, result, capabilities, error);
1379
1380         e_client_set_capabilities (client, res ? *capabilities : NULL);
1381
1382         if (error && *error)
1383                 e_client_unwrap_dbus_error (client, *error, error);
1384
1385         return res;
1386 }
1387
1388 /**
1389  * e_client_retrieve_capabilities_sync:
1390  * @client: an #EClient
1391  * @capabilities: (out): Comma-separated list of capabilities of the @client
1392  * @cancellable: a #GCancellable; can be %NULL
1393  * @error: (out): a #GError to set an error, if any
1394  *
1395  * Initiates retrieval of capabilities on the @client. This is usually
1396  * required only once, after the @client is opened. The returned value
1397  * is cached and any subsequent call of e_client_get_capabilities() and
1398  * e_client_check_capability() is using the cached value. Returned value
1399  * of @capabilities should be freed with g_free(), when no longer needed.
1400  *
1401  * Returns: %TRUE if successful, %FALSE otherwise.
1402  *
1403  * Since: 3.2
1404  **/
1405 gboolean
1406 e_client_retrieve_capabilities_sync (EClient *client,
1407                                      gchar **capabilities,
1408                                      GCancellable *cancellable,
1409                                      GError **error)
1410 {
1411         EClientClass *class;
1412         gboolean res = FALSE;
1413
1414         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1415         g_return_val_if_fail (capabilities != NULL, FALSE);
1416
1417         class = E_CLIENT_GET_CLASS (client);
1418         g_return_val_if_fail (class != NULL, FALSE);
1419         g_return_val_if_fail (class->retrieve_capabilities_sync != NULL, FALSE);
1420
1421         *capabilities = NULL;
1422         res = class->retrieve_capabilities_sync (client, capabilities, cancellable, error);
1423
1424         e_client_set_capabilities (client, res ? *capabilities : NULL);
1425
1426         if (error && *error)
1427                 e_client_unwrap_dbus_error (client, *error, error);
1428
1429         return res;
1430 }
1431
1432 /**
1433  * e_client_get_backend_property:
1434  * @client: an #EClient
1435  * @prop_name: property name, whose value to retrieve; cannot be %NULL
1436  * @cancellable: a #GCancellable; can be %NULL
1437  * @callback: callback to call when a result is ready
1438  * @user_data: user data for the @callback
1439  *
1440  * Queries @client's backend for a property of name @prop_name.
1441  * The call is finished by e_client_get_backend_property_finish()
1442  * from the @callback.
1443  *
1444  * Since: 3.2
1445  **/
1446 void
1447 e_client_get_backend_property (EClient *client,
1448                                const gchar *prop_name,
1449                                GCancellable *cancellable,
1450                                GAsyncReadyCallback callback,
1451                                gpointer user_data)
1452 {
1453         EClientClass *class;
1454
1455         g_return_if_fail (callback != NULL);
1456         g_return_if_fail (E_IS_CLIENT (client));
1457         g_return_if_fail (prop_name != NULL);
1458
1459         class = E_CLIENT_GET_CLASS (client);
1460         g_return_if_fail (class != NULL);
1461         g_return_if_fail (class->get_backend_property != NULL);
1462
1463         class->get_backend_property (client, prop_name, cancellable, callback, user_data);
1464 }
1465
1466 /**
1467  * e_client_get_backend_property_finish:
1468  * @client: an #EClient
1469  * @result: a #GAsyncResult
1470  * @prop_value: (out): Retrieved backend property value; cannot be %NULL
1471  * @error: (out): a #GError to set an error, if any
1472  *
1473  * Finishes previous call of e_client_get_backend_property().
1474  *
1475  * Returns: %TRUE if successful, %FALSE otherwise.
1476  *
1477  * Since: 3.2
1478  **/
1479 gboolean
1480 e_client_get_backend_property_finish (EClient *client,
1481                                       GAsyncResult *result,
1482                                       gchar **prop_value,
1483                                       GError **error)
1484 {
1485         EClientClass *class;
1486         gboolean res;
1487
1488         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1489         g_return_val_if_fail (prop_value != NULL, FALSE);
1490
1491         class = E_CLIENT_GET_CLASS (client);
1492         g_return_val_if_fail (class != NULL, FALSE);
1493         g_return_val_if_fail (class->get_backend_property_finish != NULL, FALSE);
1494
1495         res = class->get_backend_property_finish (client, result, prop_value, error);
1496
1497         if (error && *error)
1498                 e_client_unwrap_dbus_error (client, *error, error);
1499
1500         return res;
1501 }
1502
1503 /**
1504  * e_client_get_backend_property_sync:
1505  * @client: an #EClient
1506  * @prop_name: property name, whose value to retrieve; cannot be %NULL
1507  * @prop_value: (out): Retrieved backend property value; cannot be %NULL
1508  * @cancellable: a #GCancellable; can be %NULL
1509  * @error: (out): a #GError to set an error, if any
1510  *
1511  * Queries @client's backend for a property of name @prop_name.
1512  *
1513  * Returns: %TRUE if successful, %FALSE otherwise.
1514  *
1515  * Since: 3.2
1516  **/
1517 gboolean
1518 e_client_get_backend_property_sync (EClient *client,
1519                                     const gchar *prop_name,
1520                                     gchar **prop_value,
1521                                     GCancellable *cancellable,
1522                                     GError **error)
1523 {
1524         EClientClass *class;
1525         gboolean res;
1526
1527         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1528         g_return_val_if_fail (prop_name != NULL, FALSE);
1529         g_return_val_if_fail (prop_value != NULL, FALSE);
1530
1531         class = E_CLIENT_GET_CLASS (client);
1532         g_return_val_if_fail (class != NULL, FALSE);
1533         g_return_val_if_fail (class->get_backend_property_sync != NULL, FALSE);
1534
1535         res = class->get_backend_property_sync (client, prop_name, prop_value, cancellable, error);
1536
1537         if (error && *error)
1538                 e_client_unwrap_dbus_error (client, *error, error);
1539
1540         return res;
1541 }
1542
1543 /**
1544  * e_client_set_backend_property:
1545  * @client: an #EClient
1546  * @prop_name: property name, whose value to change; cannot be %NULL
1547  * @prop_value: property value, to set; cannot be %NULL
1548  * @cancellable: a #GCancellable; can be %NULL
1549  * @callback: callback to call when a result is ready
1550  * @user_data: user data for the @callback
1551  *
1552  * Sets @client's backend property of name @prop_name
1553  * to value @prop_value. The call is finished
1554  * by e_client_set_backend_property_finish() from the @callback.
1555  *
1556  * Since: 3.2
1557  **/
1558 void
1559 e_client_set_backend_property (EClient *client,
1560                                const gchar *prop_name,
1561                                const gchar *prop_value,
1562                                GCancellable *cancellable,
1563                                GAsyncReadyCallback callback,
1564                                gpointer user_data)
1565 {
1566         EClientClass *class;
1567
1568         g_return_if_fail (callback != NULL);
1569         g_return_if_fail (E_IS_CLIENT (client));
1570         g_return_if_fail (prop_name != NULL);
1571         g_return_if_fail (prop_value != NULL);
1572
1573         class = E_CLIENT_GET_CLASS (client);
1574         g_return_if_fail (class != NULL);
1575         g_return_if_fail (class->set_backend_property != NULL);
1576
1577         class->set_backend_property (client, prop_name, prop_value, cancellable, callback, user_data);
1578 }
1579
1580 /**
1581  * e_client_set_backend_property_finish:
1582  * @client: an #EClient
1583  * @result: a #GAsyncResult
1584  * @error: (out): a #GError to set an error, if any
1585  *
1586  * Finishes previous call of e_client_set_backend_property().
1587  *
1588  * Returns: %TRUE if successful, %FALSE otherwise.
1589  *
1590  * Since: 3.2
1591  **/
1592 gboolean
1593 e_client_set_backend_property_finish (EClient *client,
1594                                       GAsyncResult *result,
1595                                       GError **error)
1596 {
1597         EClientClass *class;
1598         gboolean res;
1599
1600         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1601
1602         class = E_CLIENT_GET_CLASS (client);
1603         g_return_val_if_fail (class != NULL, FALSE);
1604         g_return_val_if_fail (class->set_backend_property_finish != NULL, FALSE);
1605
1606         res = class->set_backend_property_finish (client, result, error);
1607
1608         if (error && *error)
1609                 e_client_unwrap_dbus_error (client, *error, error);
1610
1611         return res;
1612 }
1613
1614 /**
1615  * e_client_set_backend_property_sync:
1616  * @client: an #EClient
1617  * @prop_name: property name, whose value to change; cannot be %NULL
1618  * @prop_value: property value, to set; cannot be %NULL
1619  * @cancellable: a #GCancellable; can be %NULL
1620  * @error: (out): a #GError to set an error, if any
1621  *
1622  * Sets @client's backend property of name @prop_name
1623  * to value @prop_value.
1624  *
1625  * Returns: %TRUE if successful, %FALSE otherwise.
1626  *
1627  * Since: 3.2
1628  **/
1629 gboolean
1630 e_client_set_backend_property_sync (EClient *client,
1631                                     const gchar *prop_name,
1632                                     const gchar *prop_value,
1633                                     GCancellable *cancellable,
1634                                     GError **error)
1635 {
1636         EClientClass *class;
1637         gboolean res;
1638
1639         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1640         g_return_val_if_fail (prop_name != NULL, FALSE);
1641         g_return_val_if_fail (prop_value != NULL, FALSE);
1642
1643         class = E_CLIENT_GET_CLASS (client);
1644         g_return_val_if_fail (class != NULL, FALSE);
1645         g_return_val_if_fail (class->set_backend_property_sync != NULL, FALSE);
1646
1647         res = class->set_backend_property_sync (client, prop_name, prop_value, cancellable, error);
1648
1649         if (error && *error)
1650                 e_client_unwrap_dbus_error (client, *error, error);
1651
1652         return res;
1653 }
1654
1655 /**
1656  * e_client_open:
1657  * @client: an #EClient
1658  * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
1659  * @cancellable: a #GCancellable; can be %NULL
1660  * @callback: callback to call when a result is ready
1661  * @user_data: user data for the @callback
1662  *
1663  * Opens the @client, making it ready for queries and other operations.
1664  * The call is finished by e_client_open_finish() from the @callback.
1665  *
1666  * Since: 3.2
1667  **/
1668 void
1669 e_client_open (EClient *client,
1670                gboolean only_if_exists,
1671                GCancellable *cancellable,
1672                GAsyncReadyCallback callback,
1673                gpointer user_data)
1674 {
1675         EClientClass *class;
1676
1677         g_return_if_fail (callback != NULL);
1678         g_return_if_fail (E_IS_CLIENT (client));
1679
1680         class = E_CLIENT_GET_CLASS (client);
1681         g_return_if_fail (class != NULL);
1682         g_return_if_fail (class->open != NULL);
1683
1684         class->open (client, only_if_exists, cancellable, callback, user_data);
1685 }
1686
1687 /**
1688  * e_client_open_finish:
1689  * @client: an #EClient
1690  * @result: a #GAsyncResult
1691  * @error: (out): a #GError to set an error, if any
1692  *
1693  * Finishes previous call of e_client_open().
1694  *
1695  * Returns: %TRUE if successful, %FALSE otherwise.
1696  *
1697  * Since: 3.2
1698  **/
1699 gboolean
1700 e_client_open_finish (EClient *client,
1701                       GAsyncResult *result,
1702                       GError **error)
1703 {
1704         EClientClass *class;
1705         gboolean res;
1706
1707         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1708
1709         class = E_CLIENT_GET_CLASS (client);
1710         g_return_val_if_fail (class != NULL, FALSE);
1711         g_return_val_if_fail (class->open_finish != NULL, FALSE);
1712
1713         res = class->open_finish (client, result, error);
1714
1715         if (error && *error)
1716                 e_client_unwrap_dbus_error (client, *error, error);
1717
1718         return res;
1719 }
1720
1721 /**
1722  * e_client_open_sync:
1723  * @client: an #EClient
1724  * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
1725  * @cancellable: a #GCancellable; can be %NULL
1726  * @error: (out): a #GError to set an error, if any
1727  *
1728  * Opens the @client, making it ready for queries and other operations.
1729  *
1730  * Returns: %TRUE if successful, %FALSE otherwise.
1731  *
1732  * Since: 3.2
1733  **/
1734 gboolean
1735 e_client_open_sync (EClient *client,
1736                     gboolean only_if_exists,
1737                     GCancellable *cancellable,
1738                     GError **error)
1739 {
1740         EClientClass *class;
1741         gboolean res;
1742
1743         class = E_CLIENT_GET_CLASS (client);
1744         g_return_val_if_fail (class != NULL, FALSE);
1745         g_return_val_if_fail (class->open_sync != NULL, FALSE);
1746
1747         res = class->open_sync (client, only_if_exists, cancellable, error);
1748
1749         if (error && *error)
1750                 e_client_unwrap_dbus_error (client, *error, error);
1751
1752         return res;
1753 }
1754
1755 /**
1756  * e_client_remove:
1757  * @client: an #EClient
1758  * @cancellable: a #GCancellable; can be %NULL
1759  * @callback: callback to call when a result is ready
1760  * @user_data: user data for the @callback
1761  *
1762  * Removes the backing data for this #EClient. For example, with the file
1763  * backend this deletes the database file. You cannot get it back!
1764  * The call is finished by e_client_remove_finish() from the @callback.
1765  *
1766  * Since: 3.2
1767  *
1768  * Deprecated: 3.6: Use e_source_remove() instead.
1769  **/
1770 void
1771 e_client_remove (EClient *client,
1772                  GCancellable *cancellable,
1773                  GAsyncReadyCallback callback,
1774                  gpointer user_data)
1775 {
1776         EClientClass *class;
1777
1778         g_return_if_fail (E_IS_CLIENT (client));
1779         g_return_if_fail (callback != NULL);
1780
1781         class = E_CLIENT_GET_CLASS (client);
1782         g_return_if_fail (class != NULL);
1783         g_return_if_fail (class->remove != NULL);
1784
1785         class->remove (client, cancellable, callback, user_data);
1786 }
1787
1788 /**
1789  * e_client_remove_finish:
1790  * @client: an #EClient
1791  * @result: a #GAsyncResult
1792  * @error: (out): a #GError to set an error, if any
1793  *
1794  * Finishes previous call of e_client_remove().
1795  *
1796  * Returns: %TRUE if successful, %FALSE otherwise.
1797  *
1798  * Since: 3.2
1799  *
1800  * Deprecated: 3.6: Use e_source_remove_finish() instead.
1801  **/
1802 gboolean
1803 e_client_remove_finish (EClient *client,
1804                         GAsyncResult *result,
1805                         GError **error)
1806 {
1807         EClientClass *class;
1808         gboolean res;
1809
1810         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1811
1812         class = E_CLIENT_GET_CLASS (client);
1813         g_return_val_if_fail (class != NULL, FALSE);
1814         g_return_val_if_fail (class->remove_finish != NULL, FALSE);
1815
1816         res = class->remove_finish (client, result, error);
1817
1818         if (error && *error)
1819                 e_client_unwrap_dbus_error (client, *error, error);
1820
1821         return res;
1822 }
1823
1824 /**
1825  * e_client_remove_sync:
1826  * @client: an #EClient
1827  * @cancellable: a #GCancellable; can be %NULL
1828  * @error: (out): a #GError to set an error, if any
1829  *
1830  * Removes the backing data for this #EClient. For example, with the file
1831  * backend this deletes the database file. You cannot get it back!
1832  *
1833  * Returns: %TRUE if successful, %FALSE otherwise.
1834  *
1835  * Since: 3.2
1836  *
1837  * Deprecated: 3.6: Use e_source_remove_sync() instead.
1838  **/
1839 gboolean
1840 e_client_remove_sync (EClient *client,
1841                       GCancellable *cancellable,
1842                       GError **error)
1843 {
1844         EClientClass *class;
1845         gboolean res;
1846
1847         class = E_CLIENT_GET_CLASS (client);
1848         g_return_val_if_fail (class != NULL, FALSE);
1849         g_return_val_if_fail (class->remove_sync != NULL, FALSE);
1850
1851         res = class->remove_sync (client, cancellable, error);
1852
1853         if (error && *error)
1854                 e_client_unwrap_dbus_error (client, *error, error);
1855
1856         return res;
1857 }
1858
1859 /**
1860  * e_client_refresh:
1861  * @client: an #EClient
1862  * @cancellable: a #GCancellable; can be %NULL
1863  * @callback: callback to call when a result is ready
1864  * @user_data: user data for the @callback
1865  *
1866  * Initiates refresh on the @client. Finishing the method doesn't mean
1867  * that the refresh is done, backend only notifies whether it started
1868  * refreshing or not. Use e_client_check_refresh_supported() to check
1869  * whether the backend supports this method.
1870  * The call is finished by e_client_refresh_finish() from the @callback.
1871  *
1872  * Since: 3.2
1873  **/
1874 void
1875 e_client_refresh (EClient *client,
1876                   GCancellable *cancellable,
1877                   GAsyncReadyCallback callback,
1878                   gpointer user_data)
1879 {
1880         EClientClass *class;
1881
1882         g_return_if_fail (E_IS_CLIENT (client));
1883         g_return_if_fail (callback != NULL);
1884
1885         class = E_CLIENT_GET_CLASS (client);
1886         g_return_if_fail (class != NULL);
1887         g_return_if_fail (class->refresh != NULL);
1888
1889         class->refresh (client, cancellable, callback, user_data);
1890 }
1891
1892 /**
1893  * e_client_refresh_finish:
1894  * @client: an #EClient
1895  * @result: a #GAsyncResult
1896  * @error: (out): a #GError to set an error, if any
1897  *
1898  * Finishes previous call of e_client_refresh().
1899  *
1900  * Returns: %TRUE if successful, %FALSE otherwise.
1901  *
1902  * Since: 3.2
1903  **/
1904 gboolean
1905 e_client_refresh_finish (EClient *client,
1906                          GAsyncResult *result,
1907                          GError **error)
1908 {
1909         EClientClass *class;
1910         gboolean res;
1911
1912         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1913
1914         class = E_CLIENT_GET_CLASS (client);
1915         g_return_val_if_fail (class != NULL, FALSE);
1916         g_return_val_if_fail (class->refresh_finish != NULL, FALSE);
1917
1918         res = class->refresh_finish (client, result, error);
1919
1920         if (error && *error)
1921                 e_client_unwrap_dbus_error (client, *error, error);
1922
1923         return res;
1924 }
1925
1926 /**
1927  * e_client_refresh_sync:
1928  * @client: an #EClient
1929  * @cancellable: a #GCancellable; can be %NULL
1930  * @error: (out): a #GError to set an error, if any
1931  *
1932  * Initiates refresh on the @client. Finishing the method doesn't mean
1933  * that the refresh is done, backend only notifies whether it started
1934  * refreshing or not. Use e_client_check_refresh_supported() to check
1935  * whether the backend supports this method.
1936  *
1937  * Returns: %TRUE if successful, %FALSE otherwise.
1938  *
1939  * Since: 3.2
1940  **/
1941 gboolean
1942 e_client_refresh_sync (EClient *client,
1943                        GCancellable *cancellable,
1944                        GError **error)
1945 {
1946         EClientClass *class;
1947         gboolean res;
1948
1949         class = E_CLIENT_GET_CLASS (client);
1950         g_return_val_if_fail (class != NULL, FALSE);
1951         g_return_val_if_fail (class->refresh_sync != NULL, FALSE);
1952
1953         res = class->refresh_sync (client, cancellable, error);
1954
1955         if (error && *error)
1956                 e_client_unwrap_dbus_error (client, *error, error);
1957
1958         return res;
1959 }
1960
1961 /**
1962  * e_client_util_slist_to_strv:
1963  * @strings: (element-type utf8): a #GSList of strings (const gchar *)
1964  *
1965  * Convert a list of strings into a %NULL-terminated array of strings.
1966  *
1967  * Returns: (transfer full): Newly allocated %NULL-terminated array of strings.
1968  * The returned pointer should be freed with g_strfreev().
1969  *
1970  * Note: Paired function for this is e_client_util_strv_to_slist().
1971  *
1972  * Since: 3.2
1973  *
1974  * Deprecated: 3.8: Use e_util_slist_to_strv() instead.
1975  **/
1976 gchar **
1977 e_client_util_slist_to_strv (const GSList *strings)
1978 {
1979         return e_util_slist_to_strv (strings);
1980 }
1981
1982 /**
1983  * e_client_util_strv_to_slist:
1984  * @strv: a %NULL-terminated array of strings (const gchar *)
1985  *
1986  * Convert a %NULL-terminated array of strings to a list of strings.
1987  *
1988  * Returns: (transfer full) (element-type utf8): Newly allocated #GSList of
1989  * newly allocated strings. The returned pointer should be freed with
1990  * e_client_util_free_string_slist().
1991  *
1992  * Note: Paired function for this is e_client_util_slist_to_strv().
1993  *
1994  * Since: 3.2
1995  *
1996  * Deprecated: 3.8: Use e_util_strv_to_slist() instead.
1997  **/
1998 GSList *
1999 e_client_util_strv_to_slist (const gchar * const *strv)
2000 {
2001         return e_util_strv_to_slist (strv);
2002 }
2003
2004 /**
2005  * e_client_util_copy_string_slist:
2006  * @copy_to: (element-type utf8) (allow-none): Where to copy; may be %NULL
2007  * @strings: (element-type utf8): #GSList of strings to be copied
2008  *
2009  * Copies the #GSList of strings to the end of @copy_to.
2010  *
2011  * Returns: (transfer full) (element-type utf8): New head of @copy_to.
2012  * The returned pointer can be freed with e_client_util_free_string_slist().
2013  *
2014  * Since: 3.2
2015  *
2016  * Deprecated: 3.8: Use e_util_copy_string_slist() instead.
2017  **/
2018 GSList *
2019 e_client_util_copy_string_slist (GSList *copy_to,
2020                                  const GSList *strings)
2021 {
2022         return e_util_copy_string_slist (copy_to, strings);
2023 }
2024
2025 /**
2026  * e_client_util_copy_object_slist:
2027  * @copy_to: (element-type GObject) (allow-none): Where to copy; may be %NULL
2028  * @objects: (element-type GObject): #GSList of #GObject<!-- -->s to be copied
2029  *
2030  * Copies a #GSList of #GObject<!-- -->s to the end of @copy_to.
2031  *
2032  * Returns: (transfer full) (element-type GObject): New head of @copy_to.
2033  * The returned pointer can be freed with e_client_util_free_object_slist().
2034  *
2035  * Since: 3.2
2036  *
2037  * Deprecated: 3.8: Use e_util_copy_object_slist() instead.
2038  **/
2039 GSList *
2040 e_client_util_copy_object_slist (GSList *copy_to,
2041                                  const GSList *objects)
2042 {
2043         return e_util_copy_object_slist (copy_to, objects);
2044 }
2045
2046 /**
2047  * e_client_util_free_string_slist:
2048  * @strings: (element-type utf8): a #GSList of strings (gchar *)
2049  *
2050  * Frees memory previously allocated by e_client_util_strv_to_slist().
2051  *
2052  * Since: 3.2
2053  *
2054  * Deprecated: 3.8: Use g_slist_free_full() instead.
2055  **/
2056 void
2057 e_client_util_free_string_slist (GSList *strings)
2058 {
2059         e_util_free_string_slist (strings);
2060 }
2061
2062 /**
2063  * e_client_util_free_object_slist:
2064  * @objects: (element-type GObject): a #GSList of #GObject<!-- -->s
2065  *
2066  * Calls g_object_unref() on each member of @objects and then frees @objects
2067  * itself.
2068  *
2069  * Since: 3.2
2070  *
2071  * Deprecated: 3.8: Use g_slist_free_full() instead.
2072  **/
2073 void
2074 e_client_util_free_object_slist (GSList *objects)
2075 {
2076         e_util_free_object_slist (objects);
2077 }
2078
2079 /**
2080  * e_client_util_parse_comma_strings:
2081  * @strings: string of comma-separated values
2082  *
2083  * Parses comma-separated list of values into #GSList.
2084  *
2085  * Returns: (transfer full) (element-type utf8): Newly allocated #GSList of
2086  * newly allocated strings corresponding to values parsed from @strings.
2087  * Free the returned pointer with e_client_util_free_string_slist().
2088  *
2089  * Since: 3.2
2090  **/
2091 GSList *
2092 e_client_util_parse_comma_strings (const gchar *strings)
2093 {
2094         GSList *strs_slist = NULL;
2095         gchar **strs_strv = NULL;
2096         gint ii;
2097
2098         if (!strings || !*strings)
2099                 return NULL;
2100
2101         strs_strv = g_strsplit (strings, ",", -1);
2102         g_return_val_if_fail (strs_strv != NULL, NULL);
2103
2104         for (ii = 0; strs_strv && strs_strv[ii]; ii++) {
2105                 gchar *str = g_strstrip (strs_strv[ii]);
2106
2107                 if (str && *str)
2108                         strs_slist = g_slist_prepend (strs_slist, g_strdup (str));
2109         }
2110
2111         g_strfreev (strs_strv);
2112
2113         return g_slist_reverse (strs_slist);
2114 }
2115
2116 void
2117 e_client_finish_async_without_dbus (EClient *client,
2118                                     GCancellable *cancellable,
2119                                     GAsyncReadyCallback callback,
2120                                     gpointer user_data,
2121                                     gpointer source_tag,
2122                                     gpointer op_res,
2123                                     GDestroyNotify destroy_op_res)
2124 {
2125         GCancellable *use_cancellable;
2126         GSimpleAsyncResult *simple;
2127         guint32 opid;
2128
2129         g_return_if_fail (E_IS_CLIENT (client));
2130         g_return_if_fail (callback != NULL);
2131         g_return_if_fail (source_tag != NULL);
2132
2133         use_cancellable = cancellable;
2134         if (!use_cancellable)
2135                 use_cancellable = g_cancellable_new ();
2136
2137         opid = e_client_register_op (client, use_cancellable);
2138         g_return_if_fail (opid > 0);
2139
2140         simple = g_simple_async_result_new (
2141                 G_OBJECT (client), callback, user_data, source_tag);
2142
2143         g_simple_async_result_set_check_cancellable (simple, cancellable);
2144
2145         g_simple_async_result_set_op_res_gpointer (
2146                 simple, op_res, destroy_op_res);
2147
2148         g_simple_async_result_complete_in_idle (simple);
2149
2150         g_object_unref (simple);
2151
2152         if (use_cancellable != cancellable)
2153                 g_object_unref (use_cancellable);
2154 }
2155
2156 GDBusProxy *
2157 e_client_get_dbus_proxy (EClient *client)
2158 {
2159         EClientClass *class;
2160
2161         g_return_val_if_fail (E_IS_CLIENT (client), NULL);
2162
2163         class = E_CLIENT_GET_CLASS (client);
2164         g_return_val_if_fail (class != NULL, NULL);
2165         g_return_val_if_fail (class->get_dbus_proxy != NULL, NULL);
2166
2167         return class->get_dbus_proxy (client);
2168 }
2169
2170 /**
2171  * e_client_unwrap_dbus_error:
2172  * @client: an #EClient
2173  * @dbus_error: a #GError returned bu D-Bus
2174  * @out_error: a #GError variable where to store the result
2175  *
2176  * Unwraps D-Bus error to local error. @dbus_error is automatically freed.
2177  * @dbus_erorr and @out_error can point to the same variable.
2178  *
2179  * Since: 3.2
2180  **/
2181 void
2182 e_client_unwrap_dbus_error (EClient *client,
2183                             GError *dbus_error,
2184                             GError **out_error)
2185 {
2186         EClientClass *class;
2187
2188         g_return_if_fail (E_IS_CLIENT (client));
2189
2190         class = E_CLIENT_GET_CLASS (client);
2191         g_return_if_fail (class != NULL);
2192         g_return_if_fail (class->unwrap_dbus_error != NULL);
2193
2194         if (!dbus_error || !out_error) {
2195                 if (dbus_error)
2196                         g_error_free (dbus_error);
2197         } else {
2198                 class->unwrap_dbus_error (client, dbus_error, out_error);
2199         }
2200 }
2201
2202 /**
2203  * e_client_util_unwrap_dbus_error:
2204  * @dbus_error: DBus #GError to unwrap
2205  * @client_error: (out): Resulting #GError; can be %NULL
2206  * @known_errors: List of known errors against which try to match
2207  * @known_errors_count: How many items are stored in @known_errors
2208  * @known_errors_domain: Error domain for @known_errors
2209  * @fail_when_none_matched: Whether to fail when none of @known_errors matches
2210  *
2211  * The function takes a @dbus_error and tries to find a match in @known_errors
2212  * for it, if it is a G_IO_ERROR, G_IO_ERROR_DBUS_ERROR. If it is anything else
2213  * then the @dbus_error is moved to @client_error.
2214  *
2215  * The @fail_when_none_matched influences behaviour. If it's %TRUE, and none of
2216  * @known_errors matches, or this is not a G_IO_ERROR_DBUS_ERROR, then %FALSE
2217  * is returned and the @client_error is left without change. Otherwise, the
2218  * @fail_when_none_matched is %FALSE, the error is always processed and will
2219  * result in E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR if none of @known_error
2220  * matches.
2221  *
2222  * Returns: Whether was @dbus_error processed into @client_error.
2223  *
2224  * Note: The @dbus_error is automatically freed if returned %TRUE.
2225  *
2226  * Since: 3.2
2227  **/
2228 gboolean
2229 e_client_util_unwrap_dbus_error (GError *dbus_error,
2230                                  GError **client_error,
2231                                  const EClientErrorsList *known_errors,
2232                                  guint known_errors_count,
2233                                  GQuark known_errors_domain,
2234                                  gboolean fail_when_none_matched)
2235 {
2236         if (!client_error) {
2237                 if (dbus_error)
2238                         g_error_free (dbus_error);
2239                 return TRUE;
2240         }
2241
2242         if (!dbus_error) {
2243                 *client_error = NULL;
2244                 return TRUE;
2245         }
2246
2247         if (dbus_error->domain == known_errors_domain) {
2248                 *client_error = dbus_error;
2249                 return TRUE;
2250         }
2251
2252         if (known_errors) {
2253                 if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
2254                         gchar *name;
2255                         gint ii;
2256
2257                         name = g_dbus_error_get_remote_error (dbus_error);
2258
2259                         for (ii = 0; ii < known_errors_count; ii++) {
2260                                 if (g_ascii_strcasecmp (known_errors[ii].name, name) == 0) {
2261                                         g_free (name);
2262
2263                                         g_dbus_error_strip_remote_error (dbus_error);
2264                                         *client_error = g_error_new_literal (known_errors_domain, known_errors[ii].err_code, dbus_error->message);
2265                                         g_error_free (dbus_error);
2266                                         return TRUE;
2267                                 }
2268                         }
2269
2270                         g_free (name);
2271                 }
2272         }
2273
2274         if (fail_when_none_matched)
2275                 return FALSE;
2276
2277         if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
2278                 g_dbus_error_strip_remote_error (dbus_error);
2279                 *client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, dbus_error->message);
2280                 g_error_free (dbus_error);
2281         } else {
2282                 g_dbus_error_strip_remote_error (dbus_error);
2283                 *client_error = dbus_error;
2284         }
2285
2286         return TRUE;
2287 }
2288
2289 typedef struct _EClientAsyncOpData
2290 {
2291         EClient *client;
2292         guint32 opid;
2293
2294         gpointer source_tag;
2295         gchar *res_op_data; /* optional string to set on a GAsyncResult object as "res-op-data" user data */
2296         GAsyncReadyCallback callback;
2297         gpointer user_data;
2298
2299         gboolean result; /* result of the finish function call */
2300
2301         /* only one can be non-NULL, and the type is telling which 'out' value is valid */
2302         EClientProxyFinishVoidFunc finish_void;
2303         EClientProxyFinishBooleanFunc finish_boolean;
2304         EClientProxyFinishStringFunc finish_string;
2305         EClientProxyFinishStrvFunc finish_strv;
2306         EClientProxyFinishUintFunc finish_uint;
2307
2308         union {
2309                 gboolean val_boolean;
2310                 gchar *val_string;
2311                 gchar **val_strv;
2312                 guint val_uint;
2313         } out;
2314 } EClientAsyncOpData;
2315
2316 static void
2317 async_data_free (EClientAsyncOpData *async_data)
2318 {
2319         g_return_if_fail (async_data != NULL);
2320         g_return_if_fail (async_data->client != NULL);
2321
2322         e_client_unregister_op (async_data->client, async_data->opid);
2323
2324         if (async_data->finish_string)
2325                 g_free (async_data->out.val_string);
2326         else if (async_data->finish_strv)
2327                 g_strfreev (async_data->out.val_strv);
2328
2329         g_object_unref (async_data->client);
2330         g_free (async_data->res_op_data);
2331         g_free (async_data);
2332 }
2333
2334 static gboolean
2335 complete_async_op_in_idle_cb (gpointer user_data)
2336 {
2337         GSimpleAsyncResult *simple = user_data;
2338         gint run_main_depth;
2339
2340         g_return_val_if_fail (simple != NULL, FALSE);
2341
2342         run_main_depth = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "run-main-depth"));
2343         if (run_main_depth < 1)
2344                 run_main_depth = 1;
2345
2346         /* do not receive in higher level than was initially run */
2347         if (g_main_depth () > run_main_depth) {
2348                 return TRUE;
2349         }
2350
2351         g_simple_async_result_complete (simple);
2352         g_object_unref (simple);
2353
2354         return FALSE;
2355 }
2356
2357 static void
2358 finish_async_op (EClientAsyncOpData *async_data,
2359                  const GError *error,
2360                  gboolean in_idle)
2361 {
2362         GSimpleAsyncResult *simple;
2363
2364         g_return_if_fail (async_data != NULL);
2365         g_return_if_fail (async_data->source_tag != NULL);
2366         g_return_if_fail (async_data->client != NULL);
2367
2368         simple = g_simple_async_result_new (G_OBJECT (async_data->client), async_data->callback, async_data->user_data, async_data->source_tag);
2369         g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free);
2370
2371         if (async_data->res_op_data)
2372                 g_object_set_data_full (G_OBJECT (simple), "res-op-data", g_strdup (async_data->res_op_data), g_free);
2373
2374         if (error != NULL)
2375                 g_simple_async_result_set_from_error (simple, error);
2376
2377         if (in_idle) {
2378                 g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
2379                 g_idle_add (complete_async_op_in_idle_cb, simple);
2380         } else {
2381                 g_simple_async_result_complete (simple);
2382                 g_object_unref (simple);
2383         }
2384 }
2385
2386 static void
2387 async_result_ready_cb (GObject *source_object,
2388                        GAsyncResult *result,
2389                        gpointer user_data)
2390 {
2391         GError *error = NULL;
2392         EClientAsyncOpData *async_data;
2393         EClient *client;
2394
2395         g_return_if_fail (result != NULL);
2396         g_return_if_fail (source_object != NULL);
2397
2398         async_data = user_data;
2399         g_return_if_fail (async_data != NULL);
2400         g_return_if_fail (async_data->client != NULL);
2401
2402         client = async_data->client;
2403         g_return_if_fail (e_client_get_dbus_proxy (client) == G_DBUS_PROXY (source_object));
2404
2405         if (async_data->finish_void)
2406                 async_data->result = async_data->finish_void (G_DBUS_PROXY (source_object), result, &error);
2407         else if (async_data->finish_boolean)
2408                 async_data->result = async_data->finish_boolean (G_DBUS_PROXY (source_object), result, &async_data->out.val_boolean, &error);
2409         else if (async_data->finish_string)
2410                 async_data->result = async_data->finish_string (G_DBUS_PROXY (source_object), result, &async_data->out.val_string, &error);
2411         else if (async_data->finish_strv)
2412                 async_data->result = async_data->finish_strv (G_DBUS_PROXY (source_object), result, &async_data->out.val_strv, &error);
2413         else if (async_data->finish_uint)
2414                 async_data->result = async_data->finish_uint (G_DBUS_PROXY (source_object), result, &async_data->out.val_uint, &error);
2415         else
2416                 g_warning ("%s: Do not know how to finish async operation", G_STRFUNC);
2417
2418         finish_async_op (async_data, error, FALSE);
2419
2420         if (error != NULL)
2421                 g_error_free (error);
2422 }
2423
2424 static EClientAsyncOpData *
2425 prepare_async_data (EClient *client,
2426                     GCancellable *cancellable,
2427                     GAsyncReadyCallback callback,
2428                     gpointer user_data,
2429                     gpointer source_tag,
2430                     gboolean error_report_only,
2431                     EClientProxyFinishVoidFunc finish_void,
2432                     EClientProxyFinishBooleanFunc finish_boolean,
2433                     EClientProxyFinishStringFunc finish_string,
2434                     EClientProxyFinishStrvFunc finish_strv,
2435                     EClientProxyFinishUintFunc finish_uint,
2436                     GDBusProxy **proxy,
2437                     GCancellable **out_cancellable)
2438 {
2439         EClientAsyncOpData *async_data;
2440         GCancellable *use_cancellable;
2441         guint32 opid;
2442
2443         g_return_val_if_fail (client != NULL, NULL);
2444         g_return_val_if_fail (callback != NULL, NULL);
2445         g_return_val_if_fail (source_tag != NULL, NULL);
2446
2447         if (!error_report_only) {
2448                 g_return_val_if_fail (proxy != NULL, NULL);
2449                 g_return_val_if_fail (out_cancellable != NULL, NULL);
2450                 g_return_val_if_fail (finish_void || finish_boolean || finish_string || finish_strv || finish_uint, NULL);
2451
2452                 if (finish_void) {
2453                         g_return_val_if_fail (finish_boolean == NULL, NULL);
2454                         g_return_val_if_fail (finish_string == NULL, NULL);
2455                         g_return_val_if_fail (finish_strv == NULL, NULL);
2456                         g_return_val_if_fail (finish_uint == NULL, NULL);
2457                 }
2458
2459                 if (finish_boolean) {
2460                         g_return_val_if_fail (finish_void == NULL, NULL);
2461                         g_return_val_if_fail (finish_string == NULL, NULL);
2462                         g_return_val_if_fail (finish_strv == NULL, NULL);
2463                         g_return_val_if_fail (finish_uint == NULL, NULL);
2464                 }
2465
2466                 if (finish_string) {
2467                         g_return_val_if_fail (finish_void == NULL, NULL);
2468                         g_return_val_if_fail (finish_boolean == NULL, NULL);
2469                         g_return_val_if_fail (finish_strv == NULL, NULL);
2470                         g_return_val_if_fail (finish_uint == NULL, NULL);
2471                 }
2472
2473                 if (finish_strv) {
2474                         g_return_val_if_fail (finish_void == NULL, NULL);
2475                         g_return_val_if_fail (finish_boolean == NULL, NULL);
2476                         g_return_val_if_fail (finish_string == NULL, NULL);
2477                         g_return_val_if_fail (finish_uint == NULL, NULL);
2478                 }
2479
2480                 if (finish_uint) {
2481                         g_return_val_if_fail (finish_void == NULL, NULL);
2482                         g_return_val_if_fail (finish_boolean == NULL, NULL);
2483                         g_return_val_if_fail (finish_string == NULL, NULL);
2484                         g_return_val_if_fail (finish_strv == NULL, NULL);
2485                 }
2486
2487                 *proxy = e_client_get_dbus_proxy (client);
2488                 if (!*proxy)
2489                         return NULL;
2490         }
2491
2492         use_cancellable = cancellable;
2493         if (!use_cancellable)
2494                 use_cancellable = g_cancellable_new ();
2495
2496         opid = e_client_register_op (client, use_cancellable);
2497         async_data = g_new0 (EClientAsyncOpData, 1);
2498         async_data->client = g_object_ref (client);
2499         async_data->opid = opid;
2500         async_data->source_tag = source_tag;
2501         async_data->callback = callback;
2502         async_data->user_data = user_data;
2503         async_data->finish_void = finish_void;
2504         async_data->finish_boolean = finish_boolean;
2505         async_data->finish_string = finish_string;
2506         async_data->finish_strv = finish_strv;
2507         async_data->finish_uint = finish_uint;
2508
2509         /* EClient from e_client_register_op() took ownership of the use_cancellable */
2510         if (use_cancellable != cancellable)
2511                 g_object_unref (use_cancellable);
2512
2513         if (out_cancellable)
2514                 *out_cancellable = use_cancellable;
2515
2516         return async_data;
2517 }
2518
2519 void
2520 e_client_proxy_return_async_error (EClient *client,
2521                                    const GError *error,
2522                                    GAsyncReadyCallback callback,
2523                                    gpointer user_data,
2524                                    gpointer source_tag)
2525 {
2526         EClientAsyncOpData *async_data;
2527
2528         g_return_if_fail (E_IS_CLIENT (client));
2529         g_return_if_fail (error != NULL);
2530         g_return_if_fail (callback != NULL);
2531
2532         async_data = prepare_async_data (client, NULL, callback, user_data, source_tag, TRUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2533         g_return_if_fail (async_data != NULL);
2534
2535         finish_async_op (async_data, error, TRUE);
2536 }
2537
2538 void
2539 e_client_proxy_call_void (EClient *client,
2540                           GCancellable *cancellable,
2541                           GAsyncReadyCallback callback,
2542                           gpointer user_data,
2543                           gpointer source_tag,
2544                           void (*func) (GDBusProxy *proxy,
2545                                         GCancellable *cancellable,
2546                                         GAsyncReadyCallback callback,
2547                                         gpointer user_data),
2548                           EClientProxyFinishVoidFunc finish_void,
2549                           EClientProxyFinishBooleanFunc finish_boolean,
2550                           EClientProxyFinishStringFunc finish_string,
2551                           EClientProxyFinishStrvFunc finish_strv,
2552                           EClientProxyFinishUintFunc finish_uint)
2553 {
2554         EClientAsyncOpData *async_data;
2555         GDBusProxy *proxy = NULL;
2556
2557         g_return_if_fail (E_IS_CLIENT (client));
2558         g_return_if_fail (callback != NULL);
2559         g_return_if_fail (source_tag != NULL);
2560         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2561
2562         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2563         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2564
2565         func (proxy, cancellable, async_result_ready_cb, async_data);
2566 }
2567
2568 void
2569 e_client_proxy_call_boolean (EClient *client,
2570                              gboolean in_boolean,
2571                              GCancellable *cancellable,
2572                              GAsyncReadyCallback callback,
2573                              gpointer user_data,
2574                              gpointer source_tag,
2575                              void (*func) (GDBusProxy *proxy,
2576                                            gboolean in_boolean,
2577                                            GCancellable *cancellable,
2578                                            GAsyncReadyCallback callback,
2579                                            gpointer user_data),
2580                              EClientProxyFinishVoidFunc finish_void,
2581                              EClientProxyFinishBooleanFunc finish_boolean,
2582                              EClientProxyFinishStringFunc finish_string,
2583                              EClientProxyFinishStrvFunc finish_strv,
2584                              EClientProxyFinishUintFunc finish_uint)
2585 {
2586         EClientAsyncOpData *async_data;
2587         GDBusProxy *proxy = NULL;
2588
2589         g_return_if_fail (E_IS_CLIENT (client));
2590         g_return_if_fail (callback != NULL);
2591         g_return_if_fail (source_tag != NULL);
2592         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2593
2594         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2595         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2596
2597         func (proxy, in_boolean, cancellable, async_result_ready_cb, async_data);
2598 }
2599
2600 void
2601 e_client_proxy_call_string (EClient *client,
2602                             const gchar *in_string,
2603                             GCancellable *cancellable,
2604                             GAsyncReadyCallback callback,
2605                             gpointer user_data,
2606                             gpointer source_tag,
2607                             void (*func) (GDBusProxy *proxy,
2608                                           const gchar *in_string,
2609                                           GCancellable *cancellable,
2610                                           GAsyncReadyCallback callback,
2611                                           gpointer user_data),
2612                             EClientProxyFinishVoidFunc finish_void,
2613                             EClientProxyFinishBooleanFunc finish_boolean,
2614                             EClientProxyFinishStringFunc finish_string,
2615                             EClientProxyFinishStrvFunc finish_strv,
2616                             EClientProxyFinishUintFunc finish_uint)
2617 {
2618         EClientAsyncOpData *async_data;
2619         GDBusProxy *proxy = NULL;
2620
2621         g_return_if_fail (E_IS_CLIENT (client));
2622         g_return_if_fail (callback != NULL);
2623         g_return_if_fail (source_tag != NULL);
2624         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2625         e_client_return_async_if_fail (in_string != NULL, client, callback, user_data, source_tag);
2626
2627         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2628         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2629
2630         func (proxy, in_string, cancellable, async_result_ready_cb, async_data);
2631 }
2632
2633 void
2634 e_client_proxy_call_string_with_res_op_data (EClient *client,
2635                                              const gchar *in_string,
2636                                              GCancellable *cancellable,
2637                                              GAsyncReadyCallback callback,
2638                                              gpointer user_data,
2639                                              gpointer source_tag,
2640                                              const gchar *res_op_data,
2641                                              void (*func) (GDBusProxy *proxy,
2642                                                            const gchar *in_string,
2643                                                            GCancellable *cancellable,
2644                                                            GAsyncReadyCallback callback,
2645                                                            gpointer user_data),
2646                                              EClientProxyFinishVoidFunc finish_void,
2647                                              EClientProxyFinishBooleanFunc finish_boolean,
2648                                              EClientProxyFinishStringFunc finish_string,
2649                                              EClientProxyFinishStrvFunc finish_strv,
2650                                              EClientProxyFinishUintFunc finish_uint)
2651 {
2652         EClientAsyncOpData *async_data;
2653         GDBusProxy *proxy = NULL;
2654
2655         g_return_if_fail (E_IS_CLIENT (client));
2656         g_return_if_fail (callback != NULL);
2657         g_return_if_fail (source_tag != NULL);
2658         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2659         e_client_return_async_if_fail (in_string != NULL, client, callback, user_data, source_tag);
2660
2661         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2662         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2663
2664         async_data->res_op_data = g_strdup (res_op_data);
2665
2666         func (proxy, in_string, cancellable, async_result_ready_cb, async_data);
2667 }
2668
2669 void
2670 e_client_proxy_call_strv (EClient *client,
2671                           const gchar * const *in_strv,
2672                           GCancellable *cancellable,
2673                           GAsyncReadyCallback callback,
2674                           gpointer user_data,
2675                           gpointer source_tag,
2676                           void (*func) (GDBusProxy *proxy,
2677                                         const gchar * const * in_strv,
2678                                         GCancellable *cancellable,
2679                                         GAsyncReadyCallback callback,
2680                                         gpointer user_data),
2681                           EClientProxyFinishVoidFunc finish_void,
2682                           EClientProxyFinishBooleanFunc finish_boolean,
2683                           EClientProxyFinishStringFunc finish_string,
2684                           EClientProxyFinishStrvFunc finish_strv,
2685                           EClientProxyFinishUintFunc finish_uint)
2686 {
2687         EClientAsyncOpData *async_data;
2688         GDBusProxy *proxy = NULL;
2689
2690         g_return_if_fail (E_IS_CLIENT (client));
2691         g_return_if_fail (callback != NULL);
2692         g_return_if_fail (source_tag != NULL);
2693         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2694         e_client_return_async_if_fail (in_strv != NULL, client, callback, user_data, source_tag);
2695
2696         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2697         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2698
2699         func (proxy, in_strv, cancellable, async_result_ready_cb, async_data);
2700 }
2701
2702 void
2703 e_client_proxy_call_uint (EClient *client,
2704                           guint in_uint,
2705                           GCancellable *cancellable,
2706                           GAsyncReadyCallback callback,
2707                           gpointer user_data,
2708                           gpointer source_tag,
2709                           void (*func) (GDBusProxy *proxy,
2710                                         guint in_uint,
2711                                         GCancellable *cancellable,
2712                                         GAsyncReadyCallback callback,
2713                                         gpointer user_data),
2714                           EClientProxyFinishVoidFunc finish_void,
2715                           EClientProxyFinishBooleanFunc finish_boolean,
2716                           EClientProxyFinishStringFunc finish_string,
2717                           EClientProxyFinishStrvFunc finish_strv,
2718                           EClientProxyFinishUintFunc finish_uint)
2719 {
2720         EClientAsyncOpData *async_data;
2721         GDBusProxy *proxy = NULL;
2722
2723         g_return_if_fail (E_IS_CLIENT (client));
2724         g_return_if_fail (callback != NULL);
2725         g_return_if_fail (source_tag != NULL);
2726         e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
2727
2728         async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
2729         e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
2730
2731         func (proxy, in_uint, cancellable, async_result_ready_cb, async_data);
2732 }
2733
2734 gboolean
2735 e_client_proxy_call_finish_void (EClient *client,
2736                                  GAsyncResult *result,
2737                                  GError **error,
2738                                  gpointer source_tag)
2739 {
2740         GSimpleAsyncResult *simple;
2741         GError *local_error = NULL;
2742         EClientAsyncOpData *async_data;
2743
2744         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2745         g_return_val_if_fail (result != NULL, FALSE);
2746         g_return_val_if_fail (source_tag != NULL, FALSE);
2747         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
2748
2749         simple = G_SIMPLE_ASYNC_RESULT (result);
2750
2751         if (g_simple_async_result_propagate_error (simple, &local_error)) {
2752                 e_client_unwrap_dbus_error (client, local_error, error);
2753                 return FALSE;
2754         }
2755
2756         async_data = g_simple_async_result_get_op_res_gpointer (simple);
2757         g_return_val_if_fail (async_data != NULL, FALSE);
2758
2759         return async_data->result;
2760 }
2761
2762 gboolean
2763 e_client_proxy_call_finish_boolean (EClient *client,
2764                                     GAsyncResult *result,
2765                                     gboolean *out_boolean,
2766                                     GError **error,
2767                                     gpointer source_tag)
2768 {
2769         GSimpleAsyncResult *simple;
2770         GError *local_error = NULL;
2771         EClientAsyncOpData *async_data;
2772
2773         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2774         g_return_val_if_fail (result != NULL, FALSE);
2775         g_return_val_if_fail (source_tag != NULL, FALSE);
2776         g_return_val_if_fail (out_boolean != NULL, FALSE);
2777         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
2778
2779         simple = G_SIMPLE_ASYNC_RESULT (result);
2780
2781         if (g_simple_async_result_propagate_error (simple, &local_error)) {
2782                 e_client_unwrap_dbus_error (client, local_error, error);
2783                 return FALSE;
2784         }
2785
2786         async_data = g_simple_async_result_get_op_res_gpointer (simple);
2787         g_return_val_if_fail (async_data != NULL, FALSE);
2788
2789         *out_boolean = async_data->out.val_boolean;
2790
2791         return async_data->result;
2792 }
2793
2794 gboolean
2795 e_client_proxy_call_finish_string (EClient *client,
2796                                    GAsyncResult *result,
2797                                    gchar **out_string,
2798                                    GError **error,
2799                                    gpointer source_tag)
2800 {
2801         GSimpleAsyncResult *simple;
2802         GError *local_error = NULL;
2803         EClientAsyncOpData *async_data;
2804
2805         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2806         g_return_val_if_fail (result != NULL, FALSE);
2807         g_return_val_if_fail (source_tag != NULL, FALSE);
2808         g_return_val_if_fail (out_string != NULL, FALSE);
2809         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
2810
2811         simple = G_SIMPLE_ASYNC_RESULT (result);
2812
2813         if (g_simple_async_result_propagate_error (simple, &local_error)) {
2814                 e_client_unwrap_dbus_error (client, local_error, error);
2815                 return FALSE;
2816         }
2817
2818         async_data = g_simple_async_result_get_op_res_gpointer (simple);
2819         g_return_val_if_fail (async_data != NULL, FALSE);
2820
2821         *out_string = async_data->out.val_string;
2822         async_data->out.val_string = NULL;
2823
2824         return async_data->result;
2825 }
2826
2827 gboolean
2828 e_client_proxy_call_finish_strv (EClient *client,
2829                                  GAsyncResult *result,
2830                                  gchar ***out_strv,
2831                                  GError **error,
2832                                  gpointer source_tag)
2833 {
2834         GSimpleAsyncResult *simple;
2835         GError *local_error = NULL;
2836         EClientAsyncOpData *async_data;
2837
2838         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2839         g_return_val_if_fail (result != NULL, FALSE);
2840         g_return_val_if_fail (source_tag != NULL, FALSE);
2841         g_return_val_if_fail (out_strv != NULL, FALSE);
2842         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
2843
2844         simple = G_SIMPLE_ASYNC_RESULT (result);
2845
2846         if (g_simple_async_result_propagate_error (simple, &local_error)) {
2847                 e_client_unwrap_dbus_error (client, local_error, error);
2848                 return FALSE;
2849         }
2850
2851         async_data = g_simple_async_result_get_op_res_gpointer (simple);
2852         g_return_val_if_fail (async_data != NULL, FALSE);
2853
2854         *out_strv = async_data->out.val_strv;
2855         async_data->out.val_strv = NULL;
2856
2857         return async_data->result;
2858 }
2859
2860 gboolean
2861 e_client_proxy_call_finish_uint (EClient *client,
2862                                  GAsyncResult *result,
2863                                  guint *out_uint,
2864                                  GError **error,
2865                                  gpointer source_tag)
2866 {
2867         GSimpleAsyncResult *simple;
2868         GError *local_error = NULL;
2869         EClientAsyncOpData *async_data;
2870
2871         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2872         g_return_val_if_fail (result != NULL, FALSE);
2873         g_return_val_if_fail (source_tag != NULL, FALSE);
2874         g_return_val_if_fail (out_uint != NULL, FALSE);
2875         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
2876
2877         simple = G_SIMPLE_ASYNC_RESULT (result);
2878
2879         if (g_simple_async_result_propagate_error (simple, &local_error)) {
2880                 e_client_unwrap_dbus_error (client, local_error, error);
2881                 return FALSE;
2882         }
2883
2884         async_data = g_simple_async_result_get_op_res_gpointer (simple);
2885         g_return_val_if_fail (async_data != NULL, FALSE);
2886
2887         *out_uint = async_data->out.val_uint;
2888
2889         return async_data->result;
2890 }
2891
2892 #define SYNC_CALL_TEMPLATE(_out_test,_the_call)                 \
2893         GDBusProxy *proxy;                                      \
2894         GCancellable *use_cancellable;                          \
2895         guint32 opid;                                           \
2896         gboolean result;                                        \
2897         GError *local_error = NULL;                             \
2898                                                                 \
2899         g_return_val_if_fail (E_IS_CLIENT (client), FALSE);     \
2900         g_return_val_if_fail (func != NULL, FALSE);             \
2901         g_return_val_if_fail (_out_test != NULL, FALSE);        \
2902                                                                 \
2903         proxy = e_client_get_dbus_proxy (client);               \
2904         g_return_val_if_fail (proxy != NULL, FALSE);            \
2905                                                                 \
2906         use_cancellable = cancellable;                          \
2907         if (!use_cancellable)                                   \
2908                 use_cancellable = g_cancellable_new ();         \
2909                                                                 \
2910         g_object_ref (client);                                  \
2911         opid = e_client_register_op (client, use_cancellable);  \
2912                                                                 \
2913         result = func _the_call;                                \
2914                                                                 \
2915         e_client_unregister_op (client, opid);                  \
2916         g_object_unref (client);                                \
2917                                                                 \
2918         if (use_cancellable != cancellable)                     \
2919                 g_object_unref (use_cancellable);               \
2920                                                                 \
2921         e_client_unwrap_dbus_error (client, local_error, error);\
2922                                                                 \
2923         return result;
2924
2925 gboolean
2926 e_client_proxy_call_sync_void__void (EClient *client,
2927                                      GCancellable *cancellable,
2928                                      GError **error,
2929                                      gboolean (*func) (GDBusProxy *proxy,
2930                                                        GCancellable *cancellable,
2931                                                        GError **error))
2932 {
2933         SYNC_CALL_TEMPLATE (client, (proxy, use_cancellable, &local_error))
2934 }
2935
2936 gboolean
2937 e_client_proxy_call_sync_void__boolean (EClient *client,
2938                                         gboolean *out_boolean,
2939                                         GCancellable *cancellable,
2940                                         GError **error,
2941                                         gboolean (*func) (GDBusProxy *proxy,
2942                                                           gboolean *out_boolean,
2943                                                           GCancellable *cancellable,
2944                                                           GError **error))
2945 {
2946         SYNC_CALL_TEMPLATE (out_boolean, (proxy, out_boolean, use_cancellable, &local_error))
2947 }
2948
2949 gboolean
2950 e_client_proxy_call_sync_void__string (EClient *client,
2951                                        gchar **out_string,
2952                                        GCancellable *cancellable,
2953                                        GError **error,
2954                                        gboolean (*func) (GDBusProxy *proxy,
2955                                                          gchar **out_string,
2956                                                          GCancellable *cancellable,
2957                                                          GError **error))
2958 {
2959         SYNC_CALL_TEMPLATE (out_string, (proxy, out_string, use_cancellable, &local_error))
2960 }
2961
2962 gboolean
2963 e_client_proxy_call_sync_void__strv (EClient *client,
2964                                      gchar ***out_strv,
2965                                      GCancellable *cancellable,
2966                                      GError **error,
2967                                      gboolean (*func) (GDBusProxy *proxy,
2968                                                        gchar ***out_strv,
2969                                                        GCancellable *cancellable,
2970                                                        GError **error))
2971 {
2972         SYNC_CALL_TEMPLATE (out_strv, (proxy, out_strv, use_cancellable, &local_error))
2973 }
2974
2975 gboolean
2976 e_client_proxy_call_sync_void__uint (EClient *client,
2977                                      guint *out_uint,
2978                                      GCancellable *cancellable,
2979                                      GError **error,
2980                                      gboolean (*func) (GDBusProxy *proxy,
2981                                                        guint *out_uint,
2982                                                        GCancellable *cancellable,
2983                                                        GError **error))
2984 {
2985         SYNC_CALL_TEMPLATE (out_uint, (proxy, out_uint, use_cancellable, &local_error))
2986 }
2987
2988 gboolean
2989 e_client_proxy_call_sync_boolean__void (EClient *client,
2990                                         gboolean in_boolean,
2991                                         GCancellable *cancellable,
2992                                         GError **error,
2993                                         gboolean (*func) (GDBusProxy *proxy,
2994                                                           gboolean in_boolean,
2995                                                           GCancellable *cancellable,
2996                                                           GError **error))
2997 {
2998         SYNC_CALL_TEMPLATE (client, (proxy, in_boolean, use_cancellable, &local_error))
2999 }
3000
3001 gboolean
3002 e_client_proxy_call_sync_boolean__boolean (EClient *client,
3003                                            gboolean in_boolean,
3004                                            gboolean *out_boolean,
3005                                            GCancellable *cancellable,
3006                                            GError **error,
3007                                            gboolean (*func) (GDBusProxy *proxy,
3008                                                              gboolean in_boolean,
3009                                                              gboolean *out_boolean,
3010                                                              GCancellable *cancellable,
3011                                                              GError **error))
3012 {
3013         SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_boolean, out_boolean, use_cancellable, &local_error))
3014 }
3015
3016 gboolean
3017 e_client_proxy_call_sync_boolean__string (EClient *client,
3018                                           gboolean in_boolean,
3019                                           gchar **out_string,
3020                                           GCancellable *cancellable,
3021                                           GError **error,
3022                                           gboolean (*func) (GDBusProxy *proxy,
3023                                                             gboolean in_boolean,
3024                                                             gchar **out_string,
3025                                                             GCancellable *cancellable,
3026                                                             GError **error))
3027 {
3028         SYNC_CALL_TEMPLATE (out_string, (proxy, in_boolean, out_string, use_cancellable, &local_error))
3029 }
3030
3031 gboolean
3032 e_client_proxy_call_sync_boolean__strv (EClient *client,
3033                                         gboolean in_boolean,
3034                                         gchar ***out_strv,
3035                                         GCancellable *cancellable,
3036                                         GError **error,
3037                                         gboolean (*func) (GDBusProxy *proxy,
3038                                                           gboolean in_boolean,
3039                                                           gchar ***out_strv,
3040                                                           GCancellable *cancellable,
3041                                                           GError **error))
3042 {
3043         SYNC_CALL_TEMPLATE (out_strv, (proxy, in_boolean, out_strv, use_cancellable, &local_error))
3044 }
3045
3046 gboolean
3047 e_client_proxy_call_sync_boolean__uint (EClient *client,
3048                                         gboolean in_boolean,
3049                                         guint *out_uint,
3050                                         GCancellable *cancellable,
3051                                         GError **error,
3052                                         gboolean (*func) (GDBusProxy *proxy,
3053                                                           gboolean in_boolean,
3054                                                           guint *out_uint,
3055                                                           GCancellable *cancellable,
3056                                                           GError **error))
3057 {
3058         SYNC_CALL_TEMPLATE (out_uint, (proxy, in_boolean, out_uint, use_cancellable, &local_error))
3059 }
3060
3061 gboolean
3062 e_client_proxy_call_sync_string__void (EClient *client,
3063                                        const gchar *in_string,
3064                                        GCancellable *cancellable,
3065                                        GError **error,
3066                                        gboolean (*func) (GDBusProxy *proxy,
3067                                                          const gchar *in_string,
3068                                                          GCancellable *cancellable,
3069                                                          GError **error))
3070 {
3071         SYNC_CALL_TEMPLATE (client, (proxy, in_string, use_cancellable, &local_error))
3072 }
3073
3074 gboolean
3075 e_client_proxy_call_sync_string__boolean (EClient *client,
3076                                           const gchar *in_string,
3077                                           gboolean *out_boolean,
3078                                           GCancellable *cancellable,
3079                                           GError **error,
3080                                           gboolean (*func) (GDBusProxy *proxy,
3081                                                             const gchar *in_string,
3082                                                             gboolean *out_boolean,
3083                                                             GCancellable *cancellable,
3084                                                             GError **error))
3085 {
3086         SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_string, out_boolean, use_cancellable, &local_error))
3087 }
3088
3089 gboolean
3090 e_client_proxy_call_sync_string__string (EClient *client,
3091                                          const gchar *in_string,
3092                                          gchar **out_string,
3093                                          GCancellable *cancellable,
3094                                          GError **error,
3095                                          gboolean (*func) (GDBusProxy *proxy,
3096                                                            const gchar *in_string,
3097                                                            gchar **out_string,
3098                                                            GCancellable *cancellable,
3099                                                            GError **error))
3100 {
3101         SYNC_CALL_TEMPLATE (out_string, (proxy, in_string, out_string, use_cancellable, &local_error))
3102 }
3103
3104 gboolean
3105 e_client_proxy_call_sync_string__strv (EClient *client,
3106                                        const gchar *in_string,
3107                                        gchar ***out_strv,
3108                                        GCancellable *cancellable,
3109                                        GError **error,
3110                                        gboolean (*func) (GDBusProxy *proxy,
3111                                                          const gchar *in_string,
3112                                                          gchar ***out_strv,
3113                                                          GCancellable *cancellable,
3114                                                          GError **error))
3115 {
3116         SYNC_CALL_TEMPLATE (out_strv, (proxy, in_string, out_strv, use_cancellable, &local_error))
3117 }
3118
3119 gboolean
3120 e_client_proxy_call_sync_string__uint (EClient *client,
3121                                        const gchar *in_string,
3122                                        guint *out_uint,
3123                                        GCancellable *cancellable,
3124                                        GError **error,
3125                                        gboolean (*func) (GDBusProxy *proxy,
3126                                                          const gchar *in_string,
3127                                                          guint *out_uint,
3128                                                          GCancellable *cancellable,
3129                                                          GError **error))
3130 {
3131         SYNC_CALL_TEMPLATE (out_uint, (proxy, in_string, out_uint, use_cancellable, &local_error))
3132 }
3133
3134 gboolean
3135 e_client_proxy_call_sync_strv__void (EClient *client,
3136                                      const gchar * const *in_strv,
3137                                      GCancellable *cancellable,
3138                                      GError **error,
3139                                      gboolean (*func) (GDBusProxy *proxy,
3140                                                        const gchar * const *in_strv,
3141                                                        GCancellable *cancellable,
3142                                                        GError **error))
3143 {
3144         SYNC_CALL_TEMPLATE (client, (proxy, in_strv, use_cancellable, &local_error))
3145 }
3146
3147 gboolean
3148 e_client_proxy_call_sync_strv__boolean (EClient *client,
3149                                         const gchar * const *in_strv,
3150                                         gboolean *out_boolean,
3151                                         GCancellable *cancellable,
3152                                         GError **error,
3153                                         gboolean (*func) (GDBusProxy *proxy,
3154                                                           const gchar * const *in_strv,
3155                                                           gboolean *out_boolean,
3156                                                           GCancellable *cancellable,
3157                                                           GError **error))
3158 {
3159         SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_strv, out_boolean, use_cancellable, &local_error))
3160 }
3161
3162 gboolean
3163 e_client_proxy_call_sync_strv__string (EClient *client,
3164                                        const gchar * const *in_strv,
3165                                        gchar **out_string,
3166                                        GCancellable *cancellable,
3167                                        GError **error,
3168                                        gboolean (*func) (GDBusProxy *proxy,
3169                                                          const gchar * const *in_strv,
3170                                                          gchar **out_string,
3171                                                          GCancellable *cancellable,
3172                                                          GError **error))
3173 {
3174         SYNC_CALL_TEMPLATE (out_string, (proxy, in_strv, out_string, use_cancellable, &local_error))
3175 }
3176
3177 gboolean
3178 e_client_proxy_call_sync_strv__strv (EClient *client,
3179                                      const gchar * const *in_strv,
3180                                      gchar ***out_strv,
3181                                      GCancellable *cancellable,
3182                                      GError **error,
3183                                      gboolean (*func) (GDBusProxy *proxy,
3184                                                        const gchar * const *in_strv,
3185                                                        gchar ***out_strv,
3186                                                        GCancellable *cancellable,
3187                                                        GError **error))
3188 {
3189         SYNC_CALL_TEMPLATE (out_strv, (proxy, in_strv, out_strv, use_cancellable, &local_error))
3190 }
3191
3192 gboolean
3193 e_client_proxy_call_sync_strv__uint (EClient *client,
3194                                      const gchar * const *in_strv,
3195                                      guint *out_uint,
3196                                      GCancellable *cancellable,
3197                                      GError **error,
3198                                      gboolean (*func) (GDBusProxy *proxy,
3199                                                        const gchar * const *in_strv,
3200                                                        guint *out_uint,
3201                                                        GCancellable *cancellable,
3202                                                        GError **error))
3203 {
3204         SYNC_CALL_TEMPLATE (out_uint, (proxy, in_strv, out_uint, use_cancellable, &local_error))
3205 }
3206
3207 gboolean
3208 e_client_proxy_call_sync_uint__void (EClient *client,
3209                                      guint in_uint,
3210                                      GCancellable *cancellable,
3211                                      GError **error,
3212                                      gboolean (*func) (GDBusProxy *proxy,
3213                                                        guint in_uint,
3214                                                        GCancellable *cancellable,
3215                                                        GError **error))
3216 {
3217         SYNC_CALL_TEMPLATE (client, (proxy, in_uint, use_cancellable, &local_error))
3218 }
3219
3220 gboolean
3221 e_client_proxy_call_sync_uint__boolean (EClient *client,
3222                                         guint in_uint,
3223                                         gboolean *out_boolean,
3224                                         GCancellable *cancellable,
3225                                         GError **error,
3226                                         gboolean (*func) (GDBusProxy *proxy,
3227                                                           guint in_uint,
3228                                                           gboolean *out_boolean,
3229                                                           GCancellable *cancellable,
3230                                                           GError **error))
3231 {
3232         SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_uint, out_boolean, use_cancellable, &local_error))
3233 }
3234
3235 gboolean
3236 e_client_proxy_call_sync_uint__string (EClient *client,
3237                                        guint in_uint,
3238                                        gchar **out_string,
3239                                        GCancellable *cancellable,
3240                                        GError **error,
3241                                        gboolean (*func) (GDBusProxy *proxy,
3242                                                          guint in_uint,
3243                                                          gchar **out_string,
3244                                                          GCancellable *cancellable,
3245                                                          GError **error))
3246 {
3247         SYNC_CALL_TEMPLATE (out_string, (proxy, in_uint, out_string, use_cancellable, &local_error))
3248 }
3249
3250 gboolean
3251 e_client_proxy_call_sync_uint__strv (EClient *client,
3252                                      guint in_uint,
3253                                      gchar ***out_strv,
3254                                      GCancellable *cancellable,
3255                                      GError **error,
3256                                      gboolean (*func) (GDBusProxy *proxy,
3257                                                        guint in_uint,
3258                                                        gchar ***out_strv,
3259                                                        GCancellable *cancellable,
3260                                                        GError **error))
3261 {
3262         SYNC_CALL_TEMPLATE (out_strv, (proxy, in_uint, out_strv, use_cancellable, &local_error))
3263 }
3264
3265 gboolean
3266 e_client_proxy_call_sync_uint__uint (EClient *client,
3267                                      guint in_uint,
3268                                      guint *out_uint,
3269                                      GCancellable *cancellable,
3270                                      GError **error,
3271                                      gboolean (*func) (GDBusProxy *proxy,
3272                                                        guint in_uint,
3273                                                        guint *out_uint,
3274                                                        GCancellable *cancellable,
3275                                                        GError **error))
3276 {
3277         SYNC_CALL_TEMPLATE (out_uint, (proxy, in_uint, out_uint, use_cancellable, &local_error))
3278 }
3279
3280 #undef SYNC_CALL_TEMPLATE