1 /*
2 * e-client.c
3 *
4 * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
5 *
6 * This library is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 /* TODO The next time we have a good excuse to break libedataserver's API,
21 * I'd like to purge all the deprecated cruft here and convert EClient
22 * from a GObjectClass to a GTypeInterface, implemented by EBookClient
23 * and ECalClient. Then we could just bind the "online", "readonly"
24 * and "capabilities" properties to equivalent GDBusProxy properties
25 * and kill e-client-private.h. Would simplify things. --mbarnes
26 */
27
28 /**
29 * SECTION: e-client
30 * @include: libedataserver/libedataserver.h
31 * @short_description: Base class for client handles
32 *
33 * This class provides some base functionality for clients
34 * such as #EBookClient and #ECalClient.
35 **/
36
37 #include "evolution-data-server-config.h"
38
39 #include <glib/gi18n-lib.h>
40 #include <gio/gio.h>
41
42 #include <libedataserver/e-data-server-util.h>
43
44 #include "e-flag.h"
45
46 #include "e-client.h"
47 #include "e-client-private.h"
48
49 typedef struct _AsyncContext AsyncContext;
50
51 struct _EClientPrivate {
52 GRecMutex prop_mutex;
53
54 ESource *source;
55 gboolean online;
56 gboolean readonly;
57 GSList *capabilities;
58 GMainContext *main_context;
59 gchar *bus_name;
60 };
61
62 struct _AsyncContext {
63 gchar *capabilities;
64 gchar *prop_name;
65 gchar *prop_value;
66 };
67
68 enum {
69 PROP_0,
70 PROP_CAPABILITIES,
71 PROP_MAIN_CONTEXT,
72 PROP_ONLINE,
73 PROP_OPENED,
74 PROP_READONLY,
75 PROP_SOURCE
76 };
77
78 enum {
79 OPENED,
80 BACKEND_ERROR,
81 BACKEND_DIED,
82 BACKEND_PROPERTY_CHANGED,
83 LAST_SIGNAL
84 };
85
86 static guint signals[LAST_SIGNAL];
87
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(EClient,e_client,G_TYPE_OBJECT)88 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (EClient, e_client, G_TYPE_OBJECT)
89
90 static void
91 async_context_free (AsyncContext *async_context)
92 {
93 g_free (async_context->capabilities);
94 g_free (async_context->prop_name);
95 g_free (async_context->prop_value);
96
97 g_slice_free (AsyncContext, async_context);
98 }
99
100 /*
101 * Well-known client backend properties, which are common for each #EClient:
102 * @CLIENT_BACKEND_PROPERTY_OPENED: Is set to "TRUE" or "FALSE" depending
103 * whether the backend is fully opened.
104 * @CLIENT_BACKEND_PROPERTY_OPENING: Is set to "TRUE" or "FALSE" depending
105 * whether the backend is processing its opening phase.
106 * @CLIENT_BACKEND_PROPERTY_ONLINE: Is set to "TRUE" or "FALSE" depending
107 * on the backend's loaded state. See also e_client_is_online().
108 * @CLIENT_BACKEND_PROPERTY_READONLY: Is set to "TRUE" or "FALSE" depending
109 * on the backend's readonly state. See also e_client_is_readonly().
110 * @CLIENT_BACKEND_PROPERTY_CACHE_DIR: Local folder with cached data used
111 * by the backend.
112 * @CLIENT_BACKEND_PROPERTY_CAPABILITIES: Retrieves comma-separated list
113 * of capabilities supported by the backend. Preferred method of retreiving
114 * and working with capabilities is e_client_get_capabilities() and
115 * e_client_check_capability().
116 */
117
118 G_DEFINE_QUARK (e-client-error-quark, e_client_error)
119
120 /**
121 * e_client_error_to_string:
122 * @code: an #EClientError error code
123 *
124 * Get localized human readable description of the given error code.
125 *
126 * Returns: Localized human readable description of the given error code
127 *
128 * Since: 3.2
129 **/
130 const gchar *
e_client_error_to_string(EClientError code)131 e_client_error_to_string (EClientError code)
132 {
133 switch (code) {
134 case E_CLIENT_ERROR_INVALID_ARG:
135 return _("Invalid argument");
136 case E_CLIENT_ERROR_BUSY:
137 return _("Backend is busy");
138 case E_CLIENT_ERROR_SOURCE_NOT_LOADED:
139 return _("Source not loaded");
140 case E_CLIENT_ERROR_SOURCE_ALREADY_LOADED:
141 return _("Source already loaded");
142 case E_CLIENT_ERROR_AUTHENTICATION_FAILED:
143 return _("Authentication failed");
144 case E_CLIENT_ERROR_AUTHENTICATION_REQUIRED:
145 return _("Authentication required");
146 case E_CLIENT_ERROR_REPOSITORY_OFFLINE:
147 return _("Repository offline");
148 case E_CLIENT_ERROR_OFFLINE_UNAVAILABLE:
149 /* Translators: This means that the EClient does not
150 * support offline mode, or it's not set to by a user,
151 * thus it is unavailable while user is not connected. */
152 return _("Offline unavailable");
153 case E_CLIENT_ERROR_PERMISSION_DENIED:
154 return _("Permission denied");
155 case E_CLIENT_ERROR_CANCELLED:
156 return _("Cancelled");
157 case E_CLIENT_ERROR_COULD_NOT_CANCEL:
158 return _("Could not cancel");
159 case E_CLIENT_ERROR_NOT_SUPPORTED:
160 return _("Not supported");
161 case E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD:
162 return _("Unsupported authentication method");
163 case E_CLIENT_ERROR_TLS_NOT_AVAILABLE:
164 return _("TLS not available");
165 case E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED:
166 return _("Search size limit exceeded");
167 case E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED:
168 return _("Search time limit exceeded");
169 case E_CLIENT_ERROR_INVALID_QUERY:
170 return _("Invalid query");
171 case E_CLIENT_ERROR_QUERY_REFUSED:
172 return _("Query refused");
173 case E_CLIENT_ERROR_DBUS_ERROR:
174 return _("D-Bus error");
175 case E_CLIENT_ERROR_OTHER_ERROR:
176 return _("Other error");
177 case E_CLIENT_ERROR_NOT_OPENED:
178 return _("Backend is not opened yet");
179 case E_CLIENT_ERROR_OUT_OF_SYNC:
180 return _("Object is out of sync");
181 }
182
183 return _("Unknown error");
184 }
185
186 /**
187 * e_client_error_create:
188 * @code: an #EClientError code to create
189 * @custom_msg: (nullable): custom message to use for the error; can be %NULL
190 *
191 * Returns: (transfer full): a new #GError containing an #E_CLIENT_ERROR of the given
192 * @code. If the @custom_msg is NULL, then the error message is the one returned
193 * from e_client_error_to_string() for the @code, otherwise the given message is used.
194 * Returned pointer should be freed with g_error_free().
195 *
196 * Since: 3.2
197 **/
198 GError *
e_client_error_create(EClientError code,const gchar * custom_msg)199 e_client_error_create (EClientError code,
200 const gchar *custom_msg)
201 {
202 if (!custom_msg)
203 custom_msg = e_client_error_to_string (code);
204
205 return g_error_new_literal (E_CLIENT_ERROR, code, custom_msg);
206 }
207
208 /**
209 * e_client_error_create_fmt:
210 * @code: an #EClientError
211 * @format: (nullable): message format, or %NULL to use the default message for the @code
212 * @...: arguments for the format
213 *
214 * Similar as e_client_error_create(), only here, instead of custom_msg,
215 * is used a printf() format to create a custom message for the error.
216 *
217 * Returns: (transfer full): a newly allocated #GError, which should be
218 * freed with g_error_free(), when no longer needed.
219 * The #GError has set the custom message, or the default message for
220 * @code, when @format is %NULL.
221 *
222 * Since: 3.34
223 **/
224 GError *
e_client_error_create_fmt(EClientError code,const gchar * format,...)225 e_client_error_create_fmt (EClientError code,
226 const gchar *format,
227 ...)
228 {
229 GError *error;
230 gchar *custom_msg;
231 va_list ap;
232
233 if (!format)
234 return e_client_error_create (code, NULL);
235
236 va_start (ap, format);
237 custom_msg = g_strdup_vprintf (format, ap);
238 va_end (ap);
239
240 error = e_client_error_create (code, custom_msg);
241
242 g_free (custom_msg);
243
244 return error;
245 }
246
247 static void
client_set_source(EClient * client,ESource * source)248 client_set_source (EClient *client,
249 ESource *source)
250 {
251 g_return_if_fail (E_IS_SOURCE (source));
252 g_return_if_fail (client->priv->source == NULL);
253
254 client->priv->source = g_object_ref (source);
255 }
256
257 static void
client_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)258 client_set_property (GObject *object,
259 guint property_id,
260 const GValue *value,
261 GParamSpec *pspec)
262 {
263 switch (property_id) {
264 case PROP_ONLINE:
265 e_client_set_online (
266 E_CLIENT (object),
267 g_value_get_boolean (value));
268 return;
269
270 case PROP_SOURCE:
271 client_set_source (
272 E_CLIENT (object),
273 g_value_get_object (value));
274 return;
275 }
276
277 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
278 }
279
280 static void
client_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)281 client_get_property (GObject *object,
282 guint property_id,
283 GValue *value,
284 GParamSpec *pspec)
285 {
286 switch (property_id) {
287 case PROP_CAPABILITIES:
288 g_value_set_pointer (
289 value,
290 (gpointer) e_client_get_capabilities (
291 E_CLIENT (object)));
292 return;
293
294 case PROP_MAIN_CONTEXT:
295 g_value_take_boxed (
296 value,
297 e_client_ref_main_context (
298 E_CLIENT (object)));
299 return;
300
301 case PROP_ONLINE:
302 g_value_set_boolean (
303 value,
304 e_client_is_online (
305 E_CLIENT (object)));
306 return;
307
308 case PROP_OPENED:
309 g_value_set_boolean (
310 value,
311 e_client_is_opened (
312 E_CLIENT (object)));
313 return;
314
315 case PROP_READONLY:
316 g_value_set_boolean (
317 value,
318 e_client_is_readonly (
319 E_CLIENT (object)));
320 return;
321
322 case PROP_SOURCE:
323 g_value_set_object (
324 value,
325 e_client_get_source (
326 E_CLIENT (object)));
327 return;
328 }
329
330 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
331 }
332
333 static void
client_dispose(GObject * object)334 client_dispose (GObject *object)
335 {
336 EClientPrivate *priv;
337
338 priv = E_CLIENT (object)->priv;
339 g_clear_pointer (&priv->main_context, g_main_context_unref);
340 g_clear_object (&priv->source);
341
342 g_free (priv->bus_name);
343 priv->bus_name = NULL;
344
345 /* Chain up to parent's dispose() method. */
346 G_OBJECT_CLASS (e_client_parent_class)->dispose (object);
347 }
348
349 static void
client_finalize(GObject * object)350 client_finalize (GObject *object)
351 {
352 EClientPrivate *priv;
353
354 priv = E_CLIENT (object)->priv;
355
356 g_slist_free_full (priv->capabilities, (GDestroyNotify) g_free);
357
358 g_rec_mutex_clear (&priv->prop_mutex);
359
360 /* Chain up to parent's finalize() method. */
361 G_OBJECT_CLASS (e_client_parent_class)->finalize (object);
362 }
363
364 static void
client_unwrap_dbus_error(EClient * client,GError * dbus_error,GError ** out_error)365 client_unwrap_dbus_error (EClient *client,
366 GError *dbus_error,
367 GError **out_error)
368 {
369 /* This method is deprecated. Make it a no-op. */
370
371 if (out_error != NULL)
372 *out_error = dbus_error;
373 }
374
375 /* Helper for client_retrieve_capabilities() */
376 static void
client_retrieve_capabilities_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)377 client_retrieve_capabilities_thread (GSimpleAsyncResult *simple,
378 GObject *source_object,
379 GCancellable *cancellable)
380 {
381 AsyncContext *async_context;
382 GError *error = NULL;
383
384 async_context = g_simple_async_result_get_op_res_gpointer (simple);
385
386 e_client_retrieve_capabilities_sync (
387 E_CLIENT (source_object),
388 &async_context->capabilities,
389 cancellable, &error);
390
391 if (error != NULL)
392 g_simple_async_result_take_error (simple, error);
393 }
394
395 static void
client_retrieve_capabilities(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)396 client_retrieve_capabilities (EClient *client,
397 GCancellable *cancellable,
398 GAsyncReadyCallback callback,
399 gpointer user_data)
400 {
401 GSimpleAsyncResult *simple;
402 AsyncContext *async_context;
403
404 async_context = g_slice_new0 (AsyncContext);
405
406 simple = g_simple_async_result_new (
407 G_OBJECT (client), callback,
408 user_data, client_retrieve_capabilities);
409
410 g_simple_async_result_set_check_cancellable (simple, cancellable);
411
412 g_simple_async_result_set_op_res_gpointer (
413 simple, async_context, (GDestroyNotify) async_context_free);
414
415 g_simple_async_result_run_in_thread (
416 simple, client_retrieve_capabilities_thread,
417 G_PRIORITY_DEFAULT, cancellable);
418
419 g_object_unref (simple);
420 }
421
422 static gboolean
client_retrieve_capabilities_finish(EClient * client,GAsyncResult * result,gchar ** capabilities,GError ** error)423 client_retrieve_capabilities_finish (EClient *client,
424 GAsyncResult *result,
425 gchar **capabilities,
426 GError **error)
427 {
428 GSimpleAsyncResult *simple;
429 AsyncContext *async_context;
430
431 g_return_val_if_fail (
432 g_simple_async_result_is_valid (
433 result, G_OBJECT (client),
434 client_retrieve_capabilities), FALSE);
435
436 simple = G_SIMPLE_ASYNC_RESULT (result);
437 async_context = g_simple_async_result_get_op_res_gpointer (simple);
438
439 if (g_simple_async_result_propagate_error (simple, error))
440 return FALSE;
441
442 g_return_val_if_fail (async_context->capabilities != NULL, FALSE);
443
444 if (capabilities != NULL) {
445 *capabilities = async_context->capabilities;
446 async_context->capabilities = NULL;
447 }
448
449 return TRUE;
450 }
451
452 static gboolean
client_retrieve_capabilities_sync(EClient * client,gchar ** capabilities,GCancellable * cancellable,GError ** error)453 client_retrieve_capabilities_sync (EClient *client,
454 gchar **capabilities,
455 GCancellable *cancellable,
456 GError **error)
457 {
458 return e_client_get_backend_property_sync (
459 client, CLIENT_BACKEND_PROPERTY_CAPABILITIES,
460 capabilities, cancellable, error);
461 }
462
463 /* Helper for client_get_backend_property() */
464 static void
client_get_backend_property_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)465 client_get_backend_property_thread (GSimpleAsyncResult *simple,
466 GObject *source_object,
467 GCancellable *cancellable)
468 {
469 AsyncContext *async_context;
470 GError *error = NULL;
471
472 async_context = g_simple_async_result_get_op_res_gpointer (simple);
473
474 e_client_get_backend_property_sync (
475 E_CLIENT (source_object),
476 async_context->prop_name,
477 &async_context->prop_value,
478 cancellable, &error);
479
480 if (error != NULL)
481 g_simple_async_result_take_error (simple, error);
482 }
483
484 static void
client_get_backend_property(EClient * client,const gchar * prop_name,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)485 client_get_backend_property (EClient *client,
486 const gchar *prop_name,
487 GCancellable *cancellable,
488 GAsyncReadyCallback callback,
489 gpointer user_data)
490 {
491 GSimpleAsyncResult *simple;
492 AsyncContext *async_context;
493
494 async_context = g_slice_new0 (AsyncContext);
495 async_context->prop_name = g_strdup (prop_name);
496
497 simple = g_simple_async_result_new (
498 G_OBJECT (client), callback,
499 user_data, client_get_backend_property);
500
501 g_simple_async_result_set_check_cancellable (simple, cancellable);
502
503 g_simple_async_result_set_op_res_gpointer (
504 simple, async_context, (GDestroyNotify) async_context_free);
505
506 g_simple_async_result_run_in_thread (
507 simple, client_get_backend_property_thread,
508 G_PRIORITY_DEFAULT, cancellable);
509
510 g_object_unref (simple);
511 }
512
513 static gboolean
client_get_backend_property_finish(EClient * client,GAsyncResult * result,gchar ** prop_value,GError ** error)514 client_get_backend_property_finish (EClient *client,
515 GAsyncResult *result,
516 gchar **prop_value,
517 GError **error)
518 {
519 GSimpleAsyncResult *simple;
520 AsyncContext *async_context;
521
522 g_return_val_if_fail (
523 g_simple_async_result_is_valid (
524 result, G_OBJECT (client),
525 client_get_backend_property), FALSE);
526
527 simple = G_SIMPLE_ASYNC_RESULT (result);
528 async_context = g_simple_async_result_get_op_res_gpointer (simple);
529
530 if (g_simple_async_result_propagate_error (simple, error))
531 return FALSE;
532
533 g_return_val_if_fail (async_context->prop_value != NULL, FALSE);
534
535 if (prop_value != NULL) {
536 *prop_value = async_context->prop_value;
537 async_context->prop_value = NULL;
538 }
539
540 return TRUE;
541 }
542
543 /* Helper for client_set_backend_property() */
544 static void
client_set_backend_property_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)545 client_set_backend_property_thread (GSimpleAsyncResult *simple,
546 GObject *source_object,
547 GCancellable *cancellable)
548 {
549 AsyncContext *async_context;
550 GError *error = NULL;
551
552 async_context = g_simple_async_result_get_op_res_gpointer (simple);
553
554 e_client_set_backend_property_sync (
555 E_CLIENT (source_object),
556 async_context->prop_name,
557 async_context->prop_value,
558 cancellable, &error);
559
560 if (error != NULL)
561 g_simple_async_result_take_error (simple, error);
562 }
563
564 static void
client_set_backend_property(EClient * client,const gchar * prop_name,const gchar * prop_value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)565 client_set_backend_property (EClient *client,
566 const gchar *prop_name,
567 const gchar *prop_value,
568 GCancellable *cancellable,
569 GAsyncReadyCallback callback,
570 gpointer user_data)
571 {
572 GSimpleAsyncResult *simple;
573 AsyncContext *async_context;
574
575 async_context = g_slice_new0 (AsyncContext);
576 async_context->prop_name = g_strdup (prop_name);
577 async_context->prop_value = g_strdup (prop_value);
578
579 simple = g_simple_async_result_new (
580 G_OBJECT (client), callback,
581 user_data, client_set_backend_property);
582
583 g_simple_async_result_set_check_cancellable (simple, cancellable);
584
585 g_simple_async_result_set_op_res_gpointer (
586 simple, async_context, (GDestroyNotify) async_context_free);
587
588 g_simple_async_result_run_in_thread (
589 simple, client_set_backend_property_thread,
590 G_PRIORITY_DEFAULT, cancellable);
591
592 g_object_unref (simple);
593 }
594
595 static gboolean
client_set_backend_property_finish(EClient * client,GAsyncResult * result,GError ** error)596 client_set_backend_property_finish (EClient *client,
597 GAsyncResult *result,
598 GError **error)
599 {
600 GSimpleAsyncResult *simple;
601
602 g_return_val_if_fail (
603 g_simple_async_result_is_valid (
604 result, G_OBJECT (client),
605 client_set_backend_property), FALSE);
606
607 simple = G_SIMPLE_ASYNC_RESULT (result);
608
609 /* Assume success unless a GError is set. */
610 return !g_simple_async_result_propagate_error (simple, error);
611 }
612
613 /* Helper for client_open() */
614 static void
client_open_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)615 client_open_thread (GSimpleAsyncResult *simple,
616 GObject *source_object,
617 GCancellable *cancellable)
618 {
619 GError *error = NULL;
620
621 e_client_open_sync (E_CLIENT (source_object), FALSE, cancellable, &error);
622
623 if (error != NULL)
624 g_simple_async_result_take_error (simple, error);
625 }
626
627 static void
client_open(EClient * client,gboolean only_if_exists,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)628 client_open (EClient *client,
629 gboolean only_if_exists,
630 GCancellable *cancellable,
631 GAsyncReadyCallback callback,
632 gpointer user_data)
633 {
634 GSimpleAsyncResult *simple;
635 AsyncContext *async_context;
636
637 async_context = g_slice_new0 (AsyncContext);
638
639 simple = g_simple_async_result_new (
640 G_OBJECT (client), callback, user_data, client_open);
641
642 g_simple_async_result_set_check_cancellable (simple, cancellable);
643
644 g_simple_async_result_set_op_res_gpointer (
645 simple, async_context, (GDestroyNotify) async_context_free);
646
647 g_simple_async_result_run_in_thread (
648 simple, client_open_thread,
649 G_PRIORITY_DEFAULT, cancellable);
650
651 g_object_unref (simple);
652 }
653
654 static gboolean
client_open_finish(EClient * client,GAsyncResult * result,GError ** error)655 client_open_finish (EClient *client,
656 GAsyncResult *result,
657 GError **error)
658 {
659 GSimpleAsyncResult *simple;
660
661 g_return_val_if_fail (
662 g_simple_async_result_is_valid (
663 result, G_OBJECT (client), client_open), FALSE);
664
665 simple = G_SIMPLE_ASYNC_RESULT (result);
666
667 /* Assume success unless a GError is set. */
668 return !g_simple_async_result_propagate_error (simple, error);
669 }
670
671 /* Helper for client_remove() */
672 static void
client_remove_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)673 client_remove_thread (GSimpleAsyncResult *simple,
674 GObject *source_object,
675 GCancellable *cancellable)
676 {
677 GError *error = NULL;
678
679 e_client_remove_sync (
680 E_CLIENT (source_object), cancellable, &error);
681
682 if (error != NULL)
683 g_simple_async_result_take_error (simple, error);
684 }
685
686 static void
client_remove(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)687 client_remove (EClient *client,
688 GCancellable *cancellable,
689 GAsyncReadyCallback callback,
690 gpointer user_data)
691 {
692 GSimpleAsyncResult *simple;
693
694 simple = g_simple_async_result_new (
695 G_OBJECT (client), callback, user_data, client_remove);
696
697 g_simple_async_result_set_check_cancellable (simple, cancellable);
698
699 g_simple_async_result_run_in_thread (
700 simple, client_remove_thread,
701 G_PRIORITY_DEFAULT, cancellable);
702
703 g_object_unref (simple);
704 }
705
706 static gboolean
client_remove_finish(EClient * client,GAsyncResult * result,GError ** error)707 client_remove_finish (EClient *client,
708 GAsyncResult *result,
709 GError **error)
710 {
711 GSimpleAsyncResult *simple;
712
713 g_return_val_if_fail (
714 g_simple_async_result_is_valid (
715 result, G_OBJECT (client), client_remove), FALSE);
716
717 simple = G_SIMPLE_ASYNC_RESULT (result);
718
719 /* Assume success unless a GError is set. */
720 return !g_simple_async_result_propagate_error (simple, error);
721 }
722
723 static gboolean
client_remove_sync(EClient * client,GCancellable * cancellable,GError ** error)724 client_remove_sync (EClient *client,
725 GCancellable *cancellable,
726 GError **error)
727 {
728 ESource *source;
729
730 source = e_client_get_source (client);
731
732 return e_source_remove_sync (source, cancellable, error);
733 }
734
735 /* Helper for client_refresh() */
736 static void
client_refresh_thread(GSimpleAsyncResult * simple,GObject * source_object,GCancellable * cancellable)737 client_refresh_thread (GSimpleAsyncResult *simple,
738 GObject *source_object,
739 GCancellable *cancellable)
740 {
741 GError *error = NULL;
742
743 e_client_refresh_sync (
744 E_CLIENT (source_object), cancellable, &error);
745
746 if (error != NULL)
747 g_simple_async_result_take_error (simple, error);
748 }
749
750 static void
client_refresh(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)751 client_refresh (EClient *client,
752 GCancellable *cancellable,
753 GAsyncReadyCallback callback,
754 gpointer user_data)
755 {
756 GSimpleAsyncResult *simple;
757
758 simple = g_simple_async_result_new (
759 G_OBJECT (client), callback, user_data, client_refresh);
760
761 g_simple_async_result_set_check_cancellable (simple, cancellable);
762
763 g_simple_async_result_run_in_thread (
764 simple, client_refresh_thread,
765 G_PRIORITY_DEFAULT, cancellable);
766
767 g_object_unref (simple);
768 }
769
770 static gboolean
client_refresh_finish(EClient * client,GAsyncResult * result,GError ** error)771 client_refresh_finish (EClient *client,
772 GAsyncResult *result,
773 GError **error)
774 {
775 GSimpleAsyncResult *simple;
776
777 g_return_val_if_fail (
778 g_simple_async_result_is_valid (
779 result, G_OBJECT (client), client_refresh), FALSE);
780
781 simple = G_SIMPLE_ASYNC_RESULT (result);
782
783 /* Assume success unless a GError is set. */
784 return !g_simple_async_result_propagate_error (simple, error);
785 }
786
787 static void
e_client_class_init(EClientClass * class)788 e_client_class_init (EClientClass *class)
789 {
790 GObjectClass *object_class;
791
792 object_class = G_OBJECT_CLASS (class);
793 object_class->set_property = client_set_property;
794 object_class->get_property = client_get_property;
795 object_class->dispose = client_dispose;
796 object_class->finalize = client_finalize;
797
798 class->unwrap_dbus_error = client_unwrap_dbus_error;
799 class->retrieve_capabilities = client_retrieve_capabilities;
800 class->retrieve_capabilities_finish = client_retrieve_capabilities_finish;
801 class->retrieve_capabilities_sync = client_retrieve_capabilities_sync;
802 class->get_backend_property = client_get_backend_property;
803 class->get_backend_property_finish = client_get_backend_property_finish;
804 class->set_backend_property = client_set_backend_property;
805 class->set_backend_property_finish = client_set_backend_property_finish;
806 class->open = client_open;
807 class->open_finish = client_open_finish;
808 class->remove = client_remove;
809 class->remove_finish = client_remove_finish;
810 class->remove_sync = client_remove_sync;
811 class->refresh = client_refresh;
812 class->refresh_finish = client_refresh_finish;
813
814 /**
815 * EClient:capabilities:
816 *
817 * The capabilities of this client
818 */
819 g_object_class_install_property (
820 object_class,
821 PROP_CAPABILITIES,
822 g_param_spec_pointer (
823 "capabilities",
824 "Capabilities",
825 "The capabilities of this client",
826 G_PARAM_READABLE |
827 G_PARAM_EXPLICIT_NOTIFY |
828 G_PARAM_STATIC_STRINGS));
829
830 /**
831 * EClient:main-context:
832 *
833 * The main loop context in which notifications for
834 * this client will be delivered.
835 */
836 g_object_class_install_property (
837 object_class,
838 PROP_MAIN_CONTEXT,
839 g_param_spec_boxed (
840 "main-context",
841 "Main Context",
842 "The main loop context on "
843 "which to attach event sources",
844 G_TYPE_MAIN_CONTEXT,
845 G_PARAM_READABLE |
846 G_PARAM_STATIC_STRINGS));
847
848 /**
849 * EClient:online:
850 *
851 * Whether this client's backing data is online.
852 */
853 g_object_class_install_property (
854 object_class,
855 PROP_ONLINE,
856 g_param_spec_boolean (
857 "online",
858 "Online",
859 "Whether this client is online",
860 FALSE,
861 G_PARAM_READWRITE |
862 G_PARAM_EXPLICIT_NOTIFY |
863 G_PARAM_STATIC_STRINGS));
864
865 /**
866 * EClient:opened:
867 *
868 * Whether this client is open and ready to use.
869 *
870 * Deprecated: 3.8: This property is no longer relevant and
871 * will always be %TRUE after successfully creating any concrete
872 * type of #EClient.
873 */
874 g_object_class_install_property (
875 object_class,
876 PROP_OPENED,
877 g_param_spec_boolean (
878 "opened",
879 "Opened",
880 "Whether this client is open and ready to use",
881 FALSE,
882 G_PARAM_READABLE |
883 G_PARAM_STATIC_STRINGS));
884
885 /**
886 * EClient:readonly:
887 *
888 * Whether this client's backing data is readonly.
889 */
890 g_object_class_install_property (
891 object_class,
892 PROP_READONLY,
893 g_param_spec_boolean (
894 "readonly",
895 "Read only",
896 "Whether this client's backing data is readonly",
897 FALSE,
898 G_PARAM_READABLE |
899 G_PARAM_STATIC_STRINGS));
900
901 /**
902 * EClient:source:
903 *
904 * The #ESource for which this client was created.
905 */
906 g_object_class_install_property (
907 object_class,
908 PROP_SOURCE,
909 g_param_spec_object (
910 "source",
911 "Source",
912 "The ESource for which this client was created",
913 E_TYPE_SOURCE,
914 G_PARAM_READWRITE |
915 G_PARAM_CONSTRUCT_ONLY |
916 G_PARAM_STATIC_STRINGS));
917
918 /**
919 * EClient::opened-signal: (skip)
920 *
921 * Deprecated: 3.8: This signal is no longer emitted.
922 **/
923 signals[OPENED] = g_signal_new (
924 "opened",
925 G_OBJECT_CLASS_TYPE (class),
926 G_SIGNAL_RUN_LAST |
927 G_SIGNAL_DEPRECATED,
928 G_STRUCT_OFFSET (EClientClass, opened),
929 NULL, NULL, NULL,
930 G_TYPE_NONE, 1,
931 G_TYPE_ERROR);
932
933 signals[BACKEND_ERROR] = g_signal_new (
934 "backend-error",
935 G_OBJECT_CLASS_TYPE (class),
936 G_SIGNAL_RUN_FIRST,
937 G_STRUCT_OFFSET (EClientClass, backend_error),
938 NULL, NULL, NULL,
939 G_TYPE_NONE, 1,
940 G_TYPE_STRING);
941
942 signals[BACKEND_DIED] = g_signal_new (
943 "backend-died",
944 G_OBJECT_CLASS_TYPE (class),
945 G_SIGNAL_RUN_LAST,
946 G_STRUCT_OFFSET (EClientClass, backend_died),
947 NULL, NULL, NULL,
948 G_TYPE_NONE, 0);
949
950 signals[BACKEND_PROPERTY_CHANGED] = g_signal_new (
951 "backend-property-changed",
952 G_OBJECT_CLASS_TYPE (class),
953 G_SIGNAL_RUN_LAST,
954 G_STRUCT_OFFSET (EClientClass, backend_property_changed),
955 NULL, NULL, NULL,
956 G_TYPE_NONE, 2,
957 G_TYPE_STRING,
958 G_TYPE_STRING);
959 }
960
961 static void
e_client_init(EClient * client)962 e_client_init (EClient *client)
963 {
964 client->priv = e_client_get_instance_private (client);
965
966 client->priv->readonly = FALSE;
967 client->priv->main_context = g_main_context_ref_thread_default ();
968
969 g_rec_mutex_init (&client->priv->prop_mutex);
970 }
971
972 /**
973 * e_client_get_source:
974 * @client: an #EClient
975 *
976 * Get the #ESource that this client has assigned.
977 *
978 * Returns: (transfer none): The source.
979 *
980 * Since: 3.2
981 **/
982 ESource *
e_client_get_source(EClient * client)983 e_client_get_source (EClient *client)
984 {
985 g_return_val_if_fail (E_IS_CLIENT (client), NULL);
986
987 return client->priv->source;
988 }
989
990 static void
client_ensure_capabilities(EClient * client)991 client_ensure_capabilities (EClient *client)
992 {
993 gchar *capabilities = NULL;
994
995 g_return_if_fail (E_IS_CLIENT (client));
996
997 if (client->priv->capabilities != NULL)
998 return;
999
1000 /* Despite appearances this function does not actually block. */
1001 e_client_get_backend_property_sync (
1002 client, CLIENT_BACKEND_PROPERTY_CAPABILITIES,
1003 &capabilities, NULL, NULL);
1004 e_client_set_capabilities (client, capabilities);
1005 g_free (capabilities);
1006 }
1007
1008 /**
1009 * e_client_get_capabilities:
1010 * @client: an #EClient
1011 *
1012 * Get list of strings with capabilities advertised by a backend.
1013 * This list, together with inner strings, is owned by the @client.
1014 * To check for individual capabilities use e_client_check_capability().
1015 *
1016 * Returns: (element-type utf8) (transfer none): #GSList of const strings
1017 * of capabilities
1018 *
1019 * Since: 3.2
1020 **/
1021 const GSList *
e_client_get_capabilities(EClient * client)1022 e_client_get_capabilities (EClient *client)
1023 {
1024 g_return_val_if_fail (E_IS_CLIENT (client), NULL);
1025
1026 client_ensure_capabilities (client);
1027
1028 return client->priv->capabilities;
1029 }
1030
1031 /**
1032 * e_client_ref_main_context:
1033 * @client: an #EClient
1034 *
1035 * Returns the #GMainContext on which event sources for @client are to
1036 * be attached.
1037 *
1038 * The returned #GMainContext is referenced for thread-safety and must be
1039 * unreferenced with g_main_context_unref() when finished with it.
1040 *
1041 * Returns: (transfer full): a #GMainContext
1042 *
1043 * Since: 3.8
1044 **/
1045 GMainContext *
e_client_ref_main_context(EClient * client)1046 e_client_ref_main_context (EClient *client)
1047 {
1048 g_return_val_if_fail (E_IS_CLIENT (client), NULL);
1049
1050 return g_main_context_ref (client->priv->main_context);
1051 }
1052
1053 /**
1054 * e_client_check_capability:
1055 * @client: an #EClient
1056 * @capability: a capability
1057 *
1058 * Check if backend supports particular capability.
1059 * To get all capabilities use e_client_get_capabilities().
1060 *
1061 * Returns: #GSList of const strings of capabilities
1062 *
1063 * Since: 3.2
1064 **/
1065 gboolean
e_client_check_capability(EClient * client,const gchar * capability)1066 e_client_check_capability (EClient *client,
1067 const gchar *capability)
1068 {
1069 GSList *iter;
1070
1071 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1072 g_return_val_if_fail (capability, FALSE);
1073
1074 g_rec_mutex_lock (&client->priv->prop_mutex);
1075
1076 client_ensure_capabilities (client);
1077
1078 for (iter = client->priv->capabilities; iter; iter = g_slist_next (iter)) {
1079 const gchar *cap = iter->data;
1080
1081 if (cap && g_ascii_strcasecmp (cap, capability) == 0) {
1082 g_rec_mutex_unlock (&client->priv->prop_mutex);
1083 return TRUE;
1084 }
1085 }
1086
1087 g_rec_mutex_unlock (&client->priv->prop_mutex);
1088
1089 return FALSE;
1090 }
1091
1092 /**
1093 * e_client_check_refresh_supported:
1094 * @client: A client.
1095 *
1096 * Checks whether a client supports explicit refreshing
1097 * (see e_client_refresh()).
1098 *
1099 * Returns: TRUE if the client supports refreshing, FALSE otherwise.
1100 *
1101 * Since: 3.2
1102 **/
1103 gboolean
e_client_check_refresh_supported(EClient * client)1104 e_client_check_refresh_supported (EClient *client)
1105 {
1106 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1107
1108 return e_client_check_capability (client, "refresh-supported");
1109 }
1110
1111 /* capabilities - comma-separated list of capabilities; can be NULL to unset */
1112 void
e_client_set_capabilities(EClient * client,const gchar * capabilities)1113 e_client_set_capabilities (EClient *client,
1114 const gchar *capabilities)
1115 {
1116 g_return_if_fail (E_IS_CLIENT (client));
1117
1118 g_rec_mutex_lock (&client->priv->prop_mutex);
1119
1120 g_slist_foreach (client->priv->capabilities, (GFunc) g_free, NULL);
1121 g_slist_free (client->priv->capabilities);
1122 client->priv->capabilities = e_client_util_parse_comma_strings (capabilities);
1123
1124 g_rec_mutex_unlock (&client->priv->prop_mutex);
1125
1126 g_object_notify (G_OBJECT (client), "capabilities");
1127 }
1128
1129 /**
1130 * e_client_is_readonly:
1131 * @client: an #EClient
1132 *
1133 * Check if this @client is read-only.
1134 *
1135 * Returns: %TRUE if this @client is read-only, otherwise %FALSE.
1136 *
1137 * Since: 3.2
1138 **/
1139 gboolean
e_client_is_readonly(EClient * client)1140 e_client_is_readonly (EClient *client)
1141 {
1142 g_return_val_if_fail (E_IS_CLIENT (client), TRUE);
1143
1144 return client->priv->readonly;
1145 }
1146
1147 void
e_client_set_readonly(EClient * client,gboolean readonly)1148 e_client_set_readonly (EClient *client,
1149 gboolean readonly)
1150 {
1151 g_return_if_fail (E_IS_CLIENT (client));
1152
1153 g_rec_mutex_lock (&client->priv->prop_mutex);
1154 if (client->priv->readonly == readonly) {
1155 g_rec_mutex_unlock (&client->priv->prop_mutex);
1156 return;
1157 }
1158
1159 client->priv->readonly = readonly;
1160
1161 g_rec_mutex_unlock (&client->priv->prop_mutex);
1162
1163 g_object_notify (G_OBJECT (client), "readonly");
1164 }
1165
1166 /**
1167 * e_client_is_online:
1168 * @client: an #EClient
1169 *
1170 * Check if this @client is connected.
1171 *
1172 * Returns: %TRUE if this @client is connected, otherwise %FALSE.
1173 *
1174 * Since: 3.2
1175 **/
1176 gboolean
e_client_is_online(EClient * client)1177 e_client_is_online (EClient *client)
1178 {
1179 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1180
1181 return client->priv->online;
1182 }
1183
1184 void
e_client_set_online(EClient * client,gboolean is_online)1185 e_client_set_online (EClient *client,
1186 gboolean is_online)
1187 {
1188 g_return_if_fail (E_IS_CLIENT (client));
1189
1190 /* newly connected/disconnected => make sure capabilities will be correct */
1191 e_client_set_capabilities (client, NULL);
1192
1193 g_rec_mutex_lock (&client->priv->prop_mutex);
1194 if (client->priv->online == is_online) {
1195 g_rec_mutex_unlock (&client->priv->prop_mutex);
1196 return;
1197 }
1198
1199 client->priv->online = is_online;
1200
1201 g_rec_mutex_unlock (&client->priv->prop_mutex);
1202
1203 g_object_notify (G_OBJECT (client), "online");
1204 }
1205
1206 /**
1207 * e_client_is_opened:
1208 * @client: an #EClient
1209 *
1210 * Check if this @client is fully opened. This includes
1211 * everything from e_client_open() call up to the authentication,
1212 * if required by a backend. Client cannot do any other operation
1213 * during the opening phase except of authenticate or cancel it.
1214 * Every other operation results in an %E_CLIENT_ERROR_BUSY error.
1215 *
1216 * Returns: always %TRUE
1217 *
1218 * Since: 3.2
1219 *
1220 * Deprecated: 3.8: Clients don't need to care if they're fully opened
1221 * anymore. This function always returns %TRUE.
1222 **/
1223 gboolean
e_client_is_opened(EClient * client)1224 e_client_is_opened (EClient *client)
1225 {
1226 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1227
1228 return TRUE;
1229 }
1230
1231 /**
1232 * e_client_cancel_all:
1233 * @client: an #EClient
1234 *
1235 * Cancels all pending operations started on @client.
1236 *
1237 * Since: 3.2
1238 *
1239 * Deprecated: 3.8: The function no longer does anything.
1240 **/
1241 void
e_client_cancel_all(EClient * client)1242 e_client_cancel_all (EClient *client)
1243 {
1244 /* Do nothing. */
1245 }
1246
1247 /**
1248 * e_client_retrieve_capabilities:
1249 * @client: an #EClient
1250 * @cancellable: a #GCancellable; can be %NULL
1251 * @callback: callback to call when a result is ready
1252 * @user_data: user data for the @callback
1253 *
1254 * Initiates retrieval of capabilities on the @client. This is usually
1255 * required only once, after the @client is opened. The returned value
1256 * is cached and any subsequent call of e_client_get_capabilities() and
1257 * e_client_check_capability() is using the cached value.
1258 * The call is finished by e_client_retrieve_capabilities_finish()
1259 * from the @callback.
1260 *
1261 * Since: 3.2
1262 *
1263 * Deprecated: 3.8: Use e_client_get_capabilities() instead.
1264 **/
1265 void
e_client_retrieve_capabilities(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1266 e_client_retrieve_capabilities (EClient *client,
1267 GCancellable *cancellable,
1268 GAsyncReadyCallback callback,
1269 gpointer user_data)
1270 {
1271 EClientClass *class;
1272
1273 g_return_if_fail (E_IS_CLIENT (client));
1274 g_return_if_fail (callback != NULL);
1275
1276 class = E_CLIENT_GET_CLASS (client);
1277 g_return_if_fail (class != NULL);
1278 g_return_if_fail (class->retrieve_capabilities != NULL);
1279
1280 class->retrieve_capabilities (client, cancellable, callback, user_data);
1281 }
1282
1283 /**
1284 * e_client_retrieve_capabilities_finish:
1285 * @client: an #EClient
1286 * @result: a #GAsyncResult
1287 * @capabilities: (out): Comma-separated list of capabilities of the @client
1288 * @error: a #GError to set an error, if any
1289 *
1290 * Finishes previous call of e_client_retrieve_capabilities().
1291 * Returned value of @capabilities should be freed with g_free(),
1292 * when no longer needed.
1293 *
1294 * Returns: %TRUE if successful, %FALSE otherwise.
1295 *
1296 * Since: 3.2
1297 *
1298 * Deprecated: 3.8: Use e_client_get_capabilities() instead.
1299 **/
1300 gboolean
e_client_retrieve_capabilities_finish(EClient * client,GAsyncResult * result,gchar ** capabilities,GError ** error)1301 e_client_retrieve_capabilities_finish (EClient *client,
1302 GAsyncResult *result,
1303 gchar **capabilities,
1304 GError **error)
1305 {
1306 EClientClass *class;
1307 gboolean res;
1308
1309 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1310 g_return_val_if_fail (capabilities != NULL, FALSE);
1311
1312 class = E_CLIENT_GET_CLASS (client);
1313 g_return_val_if_fail (class != NULL, FALSE);
1314 g_return_val_if_fail (class->retrieve_capabilities_finish != NULL, FALSE);
1315
1316 *capabilities = NULL;
1317 res = class->retrieve_capabilities_finish (
1318 client, result, capabilities, error);
1319
1320 e_client_set_capabilities (client, res ? *capabilities : NULL);
1321
1322 return res;
1323 }
1324
1325 /**
1326 * e_client_retrieve_capabilities_sync:
1327 * @client: an #EClient
1328 * @capabilities: (out): Comma-separated list of capabilities of the @client
1329 * @cancellable: a #GCancellable; can be %NULL
1330 * @error: a #GError to set an error, if any
1331 *
1332 * Initiates retrieval of capabilities on the @client. This is usually
1333 * required only once, after the @client is opened. The returned value
1334 * is cached and any subsequent call of e_client_get_capabilities() and
1335 * e_client_check_capability() is using the cached value. Returned value
1336 * of @capabilities should be freed with g_free(), when no longer needed.
1337 *
1338 * Returns: %TRUE if successful, %FALSE otherwise.
1339 *
1340 * Since: 3.2
1341 *
1342 * Deprecated: 3.8: Use e_client_get_capabilities() instead.
1343 **/
1344 gboolean
e_client_retrieve_capabilities_sync(EClient * client,gchar ** capabilities,GCancellable * cancellable,GError ** error)1345 e_client_retrieve_capabilities_sync (EClient *client,
1346 gchar **capabilities,
1347 GCancellable *cancellable,
1348 GError **error)
1349 {
1350 EClientClass *class;
1351 gboolean res = FALSE;
1352
1353 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1354 g_return_val_if_fail (capabilities != NULL, FALSE);
1355
1356 class = E_CLIENT_GET_CLASS (client);
1357 g_return_val_if_fail (class != NULL, FALSE);
1358 g_return_val_if_fail (class->retrieve_capabilities_sync != NULL, FALSE);
1359
1360 *capabilities = NULL;
1361 res = class->retrieve_capabilities_sync (
1362 client, capabilities, cancellable, error);
1363
1364 e_client_set_capabilities (client, res ? *capabilities : NULL);
1365
1366 return res;
1367 }
1368
1369 /**
1370 * e_client_get_backend_property:
1371 * @client: an #EClient
1372 * @prop_name: property name, whose value to retrieve; cannot be %NULL
1373 * @cancellable: a #GCancellable; can be %NULL
1374 * @callback: callback to call when a result is ready
1375 * @user_data: user data for the @callback
1376 *
1377 * Queries @client's backend for a property of name @prop_name.
1378 * The call is finished by e_client_get_backend_property_finish()
1379 * from the @callback.
1380 *
1381 * Since: 3.2
1382 **/
1383 void
e_client_get_backend_property(EClient * client,const gchar * prop_name,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1384 e_client_get_backend_property (EClient *client,
1385 const gchar *prop_name,
1386 GCancellable *cancellable,
1387 GAsyncReadyCallback callback,
1388 gpointer user_data)
1389 {
1390 EClientClass *class;
1391
1392 g_return_if_fail (callback != NULL);
1393 g_return_if_fail (E_IS_CLIENT (client));
1394 g_return_if_fail (prop_name != NULL);
1395
1396 class = E_CLIENT_GET_CLASS (client);
1397 g_return_if_fail (class != NULL);
1398 g_return_if_fail (class->get_backend_property != NULL);
1399
1400 class->get_backend_property (
1401 client, prop_name, cancellable, callback, user_data);
1402 }
1403
1404 /**
1405 * e_client_get_backend_property_finish:
1406 * @client: an #EClient
1407 * @result: a #GAsyncResult
1408 * @prop_value: (out): Retrieved backend property value; cannot be %NULL
1409 * @error: a #GError to set an error, if any
1410 *
1411 * Finishes previous call of e_client_get_backend_property().
1412 *
1413 * Returns: %TRUE if successful, %FALSE otherwise.
1414 *
1415 * Since: 3.2
1416 **/
1417 gboolean
e_client_get_backend_property_finish(EClient * client,GAsyncResult * result,gchar ** prop_value,GError ** error)1418 e_client_get_backend_property_finish (EClient *client,
1419 GAsyncResult *result,
1420 gchar **prop_value,
1421 GError **error)
1422 {
1423 EClientClass *class;
1424
1425 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1426 g_return_val_if_fail (prop_value != NULL, FALSE);
1427
1428 class = E_CLIENT_GET_CLASS (client);
1429 g_return_val_if_fail (class != NULL, FALSE);
1430 g_return_val_if_fail (class->get_backend_property_finish != NULL, FALSE);
1431
1432 return class->get_backend_property_finish (
1433 client, result, prop_value, error);
1434 }
1435
1436 /**
1437 * e_client_get_backend_property_sync:
1438 * @client: an #EClient
1439 * @prop_name: property name, whose value to retrieve; cannot be %NULL
1440 * @prop_value: (out): Retrieved backend property value; cannot be %NULL
1441 * @cancellable: a #GCancellable; can be %NULL
1442 * @error: a #GError to set an error, if any
1443 *
1444 * Queries @client's backend for a property of name @prop_name.
1445 *
1446 * Returns: %TRUE if successful, %FALSE otherwise.
1447 *
1448 * Since: 3.2
1449 **/
1450 gboolean
e_client_get_backend_property_sync(EClient * client,const gchar * prop_name,gchar ** prop_value,GCancellable * cancellable,GError ** error)1451 e_client_get_backend_property_sync (EClient *client,
1452 const gchar *prop_name,
1453 gchar **prop_value,
1454 GCancellable *cancellable,
1455 GError **error)
1456 {
1457 EClientClass *class;
1458
1459 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1460 g_return_val_if_fail (prop_name != NULL, FALSE);
1461 g_return_val_if_fail (prop_value != NULL, FALSE);
1462
1463 class = E_CLIENT_GET_CLASS (client);
1464 g_return_val_if_fail (class != NULL, FALSE);
1465 g_return_val_if_fail (class->get_backend_property_sync != NULL, FALSE);
1466
1467 return class->get_backend_property_sync (
1468 client, prop_name, prop_value, cancellable, error);
1469 }
1470
1471 /**
1472 * e_client_set_backend_property:
1473 * @client: an #EClient
1474 * @prop_name: property name, whose value to change; cannot be %NULL
1475 * @prop_value: property value, to set; cannot be %NULL
1476 * @cancellable: a #GCancellable; can be %NULL
1477 * @callback: callback to call when a result is ready
1478 * @user_data: user data for the @callback
1479 *
1480 * Sets @client's backend property of name @prop_name
1481 * to value @prop_value. The call is finished
1482 * by e_client_set_backend_property_finish() from the @callback.
1483 *
1484 * Since: 3.2
1485 *
1486 * Deprecated: 3.8: Clients cannot set backend properties. Any attempt
1487 * will fail with an %E_CLIENT_ERROR_NOT_SUPPORTED error.
1488 **/
1489 void
e_client_set_backend_property(EClient * client,const gchar * prop_name,const gchar * prop_value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1490 e_client_set_backend_property (EClient *client,
1491 const gchar *prop_name,
1492 const gchar *prop_value,
1493 GCancellable *cancellable,
1494 GAsyncReadyCallback callback,
1495 gpointer user_data)
1496 {
1497 EClientClass *class;
1498
1499 g_return_if_fail (callback != NULL);
1500 g_return_if_fail (E_IS_CLIENT (client));
1501 g_return_if_fail (prop_name != NULL);
1502 g_return_if_fail (prop_value != NULL);
1503
1504 class = E_CLIENT_GET_CLASS (client);
1505 g_return_if_fail (class != NULL);
1506 g_return_if_fail (class->set_backend_property != NULL);
1507
1508 class->set_backend_property (
1509 client, prop_name, prop_value,
1510 cancellable, callback, user_data);
1511 }
1512
1513 /**
1514 * e_client_set_backend_property_finish:
1515 * @client: an #EClient
1516 * @result: a #GAsyncResult
1517 * @error: a #GError to set an error, if any
1518 *
1519 * Finishes previous call of e_client_set_backend_property().
1520 *
1521 * Returns: %TRUE if successful, %FALSE otherwise.
1522 *
1523 * Since: 3.2
1524 *
1525 * Deprecated: 3.8: Clients cannot set backend properties. Any attempt
1526 * will fail with an %E_CLIENT_ERROR_NOT_SUPPORTED error.
1527 **/
1528 gboolean
e_client_set_backend_property_finish(EClient * client,GAsyncResult * result,GError ** error)1529 e_client_set_backend_property_finish (EClient *client,
1530 GAsyncResult *result,
1531 GError **error)
1532 {
1533 EClientClass *class;
1534
1535 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1536
1537 class = E_CLIENT_GET_CLASS (client);
1538 g_return_val_if_fail (class != NULL, FALSE);
1539 g_return_val_if_fail (class->set_backend_property_finish != NULL, FALSE);
1540
1541 return class->set_backend_property_finish (client, result, error);
1542 }
1543
1544 /**
1545 * e_client_set_backend_property_sync:
1546 * @client: an #EClient
1547 * @prop_name: property name, whose value to change; cannot be %NULL
1548 * @prop_value: property value, to set; cannot be %NULL
1549 * @cancellable: a #GCancellable; can be %NULL
1550 * @error: a #GError to set an error, if any
1551 *
1552 * Sets @client's backend property of name @prop_name
1553 * to value @prop_value.
1554 *
1555 * Returns: %TRUE if successful, %FALSE otherwise.
1556 *
1557 * Since: 3.2
1558 *
1559 * Deprecated: 3.8: Clients cannot set backend properties. Any attempt
1560 * will fail with an %E_CLIENT_ERROR_NOT_SUPPORTED error.
1561 **/
1562 gboolean
e_client_set_backend_property_sync(EClient * client,const gchar * prop_name,const gchar * prop_value,GCancellable * cancellable,GError ** error)1563 e_client_set_backend_property_sync (EClient *client,
1564 const gchar *prop_name,
1565 const gchar *prop_value,
1566 GCancellable *cancellable,
1567 GError **error)
1568 {
1569 EClientClass *class;
1570
1571 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1572 g_return_val_if_fail (prop_name != NULL, FALSE);
1573 g_return_val_if_fail (prop_value != NULL, FALSE);
1574
1575 class = E_CLIENT_GET_CLASS (client);
1576 g_return_val_if_fail (class != NULL, FALSE);
1577 g_return_val_if_fail (class->set_backend_property_sync != NULL, FALSE);
1578
1579 return class->set_backend_property_sync (
1580 client, prop_name, prop_value, cancellable, error);
1581 }
1582
1583 /**
1584 * e_client_open:
1585 * @client: an #EClient
1586 * @only_if_exists: this parameter is not used anymore
1587 * @cancellable: a #GCancellable; can be %NULL
1588 * @callback: callback to call when a result is ready
1589 * @user_data: user data for the @callback
1590 *
1591 * Opens the @client, making it ready for queries and other operations.
1592 * The call is finished by e_client_open_finish() from the @callback.
1593 *
1594 * Since: 3.2
1595 *
1596 * Deprecated: 3.8: Use e_book_client_connect() and
1597 * e_book_client_connect_finish() or
1598 * e_cal_client_connect() and
1599 * e_cal_client_connect_finish() instead.
1600 **/
1601 void
e_client_open(EClient * client,gboolean only_if_exists,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1602 e_client_open (EClient *client,
1603 gboolean only_if_exists,
1604 GCancellable *cancellable,
1605 GAsyncReadyCallback callback,
1606 gpointer user_data)
1607 {
1608 EClientClass *class;
1609
1610 g_return_if_fail (callback != NULL);
1611 g_return_if_fail (E_IS_CLIENT (client));
1612
1613 class = E_CLIENT_GET_CLASS (client);
1614 g_return_if_fail (class != NULL);
1615 g_return_if_fail (class->open != NULL);
1616
1617 class->open (client, only_if_exists, cancellable, callback, user_data);
1618 }
1619
1620 /**
1621 * e_client_open_finish:
1622 * @client: an #EClient
1623 * @result: a #GAsyncResult
1624 * @error: a #GError to set an error, if any
1625 *
1626 * Finishes previous call of e_client_open().
1627 *
1628 * Returns: %TRUE if successful, %FALSE otherwise.
1629 *
1630 * Since: 3.2
1631 *
1632 * Deprecated: 3.8: Use e_book_client_connect() and
1633 * e_book_client_connect_finish() or
1634 * e_cal_client_connect() and
1635 * e_cal_client_connect_finish() instead.
1636 **/
1637 gboolean
e_client_open_finish(EClient * client,GAsyncResult * result,GError ** error)1638 e_client_open_finish (EClient *client,
1639 GAsyncResult *result,
1640 GError **error)
1641 {
1642 EClientClass *class;
1643
1644 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1645
1646 class = E_CLIENT_GET_CLASS (client);
1647 g_return_val_if_fail (class != NULL, FALSE);
1648 g_return_val_if_fail (class->open_finish != NULL, FALSE);
1649
1650 return class->open_finish (client, result, error);
1651 }
1652
1653 /**
1654 * e_client_open_sync:
1655 * @client: an #EClient
1656 * @only_if_exists: this parameter is not used anymore
1657 * @cancellable: a #GCancellable; can be %NULL
1658 * @error: a #GError to set an error, if any
1659 *
1660 * Opens the @client, making it ready for queries and other operations.
1661 *
1662 * Returns: %TRUE if successful, %FALSE otherwise.
1663 *
1664 * Since: 3.2
1665 *
1666 * Deprecated: 3.8: Use e_book_client_connect_sync() or
1667 * e_cal_client_connect_sync() instead.
1668 **/
1669 gboolean
e_client_open_sync(EClient * client,gboolean only_if_exists,GCancellable * cancellable,GError ** error)1670 e_client_open_sync (EClient *client,
1671 gboolean only_if_exists,
1672 GCancellable *cancellable,
1673 GError **error)
1674 {
1675 EClientClass *class;
1676
1677 class = E_CLIENT_GET_CLASS (client);
1678 g_return_val_if_fail (class != NULL, FALSE);
1679 g_return_val_if_fail (class->open_sync != NULL, FALSE);
1680
1681 return class->open_sync (client, only_if_exists, cancellable, error);
1682 }
1683
1684 /**
1685 * e_client_remove:
1686 * @client: an #EClient
1687 * @cancellable: a #GCancellable; can be %NULL
1688 * @callback: callback to call when a result is ready
1689 * @user_data: user data for the @callback
1690 *
1691 * Removes the backing data for this #EClient. For example, with the file
1692 * backend this deletes the database file. You cannot get it back!
1693 * The call is finished by e_client_remove_finish() from the @callback.
1694 *
1695 * Since: 3.2
1696 *
1697 * Deprecated: 3.6: Use e_source_remove() instead.
1698 **/
1699 void
e_client_remove(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1700 e_client_remove (EClient *client,
1701 GCancellable *cancellable,
1702 GAsyncReadyCallback callback,
1703 gpointer user_data)
1704 {
1705 EClientClass *class;
1706
1707 g_return_if_fail (E_IS_CLIENT (client));
1708 g_return_if_fail (callback != NULL);
1709
1710 class = E_CLIENT_GET_CLASS (client);
1711 g_return_if_fail (class != NULL);
1712 g_return_if_fail (class->remove != NULL);
1713
1714 class->remove (client, cancellable, callback, user_data);
1715 }
1716
1717 /**
1718 * e_client_remove_finish:
1719 * @client: an #EClient
1720 * @result: a #GAsyncResult
1721 * @error: a #GError to set an error, if any
1722 *
1723 * Finishes previous call of e_client_remove().
1724 *
1725 * Returns: %TRUE if successful, %FALSE otherwise.
1726 *
1727 * Since: 3.2
1728 *
1729 * Deprecated: 3.6: Use e_source_remove_finish() instead.
1730 **/
1731 gboolean
e_client_remove_finish(EClient * client,GAsyncResult * result,GError ** error)1732 e_client_remove_finish (EClient *client,
1733 GAsyncResult *result,
1734 GError **error)
1735 {
1736 EClientClass *class;
1737
1738 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1739
1740 class = E_CLIENT_GET_CLASS (client);
1741 g_return_val_if_fail (class != NULL, FALSE);
1742 g_return_val_if_fail (class->remove_finish != NULL, FALSE);
1743
1744 return class->remove_finish (client, result, error);
1745 }
1746
1747 /**
1748 * e_client_remove_sync:
1749 * @client: an #EClient
1750 * @cancellable: a #GCancellable; can be %NULL
1751 * @error: a #GError to set an error, if any
1752 *
1753 * Removes the backing data for this #EClient. For example, with the file
1754 * backend this deletes the database file. You cannot get it back!
1755 *
1756 * Returns: %TRUE if successful, %FALSE otherwise.
1757 *
1758 * Since: 3.2
1759 *
1760 * Deprecated: 3.6: Use e_source_remove_sync() instead.
1761 **/
1762 gboolean
e_client_remove_sync(EClient * client,GCancellable * cancellable,GError ** error)1763 e_client_remove_sync (EClient *client,
1764 GCancellable *cancellable,
1765 GError **error)
1766 {
1767 EClientClass *class;
1768
1769 class = E_CLIENT_GET_CLASS (client);
1770 g_return_val_if_fail (class != NULL, FALSE);
1771 g_return_val_if_fail (class->remove_sync != NULL, FALSE);
1772
1773 return class->remove_sync (client, cancellable, error);
1774 }
1775
1776 /**
1777 * e_client_refresh:
1778 * @client: an #EClient
1779 * @cancellable: a #GCancellable; can be %NULL
1780 * @callback: callback to call when a result is ready
1781 * @user_data: user data for the @callback
1782 *
1783 * Initiates refresh on the @client. Finishing the method doesn't mean
1784 * that the refresh is done, backend only notifies whether it started
1785 * refreshing or not. Use e_client_check_refresh_supported() to check
1786 * whether the backend supports this method.
1787 * The call is finished by e_client_refresh_finish() from the @callback.
1788 *
1789 * Since: 3.2
1790 **/
1791 void
e_client_refresh(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1792 e_client_refresh (EClient *client,
1793 GCancellable *cancellable,
1794 GAsyncReadyCallback callback,
1795 gpointer user_data)
1796 {
1797 EClientClass *class;
1798
1799 g_return_if_fail (E_IS_CLIENT (client));
1800 g_return_if_fail (callback != NULL);
1801
1802 class = E_CLIENT_GET_CLASS (client);
1803 g_return_if_fail (class != NULL);
1804 g_return_if_fail (class->refresh != NULL);
1805
1806 class->refresh (client, cancellable, callback, user_data);
1807 }
1808
1809 /**
1810 * e_client_refresh_finish:
1811 * @client: an #EClient
1812 * @result: a #GAsyncResult
1813 * @error: a #GError to set an error, if any
1814 *
1815 * Finishes previous call of e_client_refresh().
1816 *
1817 * Returns: %TRUE if successful, %FALSE otherwise.
1818 *
1819 * Since: 3.2
1820 **/
1821 gboolean
e_client_refresh_finish(EClient * client,GAsyncResult * result,GError ** error)1822 e_client_refresh_finish (EClient *client,
1823 GAsyncResult *result,
1824 GError **error)
1825 {
1826 EClientClass *class;
1827
1828 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1829
1830 class = E_CLIENT_GET_CLASS (client);
1831 g_return_val_if_fail (class != NULL, FALSE);
1832 g_return_val_if_fail (class->refresh_finish != NULL, FALSE);
1833
1834 return class->refresh_finish (client, result, error);
1835 }
1836
1837 /**
1838 * e_client_refresh_sync:
1839 * @client: an #EClient
1840 * @cancellable: a #GCancellable; can be %NULL
1841 * @error: a #GError to set an error, if any
1842 *
1843 * Initiates refresh on the @client. Finishing the method doesn't mean
1844 * that the refresh is done, backend only notifies whether it started
1845 * refreshing or not. Use e_client_check_refresh_supported() to check
1846 * whether the backend supports this method.
1847 *
1848 * Returns: %TRUE if successful, %FALSE otherwise.
1849 *
1850 * Since: 3.2
1851 **/
1852 gboolean
e_client_refresh_sync(EClient * client,GCancellable * cancellable,GError ** error)1853 e_client_refresh_sync (EClient *client,
1854 GCancellable *cancellable,
1855 GError **error)
1856 {
1857 EClientClass *class;
1858
1859 class = E_CLIENT_GET_CLASS (client);
1860 g_return_val_if_fail (class != NULL, FALSE);
1861 g_return_val_if_fail (class->refresh_sync != NULL, FALSE);
1862
1863 return class->refresh_sync (client, cancellable, error);
1864 }
1865
1866 static void
client_wait_for_connected_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1867 client_wait_for_connected_thread (GTask *task,
1868 gpointer source_object,
1869 gpointer task_data,
1870 GCancellable *cancellable)
1871 {
1872 guint32 timeout_seconds;
1873 gboolean success;
1874 GError *local_error = NULL;
1875
1876 timeout_seconds = GPOINTER_TO_UINT (task_data);
1877 success = e_client_wait_for_connected_sync (E_CLIENT (source_object), timeout_seconds, cancellable, &local_error);
1878
1879 if (local_error != NULL) {
1880 g_task_return_error (task, local_error);
1881 } else {
1882 g_task_return_boolean (task, success);
1883 }
1884 }
1885
1886 /**
1887 * e_client_wait_for_connected:
1888 * @client: an #EClient
1889 * @timeout_seconds: a timeout for the wait, in seconds
1890 * @cancellable: a #GCancellable; or %NULL
1891 * @callback: callback to call when a result is ready
1892 * @user_data: user data for the @callback
1893 *
1894 * Asynchronously waits until the @client is connected (according
1895 * to @ESource::connection-status property), but not longer than @timeout_seconds.
1896 *
1897 * The call is finished by e_client_wait_for_connected_finish() from
1898 * the @callback.
1899 *
1900 * Since: 3.16
1901 **/
1902 void
e_client_wait_for_connected(EClient * client,guint32 timeout_seconds,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1903 e_client_wait_for_connected (EClient *client,
1904 guint32 timeout_seconds,
1905 GCancellable *cancellable,
1906 GAsyncReadyCallback callback,
1907 gpointer user_data)
1908 {
1909 GTask *task;
1910
1911 g_return_if_fail (E_IS_CLIENT (client));
1912
1913 task = g_task_new (client, cancellable, callback, user_data);
1914 g_task_set_source_tag (task, e_client_wait_for_connected);
1915 g_task_set_task_data (task, GUINT_TO_POINTER (timeout_seconds), NULL);
1916
1917 g_task_run_in_thread (task, client_wait_for_connected_thread);
1918
1919 g_object_unref (task);
1920 }
1921
1922 /**
1923 * e_client_wait_for_connected_finish:
1924 * @client: an #EClient
1925 * @result: a #GAsyncResult
1926 * @error: a #GError to set an error, or %NULL
1927 *
1928 * Finishes previous call of e_client_wait_for_connected().
1929 *
1930 * Returns: %TRUE if successful, %FALSE otherwise.
1931 *
1932 * Since: 3.16
1933 **/
1934 gboolean
e_client_wait_for_connected_finish(EClient * client,GAsyncResult * result,GError ** error)1935 e_client_wait_for_connected_finish (EClient *client,
1936 GAsyncResult *result,
1937 GError **error)
1938 {
1939 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
1940 g_return_val_if_fail (g_task_is_valid (result, client), FALSE);
1941
1942 g_return_val_if_fail (
1943 g_async_result_is_tagged (
1944 result, e_client_wait_for_connected), FALSE);
1945
1946 return g_task_propagate_boolean (G_TASK (result), error);
1947 }
1948
1949 static void
client_wait_for_connected_cancelled_cb(GCancellable * cancellable,EFlag * flag)1950 client_wait_for_connected_cancelled_cb (GCancellable *cancellable,
1951 EFlag *flag)
1952 {
1953 g_return_if_fail (flag != NULL);
1954
1955 e_flag_set (flag);
1956 }
1957
1958 static void
client_wait_for_connected_notify_cb(ESource * source,GParamSpec * param,EFlag * flag)1959 client_wait_for_connected_notify_cb (ESource *source,
1960 GParamSpec *param,
1961 EFlag *flag)
1962 {
1963 g_return_if_fail (flag != NULL);
1964
1965 if (e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED)
1966 e_flag_set (flag);
1967 }
1968
1969 /**
1970 * e_client_wait_for_connected_sync:
1971 * @client: an #EClient
1972 * @timeout_seconds: a timeout for the wait, in seconds
1973 * @cancellable: a #GCancellable; or %NULL
1974 * @error: a #GError to set an error, or %NULL
1975 *
1976 * Synchronously waits until the @client is connected (according
1977 * to @ESource::connection-status property), but not longer than @timeout_seconds.
1978 *
1979 * Note: This also calls e_client_retrieve_properties_sync() on success, to have
1980 * up-to-date property values on the client side, without a delay due
1981 * to property change notifcations delivery through D-Bus.
1982 *
1983 * Returns: %TRUE if successful, %FALSE otherwise.
1984 *
1985 * Since: 3.16
1986 **/
1987 gboolean
e_client_wait_for_connected_sync(EClient * client,guint32 timeout_seconds,GCancellable * cancellable,GError ** error)1988 e_client_wait_for_connected_sync (EClient *client,
1989 guint32 timeout_seconds,
1990 GCancellable *cancellable,
1991 GError **error)
1992 {
1993 ESource *source;
1994 EFlag *flag;
1995 gulong cancellable_handler_id = 0, notify_handler_id;
1996 gint64 end_time;
1997 gboolean success;
1998
1999 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2000
2001 end_time = g_get_monotonic_time () + timeout_seconds * G_TIME_SPAN_SECOND;
2002 flag = e_flag_new ();
2003
2004 if (cancellable)
2005 cancellable_handler_id = g_cancellable_connect (cancellable,
2006 G_CALLBACK (client_wait_for_connected_cancelled_cb), flag, NULL);
2007
2008 source = e_client_get_source (client);
2009
2010 notify_handler_id = g_signal_connect (source, "notify::connection-status",
2011 G_CALLBACK (client_wait_for_connected_notify_cb), flag);
2012
2013 while (success = e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED,
2014 !success && !g_cancellable_is_cancelled (cancellable)) {
2015 e_flag_clear (flag);
2016
2017 if (timeout_seconds > 0) {
2018 if (g_get_monotonic_time () > end_time)
2019 break;
2020
2021 e_flag_wait_until (flag, end_time);
2022 } else {
2023 e_flag_wait (flag);
2024 }
2025 }
2026
2027 g_signal_handler_disconnect (source, notify_handler_id);
2028
2029 if (cancellable_handler_id > 0 && cancellable)
2030 g_cancellable_disconnect (cancellable, cancellable_handler_id);
2031
2032 e_flag_free (flag);
2033
2034 success = e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED;
2035
2036 if (!success && !g_cancellable_set_error_if_cancelled (cancellable, error))
2037 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, _("Timeout was reached"));
2038 else if (success)
2039 success = e_client_retrieve_properties_sync (client, cancellable, error);
2040
2041 return success;
2042 }
2043
2044 /**
2045 * e_client_retrieve_properties_sync:
2046 * @client: an #EClient
2047 * @cancellable: optional #GCancellable object, or %NULL
2048 * @error: return location for a #GError, or %NULL
2049 *
2050 * Retrieves @client properties to match server-side values, without waiting
2051 * for the D-Bus property change notifications delivery.
2052 *
2053 * If an error occurs, the function sets @error and returns %FALSE.
2054 *
2055 * Returns: %TRUE on success, %FALSE on error
2056 *
2057 * Since: 3.16
2058 **/
2059 gboolean
e_client_retrieve_properties_sync(EClient * client,GCancellable * cancellable,GError ** error)2060 e_client_retrieve_properties_sync (EClient *client,
2061 GCancellable *cancellable,
2062 GError **error)
2063 {
2064 EClientClass *klass;
2065
2066 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2067
2068 klass = E_CLIENT_GET_CLASS (client);
2069 g_return_val_if_fail (klass != NULL, FALSE);
2070 g_return_val_if_fail (klass->retrieve_properties_sync != NULL, FALSE);
2071
2072 return klass->retrieve_properties_sync (client, cancellable, error);
2073 }
2074
2075 static void
client_retrieve_properties_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)2076 client_retrieve_properties_thread (GTask *task,
2077 gpointer source_object,
2078 gpointer task_data,
2079 GCancellable *cancellable)
2080 {
2081 gboolean success;
2082 GError *local_error = NULL;
2083
2084 success = e_client_retrieve_properties_sync (E_CLIENT (source_object), cancellable, &local_error);
2085
2086 if (local_error != NULL) {
2087 g_task_return_error (task, local_error);
2088 } else {
2089 g_task_return_boolean (task, success);
2090 }
2091 }
2092
2093 /**
2094 * e_client_retrieve_properties:
2095 * @client: an #EClient
2096 * @cancellable: optional #GCancellable object, or %NULL
2097 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2098 * @user_data: data to pass to the callback function
2099 *
2100 * Asynchronously retrieves @client properties to match server-side values,
2101 * without waiting for the D-Bus property change notifications delivery.
2102 *
2103 * When the operation is finished, @callback will be called. You can then
2104 * call e_client_retrieve_properties_finish() to get the result of the operation.
2105 *
2106 * Since: 3.16
2107 **/
2108 void
e_client_retrieve_properties(EClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2109 e_client_retrieve_properties (EClient *client,
2110 GCancellable *cancellable,
2111 GAsyncReadyCallback callback,
2112 gpointer user_data)
2113 {
2114 GTask *task;
2115
2116 g_return_if_fail (E_IS_CLIENT (client));
2117
2118 task = g_task_new (client, cancellable, callback, user_data);
2119 g_task_set_source_tag (task, e_client_retrieve_properties);
2120
2121 g_task_run_in_thread (task, client_retrieve_properties_thread);
2122
2123 g_object_unref (task);
2124 }
2125
2126 /**
2127 * e_client_retrieve_properties_finish:
2128 * @client: an #EClient
2129 * @result: a #GAsyncResult
2130 * @error: return location for a #GError, or %NULL
2131 *
2132 * Finishes the operation started with e_client_retrieve_properties().
2133 *
2134 * If an error occurs, the function sets @error and returns %FALSE.
2135 *
2136 * Returns: %TRUE on success, %FALSE on error
2137 *
2138 * Since: 3.16
2139 **/
2140 gboolean
e_client_retrieve_properties_finish(EClient * client,GAsyncResult * result,GError ** error)2141 e_client_retrieve_properties_finish (EClient *client,
2142 GAsyncResult *result,
2143 GError **error)
2144 {
2145 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
2146 g_return_val_if_fail (g_task_is_valid (result, client), FALSE);
2147
2148 g_return_val_if_fail (
2149 g_async_result_is_tagged (
2150 result, e_client_retrieve_properties), FALSE);
2151
2152 return g_task_propagate_boolean (G_TASK (result), error);
2153 }
2154
2155 /**
2156 * e_client_util_slist_to_strv:
2157 * @strings: (element-type utf8): a #GSList of strings (const gchar *)
2158 *
2159 * Convert a list of strings into a %NULL-terminated array of strings.
2160 *
2161 * Returns: (transfer full): Newly allocated %NULL-terminated array of strings.
2162 * The returned pointer should be freed with g_strfreev().
2163 *
2164 * Note: Paired function for this is e_client_util_strv_to_slist().
2165 *
2166 * Since: 3.2
2167 *
2168 * Deprecated: 3.8: Use e_util_slist_to_strv() instead.
2169 **/
2170 gchar **
e_client_util_slist_to_strv(const GSList * strings)2171 e_client_util_slist_to_strv (const GSList *strings)
2172 {
2173 return e_util_slist_to_strv (strings);
2174 }
2175
2176 /**
2177 * e_client_util_strv_to_slist:
2178 * @strv: a %NULL-terminated array of strings (const gchar *)
2179 *
2180 * Convert a %NULL-terminated array of strings to a list of strings.
2181 *
2182 * Returns: (transfer full) (element-type utf8): Newly allocated #GSList of
2183 * newly allocated strings. The returned pointer should be freed with
2184 * e_client_util_free_string_slist().
2185 *
2186 * Note: Paired function for this is e_client_util_slist_to_strv().
2187 *
2188 * Since: 3.2
2189 *
2190 * Deprecated: 3.8: Use e_util_strv_to_slist() instead.
2191 **/
2192 GSList *
e_client_util_strv_to_slist(const gchar * const * strv)2193 e_client_util_strv_to_slist (const gchar * const *strv)
2194 {
2195 return e_util_strv_to_slist (strv);
2196 }
2197
2198 /**
2199 * e_client_util_copy_string_slist:
2200 * @copy_to: (element-type utf8) (nullable) (transfer full): Where to copy; may be %NULL
2201 * @strings: (element-type utf8): #GSList of strings to be copied
2202 *
2203 * Copies the #GSList of strings to the end of @copy_to.
2204 *
2205 * Returns: (transfer full) (element-type utf8): New head of @copy_to.
2206 * The returned pointer can be freed with e_client_util_free_string_slist().
2207 *
2208 * Since: 3.2
2209 *
2210 * Deprecated: 3.8: Use e_util_copy_string_slist() instead.
2211 **/
2212 GSList *
e_client_util_copy_string_slist(GSList * copy_to,const GSList * strings)2213 e_client_util_copy_string_slist (GSList *copy_to,
2214 const GSList *strings)
2215 {
2216 return e_util_copy_string_slist (copy_to, strings);
2217 }
2218
2219 /**
2220 * e_client_util_copy_object_slist:
2221 * @copy_to: (element-type GObject) (nullable) (transfer full): Where to copy; may be %NULL
2222 * @objects: (element-type GObject): #GSList of #GObject<!-- -->s to be copied
2223 *
2224 * Copies a #GSList of #GObject<!-- -->s to the end of @copy_to.
2225 *
2226 * Returns: (transfer full) (element-type GObject): New head of @copy_to.
2227 * The returned pointer can be freed with e_client_util_free_object_slist().
2228 *
2229 * Since: 3.2
2230 *
2231 * Deprecated: 3.8: Use e_util_copy_object_slist() instead.
2232 **/
2233 GSList *
e_client_util_copy_object_slist(GSList * copy_to,const GSList * objects)2234 e_client_util_copy_object_slist (GSList *copy_to,
2235 const GSList *objects)
2236 {
2237 return e_util_copy_object_slist (copy_to, objects);
2238 }
2239
2240 /**
2241 * e_client_util_free_string_slist:
2242 * @strings: (element-type utf8): a #GSList of strings (gchar *)
2243 *
2244 * Frees memory previously allocated by e_client_util_strv_to_slist().
2245 *
2246 * Since: 3.2
2247 *
2248 * Deprecated: 3.8: Use g_slist_free_full() instead.
2249 **/
2250 void
e_client_util_free_string_slist(GSList * strings)2251 e_client_util_free_string_slist (GSList *strings)
2252 {
2253 e_util_free_string_slist (strings);
2254 }
2255
2256 /**
2257 * e_client_util_free_object_slist:
2258 * @objects: (element-type GObject): a #GSList of #GObject<!-- -->s
2259 *
2260 * Calls g_object_unref() on each member of @objects and then frees @objects
2261 * itself.
2262 *
2263 * Since: 3.2
2264 *
2265 * Deprecated: 3.8: Use g_slist_free_full() instead.
2266 **/
2267 void
e_client_util_free_object_slist(GSList * objects)2268 e_client_util_free_object_slist (GSList *objects)
2269 {
2270 e_util_free_object_slist (objects);
2271 }
2272
2273 /**
2274 * e_client_util_parse_comma_strings:
2275 * @strings: string of comma-separated values
2276 *
2277 * Parses comma-separated list of values into #GSList.
2278 *
2279 * Returns: (transfer full) (element-type utf8): Newly allocated #GSList of
2280 * newly allocated strings corresponding to values parsed from @strings.
2281 * Free the returned pointer with e_client_util_free_string_slist().
2282 *
2283 * Since: 3.2
2284 **/
2285 GSList *
e_client_util_parse_comma_strings(const gchar * strings)2286 e_client_util_parse_comma_strings (const gchar *strings)
2287 {
2288 GSList *strs_slist = NULL;
2289 gchar **strs_strv = NULL;
2290 gint ii;
2291
2292 if (!strings || !*strings)
2293 return NULL;
2294
2295 strs_strv = g_strsplit (strings, ",", -1);
2296 g_return_val_if_fail (strs_strv != NULL, NULL);
2297
2298 for (ii = 0; strs_strv && strs_strv[ii]; ii++) {
2299 gchar *str = g_strstrip (strs_strv[ii]);
2300
2301 if (str && *str)
2302 strs_slist = g_slist_prepend (strs_slist, g_strdup (str));
2303 }
2304
2305 g_strfreev (strs_strv);
2306
2307 return g_slist_reverse (strs_slist);
2308 }
2309
2310 /**
2311 * e_client_unwrap_dbus_error:
2312 * @client: an #EClient
2313 * @dbus_error: a #GError returned bu D-Bus
2314 * @out_error: a #GError variable where to store the result
2315 *
2316 * Unwraps D-Bus error to local error. @dbus_error is automatically freed.
2317 * @dbus_erorr and @out_error can point to the same variable.
2318 *
2319 * Since: 3.2
2320 *
2321 * Deprecated: 3.8: Use g_dbus_error_strip_remote_error() instead.
2322 **/
2323 void
e_client_unwrap_dbus_error(EClient * client,GError * dbus_error,GError ** out_error)2324 e_client_unwrap_dbus_error (EClient *client,
2325 GError *dbus_error,
2326 GError **out_error)
2327 {
2328 EClientClass *class;
2329
2330 g_return_if_fail (E_IS_CLIENT (client));
2331
2332 class = E_CLIENT_GET_CLASS (client);
2333 g_return_if_fail (class != NULL);
2334 g_return_if_fail (class->unwrap_dbus_error != NULL);
2335
2336 if (!dbus_error || !out_error) {
2337 if (dbus_error)
2338 g_error_free (dbus_error);
2339 } else {
2340 class->unwrap_dbus_error (client, dbus_error, out_error);
2341 }
2342 }
2343
2344 /**
2345 * e_client_util_unwrap_dbus_error:
2346 * @dbus_error: DBus #GError to unwrap
2347 * @client_error: (out): Resulting #GError; can be %NULL
2348 * @known_errors: List of known errors against which try to match
2349 * @known_errors_count: How many items are stored in @known_errors
2350 * @known_errors_domain: Error domain for @known_errors
2351 * @fail_when_none_matched: Whether to fail when none of @known_errors matches
2352 *
2353 * The function takes a @dbus_error and tries to find a match in @known_errors
2354 * for it, if it is a G_IO_ERROR, G_IO_ERROR_DBUS_ERROR. If it is anything else
2355 * then the @dbus_error is moved to @client_error.
2356 *
2357 * The @fail_when_none_matched influences behaviour. If it's %TRUE, and none of
2358 * @known_errors matches, or this is not a G_IO_ERROR_DBUS_ERROR, then %FALSE
2359 * is returned and the @client_error is left without change. Otherwise, the
2360 * @fail_when_none_matched is %FALSE, the error is always processed and will
2361 * result in E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR if none of @known_error
2362 * matches.
2363 *
2364 * Returns: Whether was @dbus_error processed into @client_error.
2365 *
2366 * Note: The @dbus_error is automatically freed if returned %TRUE.
2367 *
2368 * Since: 3.2
2369 *
2370 * Deprecated: 3.8: This function is no longer used.
2371 **/
2372 gboolean
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)2373 e_client_util_unwrap_dbus_error (GError *dbus_error,
2374 GError **client_error,
2375 const EClientErrorsList *known_errors,
2376 guint known_errors_count,
2377 GQuark known_errors_domain,
2378 gboolean fail_when_none_matched)
2379 {
2380 if (!client_error) {
2381 if (dbus_error)
2382 g_error_free (dbus_error);
2383 return TRUE;
2384 }
2385
2386 if (!dbus_error) {
2387 *client_error = NULL;
2388 return TRUE;
2389 }
2390
2391 if (dbus_error->domain == known_errors_domain) {
2392 *client_error = dbus_error;
2393 return TRUE;
2394 }
2395
2396 if (known_errors) {
2397 if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
2398 gchar *name;
2399 gint ii;
2400
2401 name = g_dbus_error_get_remote_error (dbus_error);
2402
2403 for (ii = 0; ii < known_errors_count; ii++) {
2404 if (g_ascii_strcasecmp (known_errors[ii].name, name) == 0) {
2405 g_free (name);
2406
2407 g_dbus_error_strip_remote_error (dbus_error);
2408 *client_error = g_error_new_literal (
2409 known_errors_domain,
2410 known_errors[ii].err_code,
2411 dbus_error->message);
2412 g_error_free (dbus_error);
2413 return TRUE;
2414 }
2415 }
2416
2417 g_free (name);
2418 }
2419 }
2420
2421 if (fail_when_none_matched)
2422 return FALSE;
2423
2424 if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
2425 g_dbus_error_strip_remote_error (dbus_error);
2426 *client_error = g_error_new_literal (
2427 E_CLIENT_ERROR,
2428 E_CLIENT_ERROR_OTHER_ERROR,
2429 dbus_error->message);
2430 g_error_free (dbus_error);
2431 } else {
2432 g_dbus_error_strip_remote_error (dbus_error);
2433 *client_error = dbus_error;
2434 }
2435
2436 return TRUE;
2437 }
2438
2439 /**
2440 * e_client_dup_bus_name:
2441 * @client: an #EClient
2442 *
2443 * Returns a D-Bus bus name that will be used to connect the
2444 * client to the backend subprocess.
2445 *
2446 * Returns: a newly-allocated string representing a D-Bus bus
2447 * name that will be used to connect the client to
2448 * the backend subprocess. The string should be
2449 * freed by the caller using g_free().
2450 *
2451 * Since: 3.16
2452 **/
2453 gchar *
e_client_dup_bus_name(EClient * client)2454 e_client_dup_bus_name (EClient *client)
2455 {
2456 g_return_val_if_fail (E_IS_CLIENT (client), NULL);
2457
2458 return g_strdup (client->priv->bus_name);
2459 }
2460
2461 /**
2462 * e_client_set_bus_name:
2463 * @client: an #EClient
2464 * @bus_name: a string representing a D-Bus bus name
2465 *
2466 * Sets a D-Bus bus name that will be used to connect the client
2467 * to the backend subprocess.
2468 *
2469 * Since: 3.16
2470 **/
2471 void
e_client_set_bus_name(EClient * client,const gchar * bus_name)2472 e_client_set_bus_name (EClient *client,
2473 const gchar *bus_name)
2474 {
2475 g_return_if_fail (E_IS_CLIENT (client));
2476 g_return_if_fail (client->priv->bus_name == NULL);
2477 g_return_if_fail (bus_name != NULL && *bus_name != '\0');
2478
2479 client->priv->bus_name = g_strdup (bus_name);
2480 }
2481