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