1 /*
2 * e-source.c
3 *
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 /**
19 * SECTION: e-source
20 * @include: libedataserver/libedataserver.h
21 * @short_description: Hierarchical data sources
22 *
23 * An #ESource (or "data source") is a description of a file or network
24 * location where data can be obtained (such as a mail account), or a
25 * description of a resource at that location (such as a mail folder).
26 *
27 * In more concrete terms, it's an interface for a key file. All such
28 * key files have a main group named [Data Source]. The keys in a
29 * [Data Source] group map to #GObject properties in an #ESource.
30 *
31 * Additional groups in the key file are referred to as "extensions".
32 * #ESourceExtension serves as the base class for writing interfaces
33 * for these additional key file groups. The keys in one of these
34 * key file groups map to #GObject properties in some custom subclass
35 * of #ESourceExtension which was written specifically for that key
36 * file group. For example, a key file might include a group named
37 * [Calendar], whose keys map to #GObject properties in an extension
38 * class named #ESourceCalendar.
39 *
40 * Each #ESource contains an internal dictionary of extension objects,
41 * accessible by their key file group name. e_source_get_extension()
42 * can look up extension objects by name.
43 *
44 * An #ESource is identified by a unique identifier string, or "UID",
45 * which is also the basename of the corresponding key file. Additional
46 * files related to the #ESource, such as cache files, are usually kept
47 * in a directory named after the UID of the #ESource. Similarly, the
48 * password for an account described by an #ESource is kept in GNOME
49 * Keyring under the UID of the #ESource. This makes finding these
50 * additional resources simple.
51 *
52 * Several extensions for common information such as authentication
53 * details are built into libedataserver (#ESourceAuthentication, for
54 * example). Backend modules may also define their own extensions for
55 * information and settings unique to the backend. #ESourceExtension
56 * subclasses written for specific backends are generally not available
57 * to applications and shared libraries. This is by design, to try and
58 * keep backend-specific knowledge from creeping into places it doesn't
59 * belong.
60 *
61 * As of 3.12, an #ESource with an #ESourceProxy extension can serve as a
62 * #GProxyResolver. Calling g_proxy_resolver_is_supported() on an #ESource
63 * will reflect this constraint. Attempting a proxy lookup operation on an
64 * #ESource for which g_proxy_resolver_is_supported() returns %FALSE will
65 * fail with %G_IO_ERROR_NOT_SUPPORTED.
66 **/
67
68 #include "evolution-data-server-config.h"
69
70 #include <string.h>
71 #include <glib/gi18n-lib.h>
72
73 /* Private D-Bus classes. */
74 #include "e-dbus-source.h"
75
76 #include "e-data-server-util.h"
77 #include "e-oauth2-services.h"
78 #include "e-secret-store.h"
79 #include "e-source-enumtypes.h"
80 #include "e-source-extension.h"
81 #include "e-source-registry.h"
82 #include "e-uid.h"
83
84 /* built-in extension types */
85 #include "e-source-address-book.h"
86 #include "e-source-alarms.h"
87 #include "e-source-authentication.h"
88 #include "e-source-autocomplete.h"
89 #include "e-source-autoconfig.h"
90 #include "e-source-calendar.h"
91 #include "e-source-camel.h"
92 #include "e-source-collection.h"
93 #include "e-source-contacts.h"
94 #include "e-source-goa.h"
95 #include "e-source-ldap.h"
96 #include "e-source-local.h"
97 #include "e-source-mail-account.h"
98 #include "e-source-mail-composition.h"
99 #include "e-source-mail-identity.h"
100 #include "e-source-mail-signature.h"
101 #include "e-source-mail-submission.h"
102 #include "e-source-mail-transport.h"
103 #include "e-source-mdn.h"
104 #include "e-source-memo-list.h"
105 #include "e-source-offline.h"
106 #include "e-source-openpgp.h"
107 #include "e-source-proxy.h"
108 #include "e-source-refresh.h"
109 #include "e-source-resource.h"
110 #include "e-source-revision-guards.h"
111 #include "e-source-security.h"
112 #include "e-source-selectable.h"
113 #include "e-source-smime.h"
114 #include "e-source-task-list.h"
115 #include "e-source-uoa.h"
116 #include "e-source-weather.h"
117 #include "e-source-webdav.h"
118
119 #include "e-source.h"
120
121 #define PRIMARY_GROUP_NAME "Data Source"
122
123 typedef struct _AsyncContext AsyncContext;
124 typedef struct _RemoveContext RemoveContext;
125
126 struct _ESourcePrivate {
127 GDBusObject *dbus_object;
128 GMainContext *main_context;
129
130 GSource *changed;
131 GMutex changed_lock;
132 guint ignore_changed_signal;
133
134 GSource *connection_status_change;
135 GMutex connection_status_change_lock;
136 ESourceConnectionStatus connection_status;
137
138 GMutex property_lock;
139
140 gchar *display_name;
141 gchar *collate_key;
142 gchar *parent;
143 gchar *uid;
144
145 /* The lock guards the key file and hash table. */
146
147 GKeyFile *key_file;
148 GRecMutex lock;
149 GHashTable *extensions;
150
151 gboolean enabled;
152 gboolean initialized;
153 };
154
155 struct _AsyncContext {
156 ESource *scratch_source;
157 gchar *access_token;
158 gint expires_in;
159 gchar *password;
160 gboolean permanently;
161 };
162
163 /* Used in e_source_remove_sync() */
164 struct _RemoveContext {
165 GMainContext *main_context;
166 GMainLoop *main_loop;
167 };
168
169 enum {
170 PROP_0,
171 PROP_DBUS_OBJECT,
172 PROP_DISPLAY_NAME,
173 PROP_ENABLED,
174 PROP_MAIN_CONTEXT,
175 PROP_PARENT,
176 PROP_REMOTE_CREATABLE,
177 PROP_REMOTE_DELETABLE,
178 PROP_REMOVABLE,
179 PROP_UID,
180 PROP_WRITABLE,
181 PROP_CONNECTION_STATUS
182 };
183
184 enum {
185 CHANGED,
186 CREDENTIALS_REQUIRED,
187 AUTHENTICATE,
188 LAST_SIGNAL
189 };
190
191 static guint signals[LAST_SIGNAL];
192
193 /* Forward Declarations */
194 static void e_source_initable_init (GInitableIface *iface);
195 static void e_source_proxy_resolver_init
196 (GProxyResolverInterface *iface);
197
198 /* Private function shared only with ESourceRegistry. */
199 void __e_source_private_replace_dbus_object
200 (ESource *source,
201 GDBusObject *dbus_object);
202
G_DEFINE_TYPE_WITH_CODE(ESource,e_source,G_TYPE_OBJECT,G_ADD_PRIVATE (ESource)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_source_initable_init)G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,e_source_proxy_resolver_init))203 G_DEFINE_TYPE_WITH_CODE (
204 ESource,
205 e_source,
206 G_TYPE_OBJECT,
207 G_ADD_PRIVATE (ESource)
208 G_IMPLEMENT_INTERFACE (
209 G_TYPE_INITABLE,
210 e_source_initable_init)
211 G_IMPLEMENT_INTERFACE (
212 G_TYPE_PROXY_RESOLVER,
213 e_source_proxy_resolver_init))
214
215 static void
216 async_context_free (AsyncContext *async_context)
217 {
218 if (async_context->scratch_source != NULL)
219 g_object_unref (async_context->scratch_source);
220
221 g_free (async_context->access_token);
222 g_free (async_context->password);
223
224 g_slice_free (AsyncContext, async_context);
225 }
226
227 static RemoveContext *
remove_context_new(void)228 remove_context_new (void)
229 {
230 RemoveContext *remove_context;
231
232 remove_context = g_slice_new0 (RemoveContext);
233
234 remove_context->main_context = g_main_context_new ();
235
236 remove_context->main_loop = g_main_loop_new (
237 remove_context->main_context, FALSE);
238
239 return remove_context;
240 }
241
242 static void
remove_context_free(RemoveContext * remove_context)243 remove_context_free (RemoveContext *remove_context)
244 {
245 g_main_loop_unref (remove_context->main_loop);
246 g_main_context_unref (remove_context->main_context);
247
248 g_slice_free (RemoveContext, remove_context);
249 }
250
251 static void
source_find_extension_classes_rec(GType parent_type,GHashTable * hash_table)252 source_find_extension_classes_rec (GType parent_type,
253 GHashTable *hash_table)
254 {
255 GType *children;
256 guint n_children, ii;
257
258 children = g_type_children (parent_type, &n_children);
259
260 for (ii = 0; ii < n_children; ii++) {
261 GType type = children[ii];
262 ESourceExtensionClass *class;
263 gpointer key;
264
265 /* Recurse over the child's children. */
266 source_find_extension_classes_rec (type, hash_table);
267
268 /* Skip abstract types. */
269 if (G_TYPE_IS_ABSTRACT (type))
270 continue;
271
272 class = g_type_class_ref (type);
273 key = (gpointer) class->name;
274
275 if (key != NULL)
276 g_hash_table_insert (hash_table, key, class);
277 else
278 g_type_class_unref (class);
279 }
280
281 g_free (children);
282 }
283
284 static GHashTable *
source_find_extension_classes(void)285 source_find_extension_classes (void)
286 {
287 GHashTable *hash_table;
288
289 hash_table = g_hash_table_new_full (
290 (GHashFunc) g_str_hash,
291 (GEqualFunc) g_str_equal,
292 (GDestroyNotify) NULL,
293 (GDestroyNotify) g_type_class_unref);
294
295 source_find_extension_classes_rec (
296 E_TYPE_SOURCE_EXTENSION, hash_table);
297
298 return hash_table;
299 }
300
301 static void
source_localized_hack(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * new_value)302 source_localized_hack (GKeyFile *key_file,
303 const gchar *group_name,
304 const gchar *key,
305 const gchar *new_value)
306 {
307 const gchar * const *language_names;
308 gint ii;
309
310 /* XXX If we're changing a string key that has translations,
311 * set "key[$CURRENT_LOCALE]" (if available) to the new
312 * value so g_key_file_get_locale_string() will pick it
313 * up. This is not a perfect solution however. When a
314 * different locale is used the value may revert to its
315 * original localized string. Good enough for now. */
316
317 language_names = g_get_language_names ();
318
319 for (ii = 0; language_names[ii] != NULL; ii++) {
320 gboolean has_localized_key;
321 gchar *localized_key;
322
323 localized_key = g_strdup_printf (
324 "%s[%s]", key, language_names[ii]);
325 has_localized_key = g_key_file_has_key (
326 key_file, group_name, localized_key, NULL);
327
328 if (has_localized_key)
329 g_key_file_set_string (
330 key_file, group_name,
331 localized_key, new_value);
332
333 g_free (localized_key);
334
335 if (has_localized_key)
336 return;
337 }
338
339 g_key_file_set_string (key_file, group_name, key, new_value);
340 }
341
342 static gboolean
source_check_values_differ(GType g_type,const GValue * value,const GValue * value2)343 source_check_values_differ (GType g_type,
344 const GValue *value,
345 const GValue *value2)
346 {
347 gboolean differ = TRUE;
348 GValue *value1;
349
350 g_return_val_if_fail (value != NULL, TRUE);
351 g_return_val_if_fail (value2 != NULL, TRUE);
352
353 value1 = g_slice_new0 (GValue);
354 g_value_init (value1, g_type);
355 g_value_copy (value2, value1);
356
357 if (g_value_transform (value, value1)) {
358 #define check_type(name,get) G_STMT_START { \
359 if (G_VALUE_HOLDS_ ## name (value1)) { \
360 differ = g_value_get_ ## get (value1) != g_value_get_ ## get (value2); \
361 break; \
362 } } G_STMT_END
363
364 do {
365 check_type (BOOLEAN, boolean);
366 check_type (CHAR, schar);
367 check_type (DOUBLE, double);
368 check_type (ENUM, enum);
369 check_type (FLAGS, flags);
370 check_type (FLOAT, float);
371 check_type (GTYPE, gtype);
372 check_type (INT, int);
373 check_type (INT64, int64);
374 check_type (LONG, long);
375 check_type (POINTER, pointer);
376 check_type (UCHAR, uchar);
377 check_type (UINT, uint);
378 check_type (UINT64, uint64);
379 check_type (ULONG, ulong);
380
381 if (G_VALUE_HOLDS_STRING (value1)) {
382 differ = g_strcmp0 (g_value_get_string (value1), g_value_get_string (value2)) != 0;
383 break;
384 }
385
386 if (G_VALUE_HOLDS_VARIANT (value1)) {
387 GVariant *variant1, *variant2;
388
389 variant1 = g_value_get_variant (value1);
390 variant2 = g_value_get_variant (value2);
391 differ = g_variant_compare (variant1, variant2) != 0;
392 break;
393 }
394 } while (FALSE);
395
396 #undef check_type
397 }
398
399 g_value_unset (value1);
400 g_slice_free (GValue, value1);
401
402 return differ;
403 }
404
405 static void
source_set_key_file_from_property(GObject * object,GParamSpec * pspec,GKeyFile * key_file,const gchar * group_name)406 source_set_key_file_from_property (GObject *object,
407 GParamSpec *pspec,
408 GKeyFile *key_file,
409 const gchar *group_name)
410 {
411 GValue *pvalue;
412 GValue *svalue;
413 gchar *key;
414
415 pvalue = g_slice_new0 (GValue);
416 g_value_init (pvalue, pspec->value_type);
417 g_object_get_property (object, pspec->name, pvalue);
418
419 svalue = g_slice_new0 (GValue);
420 g_value_init (svalue, G_TYPE_STRING);
421
422 key = e_source_parameter_to_key (pspec->name);
423
424 /* For the most part we can just transform any supported
425 * property type to a string, with a couple exceptions. */
426
427 /* Transforming a boolean GValue to a string results in
428 * "TRUE" or "FALSE" (all uppercase), but GKeyFile only
429 * recognizes "true" or "false" (all lowercase). So we
430 * have to use g_key_file_set_boolean(). */
431 if (G_VALUE_HOLDS_BOOLEAN (pvalue)) {
432 gboolean v_boolean = g_value_get_boolean (pvalue);
433 g_key_file_set_boolean (key_file, group_name, key, v_boolean);
434
435 /* Store UIN64 in hexa */
436 } else if (G_VALUE_HOLDS_UINT64 (pvalue)) {
437 gchar *v_str;
438
439 v_str = g_strdup_printf (
440 "%016" G_GINT64_MODIFIER "X",
441 g_value_get_uint64 (pvalue));
442 g_key_file_set_string (key_file, group_name, key, v_str);
443 g_free (v_str);
444
445 /* String GValues may contain characters that need escaping. */
446 } else if (G_VALUE_HOLDS_STRING (pvalue)) {
447 const gchar *v_string = g_value_get_string (pvalue);
448
449 if (v_string == NULL)
450 v_string = "";
451
452 /* Special case for localized "DisplayName" keys. */
453 source_localized_hack (key_file, group_name, key, v_string);
454
455 /* Transforming an enum GValue to a string results in
456 * the GEnumValue name. We want the shorter nickname. */
457 } else if (G_VALUE_HOLDS_ENUM (pvalue)) {
458 GParamSpecEnum *enum_pspec;
459 GEnumClass *enum_class;
460 GEnumValue *enum_value;
461 gint value;
462
463 enum_pspec = G_PARAM_SPEC_ENUM (pspec);
464 enum_class = enum_pspec->enum_class;
465
466 value = g_value_get_enum (pvalue);
467 enum_value = g_enum_get_value (enum_class, value);
468
469 if (enum_value == NULL) {
470 value = enum_pspec->default_value;
471 enum_value = g_enum_get_value (enum_class, value);
472 }
473
474 if (enum_value != NULL)
475 g_key_file_set_string (
476 key_file, group_name, key,
477 enum_value->value_nick);
478
479 } else if (G_VALUE_HOLDS (pvalue, G_TYPE_STRV)) {
480 const gchar **strv = g_value_get_boxed (pvalue);
481 guint length = 0;
482
483 if (strv != NULL)
484 length = g_strv_length ((gchar **) strv);
485 g_key_file_set_string_list (
486 key_file, group_name, key, strv, length);
487
488 /* For GValues holding a GFile object we save the URI. */
489 } else if (G_VALUE_HOLDS (pvalue, G_TYPE_FILE)) {
490 GFile *file = g_value_get_object (pvalue);
491 gchar *uri = NULL;
492
493 if (file != NULL)
494 uri = g_file_get_uri (file);
495 g_key_file_set_string (
496 key_file, group_name, key,
497 (uri != NULL) ? uri : "");
498 g_free (uri);
499
500 } else if (g_value_transform (pvalue, svalue)) {
501 const gchar *value = g_value_get_string (svalue);
502 g_key_file_set_value (key_file, group_name, key, value);
503 }
504
505 g_free (key);
506 g_value_unset (pvalue);
507 g_value_unset (svalue);
508 g_slice_free (GValue, pvalue);
509 g_slice_free (GValue, svalue);
510 }
511
512 static void
source_set_property_from_key_file(GObject * object,GParamSpec * pspec,GKeyFile * key_file,const gchar * group_name)513 source_set_property_from_key_file (GObject *object,
514 GParamSpec *pspec,
515 GKeyFile *key_file,
516 const gchar *group_name)
517 {
518 gchar *key;
519 GValue *value;
520 GError *local_error = NULL;
521
522 value = g_slice_new0 (GValue);
523 key = e_source_parameter_to_key (pspec->name);
524
525 if (G_IS_PARAM_SPEC_CHAR (pspec) ||
526 G_IS_PARAM_SPEC_UCHAR (pspec) ||
527 G_IS_PARAM_SPEC_INT (pspec) ||
528 G_IS_PARAM_SPEC_UINT (pspec) ||
529 G_IS_PARAM_SPEC_LONG (pspec) ||
530 G_IS_PARAM_SPEC_ULONG (pspec)) {
531 gint v_int;
532
533 v_int = g_key_file_get_integer (
534 key_file, group_name, key, &local_error);
535 if (local_error == NULL) {
536 g_value_init (value, G_TYPE_INT);
537 g_value_set_int (value, v_int);
538 }
539
540 } else if (G_IS_PARAM_SPEC_INT64 (pspec)) {
541 gint64 v_int64;
542
543 v_int64 = g_key_file_get_int64 (
544 key_file, group_name, key, &local_error);
545 if (local_error == NULL) {
546 g_value_init (value, G_TYPE_INT64);
547 g_value_set_int64 (value, v_int64);
548 }
549
550 } else if (G_IS_PARAM_SPEC_UINT64 (pspec)) {
551 guint64 v_uint64;
552 gchar *v_str;
553
554 v_str = g_key_file_get_string (
555 key_file, group_name, key, &local_error);
556 if (local_error == NULL) {
557 v_uint64 = g_ascii_strtoull (v_str, NULL, 16);
558
559 g_value_init (value, G_TYPE_UINT64);
560 g_value_set_uint64 (value, v_uint64);
561 }
562
563 g_free (v_str);
564
565 } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
566 gboolean v_boolean;
567
568 v_boolean = g_key_file_get_boolean (
569 key_file, group_name, key, &local_error);
570 if (local_error == NULL) {
571 g_value_init (value, G_TYPE_BOOLEAN);
572 g_value_set_boolean (value, v_boolean);
573 }
574
575 } else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
576 gchar *nick;
577
578 nick = g_key_file_get_string (
579 key_file, group_name, key, &local_error);
580 if (local_error == NULL) {
581 GParamSpecEnum *enum_pspec;
582 GEnumValue *enum_value;
583
584 enum_pspec = G_PARAM_SPEC_ENUM (pspec);
585 enum_value = g_enum_get_value_by_nick (
586 enum_pspec->enum_class, nick);
587 if (enum_value != NULL) {
588 g_value_init (value, pspec->value_type);
589 g_value_set_enum (value, enum_value->value);
590 }
591 g_free (nick);
592 }
593
594 } else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
595 G_IS_PARAM_SPEC_DOUBLE (pspec)) {
596 gdouble v_double;
597
598 v_double = g_key_file_get_double (
599 key_file, group_name, key, &local_error);
600 if (local_error == NULL) {
601 g_value_init (value, G_TYPE_DOUBLE);
602 g_value_set_double (value, v_double);
603 }
604
605 } else if (G_IS_PARAM_SPEC_STRING (pspec)) {
606 gchar *v_string;
607
608 /* Get the localized string if present. */
609 v_string = g_key_file_get_locale_string (
610 key_file, group_name, key, NULL, &local_error);
611 if (local_error == NULL) {
612 g_value_init (value, G_TYPE_STRING);
613 g_value_take_string (value, v_string);
614 }
615
616 } else if (g_type_is_a (pspec->value_type, G_TYPE_STRV)) {
617 gchar **strv;
618
619 strv = g_key_file_get_string_list (
620 key_file, group_name, key, NULL, &local_error);
621 if (local_error == NULL) {
622 g_value_init (value, G_TYPE_STRV);
623 g_value_take_boxed (value, strv);
624 }
625
626 } else if (g_type_is_a (pspec->value_type, G_TYPE_FILE)) {
627 gchar *uri;
628
629 /* Create the GFile from the URI string. */
630 uri = g_key_file_get_locale_string (
631 key_file, group_name, key, NULL, &local_error);
632 if (local_error == NULL) {
633 GFile *file = NULL;
634 if (uri != NULL && *uri != '\0')
635 file = g_file_new_for_uri (uri);
636 g_value_init (value, pspec->value_type);
637 g_value_take_object (value, file);
638 g_free (uri);
639 }
640
641 } else {
642 g_warning (
643 "No GKeyFile-to-GValue converter defined "
644 "for type '%s'", G_PARAM_SPEC_TYPE_NAME (pspec));
645 }
646
647 /* If a value could not be retrieved from the key
648 * file, restore the property to its default value. */
649 if (local_error != NULL) {
650 g_value_init (value, pspec->value_type);
651 g_param_value_set_default (pspec, value);
652 g_error_free (local_error);
653 }
654
655 if (G_IS_VALUE (value)) {
656 GValue *cvalue;
657
658 cvalue = g_slice_new0 (GValue);
659 g_value_init (cvalue, pspec->value_type);
660 g_object_get_property (object, pspec->name, cvalue);
661
662 /* This is because the g_object_set_property() invokes "notify" signal
663 * on the set property, even if the value did not change, which creates
664 * false notifications, which can cause UI or background activities
665 * without any real reason (especially with the ''enabled' property load). */
666 if (!G_IS_VALUE (cvalue) || source_check_values_differ (pspec->value_type, value, cvalue))
667 g_object_set_property (object, pspec->name, value);
668
669 if (G_IS_VALUE (cvalue))
670 g_value_unset (cvalue);
671 g_slice_free (GValue, cvalue);
672
673 g_value_unset (value);
674 }
675
676 g_slice_free (GValue, value);
677 g_free (key);
678 }
679
680 static void
source_load_from_key_file(GObject * object,GKeyFile * key_file,const gchar * group_name)681 source_load_from_key_file (GObject *object,
682 GKeyFile *key_file,
683 const gchar *group_name)
684 {
685 GObjectClass *class;
686 GParamSpec **properties;
687 guint n_properties, ii;
688
689 class = G_OBJECT_GET_CLASS (object);
690 properties = g_object_class_list_properties (class, &n_properties);
691
692 g_object_freeze_notify (object);
693
694 for (ii = 0; ii < n_properties; ii++) {
695 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
696 source_set_property_from_key_file (
697 object, properties[ii], key_file, group_name);
698 }
699 }
700
701 g_object_thaw_notify (object);
702
703 g_free (properties);
704 }
705
706 static void
source_save_to_key_file(GObject * object,GKeyFile * key_file,const gchar * group_name)707 source_save_to_key_file (GObject *object,
708 GKeyFile *key_file,
709 const gchar *group_name)
710 {
711 GObjectClass *class;
712 GParamSpec **properties;
713 guint n_properties, ii;
714
715 class = G_OBJECT_GET_CLASS (object);
716 properties = g_object_class_list_properties (class, &n_properties);
717
718 for (ii = 0; ii < n_properties; ii++) {
719 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
720 source_set_key_file_from_property (
721 object, properties[ii], key_file, group_name);
722 }
723 }
724
725 g_free (properties);
726 }
727
728 static gboolean
source_parse_dbus_data(ESource * source,GError ** error)729 source_parse_dbus_data (ESource *source,
730 GError **error)
731 {
732 GHashTableIter iter;
733 EDBusObject *dbus_object;
734 EDBusSource *dbus_source;
735 GKeyFile *key_file;
736 gpointer group_name;
737 gpointer extension;
738 gchar *data;
739 gboolean success;
740
741 if (!source->priv->dbus_object)
742 return FALSE;
743
744 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
745
746 dbus_source = e_dbus_object_get_source (dbus_object);
747 data = e_dbus_source_dup_data (dbus_source);
748 g_object_unref (dbus_source);
749
750 g_return_val_if_fail (data != NULL, FALSE);
751
752 key_file = source->priv->key_file;
753
754 success = g_key_file_load_from_data (
755 key_file, data, strlen (data),
756 G_KEY_FILE_KEEP_COMMENTS |
757 G_KEY_FILE_KEEP_TRANSLATIONS,
758 error);
759
760 g_free (data);
761 data = NULL;
762
763 if (!success)
764 return FALSE;
765
766 /* Make sure the key file has a [Data Source] group. */
767 if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
768 g_set_error (
769 error, G_KEY_FILE_ERROR,
770 G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
771 _("Source file is missing a [%s] group"),
772 PRIMARY_GROUP_NAME);
773 return FALSE;
774 }
775
776 /* Load key file values from the [Data Source] group and from
777 * any other groups for which an extension object has already
778 * been created. Note that not all the extension classes may
779 * be registered at this point, so avoid attempting to create
780 * new extension objects here. Extension objects are created
781 * on-demand in e_source_get_extension(). */
782
783 source_load_from_key_file (
784 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
785
786 g_hash_table_iter_init (&iter, source->priv->extensions);
787 while (g_hash_table_iter_next (&iter, &group_name, &extension))
788 source_load_from_key_file (extension, key_file, group_name);
789
790 return TRUE;
791 }
792
793 static void
source_notify_dbus_data_cb(EDBusSource * dbus_source,GParamSpec * pspec,ESource * source)794 source_notify_dbus_data_cb (EDBusSource *dbus_source,
795 GParamSpec *pspec,
796 ESource *source)
797 {
798 GError *local_error = NULL;
799
800 g_rec_mutex_lock (&source->priv->lock);
801
802 /* Since the source data came from a GKeyFile structure on the
803 * server-side, this should never fail. But we'll print error
804 * messages to the terminal just in case. */
805 source_parse_dbus_data (source, &local_error);
806
807 if (local_error != NULL) {
808 g_warning ("%s", local_error->message);
809 g_error_free (local_error);
810 }
811
812 g_rec_mutex_unlock (&source->priv->lock);
813 }
814
815 static gboolean
source_update_connection_status_internal(ESource * source,EDBusSource * dbus_source)816 source_update_connection_status_internal (ESource *source,
817 EDBusSource *dbus_source)
818 {
819 ESourceConnectionStatus connection_status_value;
820 gchar *connection_status;
821 gboolean changed = FALSE;
822
823 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
824 g_return_val_if_fail (dbus_source != NULL, FALSE);
825
826 connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
827 connection_status = e_dbus_source_dup_connection_status (dbus_source);
828
829 if (connection_status) {
830 GEnumClass *enum_class;
831 GEnumValue *enum_value;
832
833 enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
834 enum_value = g_enum_get_value_by_nick (enum_class, connection_status);
835
836 if (enum_value) {
837 connection_status_value = enum_value->value;
838 } else if (!*connection_status) {
839 connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
840 } else {
841 g_warning ("%s: Unknown connection status: '%s'", G_STRFUNC, connection_status);
842 }
843
844 g_type_class_unref (enum_class);
845 g_free (connection_status);
846 }
847
848 if (source->priv->connection_status != connection_status_value) {
849 source->priv->connection_status = connection_status_value;
850 changed = TRUE;
851 }
852
853 return changed;
854 }
855
856 static void
source_update_connection_status(ESource * source)857 source_update_connection_status (ESource *source)
858 {
859 EDBusObject *dbus_object;
860 EDBusSource *dbus_source;
861 gboolean changed = FALSE;
862
863 g_return_if_fail (E_IS_SOURCE (source));
864
865 g_mutex_lock (&source->priv->connection_status_change_lock);
866 g_clear_pointer (&source->priv->connection_status_change, g_source_unref);
867 g_mutex_unlock (&source->priv->connection_status_change_lock);
868
869 g_object_freeze_notify (G_OBJECT (source));
870 g_mutex_lock (&source->priv->property_lock);
871
872 if (source->priv->dbus_object) {
873 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
874
875 dbus_source = e_dbus_object_get_source (dbus_object);
876 changed = source_update_connection_status_internal (source, dbus_source);
877 g_object_unref (dbus_source);
878 }
879
880 if (changed)
881 g_object_notify (G_OBJECT (source), "connection-status");
882
883 g_mutex_unlock (&source->priv->property_lock);
884 g_object_thaw_notify (G_OBJECT (source));
885 }
886
887 static gboolean
source_idle_connection_status_change_cb(gpointer user_data)888 source_idle_connection_status_change_cb (gpointer user_data)
889 {
890 ESource *source;
891
892 if (g_source_is_destroyed (g_main_current_source ()))
893 return FALSE;
894
895 source = E_SOURCE (user_data);
896
897 source_update_connection_status (source);
898
899 return FALSE;
900 }
901
902 static void
source_notify_dbus_connection_status_cb(EDBusSource * dbus_source,GParamSpec * pspec,ESource * source)903 source_notify_dbus_connection_status_cb (EDBusSource *dbus_source,
904 GParamSpec *pspec,
905 ESource *source)
906 {
907 g_mutex_lock (&source->priv->connection_status_change_lock);
908 if (source->priv->connection_status_change == NULL &&
909 source->priv->initialized) {
910 source->priv->connection_status_change = g_idle_source_new ();
911 g_source_set_callback (
912 source->priv->connection_status_change,
913 source_idle_connection_status_change_cb,
914 g_object_ref (source), g_object_unref);
915 g_source_attach (
916 source->priv->connection_status_change,
917 source->priv->main_context);
918 }
919 g_mutex_unlock (&source->priv->connection_status_change_lock);
920 }
921
922 static ESourceCredentialsReason
source_credentials_reason_from_text(const gchar * arg_reason)923 source_credentials_reason_from_text (const gchar *arg_reason)
924 {
925 ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
926
927 if (arg_reason && *arg_reason) {
928 GEnumClass *enum_class;
929 GEnumValue *enum_value;
930
931 enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
932 enum_value = g_enum_get_value_by_nick (enum_class, arg_reason);
933
934 if (enum_value) {
935 reason = enum_value->value;
936 } else {
937 g_warning ("%s: Unknown reason enum: '%s'", G_STRFUNC, arg_reason);
938 }
939
940 g_type_class_unref (enum_class);
941 }
942
943 return reason;
944 }
945
946 static GTlsCertificateFlags
source_certificate_errors_from_text(const gchar * arg_certificate_errors)947 source_certificate_errors_from_text (const gchar *arg_certificate_errors)
948 {
949 GTlsCertificateFlags certificate_errors = 0;
950
951 if (arg_certificate_errors && *arg_certificate_errors) {
952 GFlagsClass *flags_class;
953 gchar **flags_strv;
954 gsize ii;
955
956 flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
957 flags_strv = g_strsplit (arg_certificate_errors, ":", -1);
958 for (ii = 0; flags_strv[ii] != NULL; ii++) {
959 GFlagsValue *flags_value;
960
961 flags_value = g_flags_get_value_by_nick (flags_class, flags_strv[ii]);
962 if (flags_value != NULL) {
963 certificate_errors |= flags_value->value;
964 } else {
965 g_warning ("%s: Unknown flag: '%s'", G_STRFUNC, flags_strv[ii]);
966 }
967 }
968 g_strfreev (flags_strv);
969 g_type_class_unref (flags_class);
970 }
971
972 return certificate_errors;
973 }
974
975 static void
source_dbus_credentials_required_cb(EDBusSource * dbus_source,const gchar * arg_reason,const gchar * arg_certificate_pem,const gchar * arg_certificate_errors,const gchar * arg_dbus_error_name,const gchar * arg_dbus_error_message,ESource * source)976 source_dbus_credentials_required_cb (EDBusSource *dbus_source,
977 const gchar *arg_reason,
978 const gchar *arg_certificate_pem,
979 const gchar *arg_certificate_errors,
980 const gchar *arg_dbus_error_name,
981 const gchar *arg_dbus_error_message,
982 ESource *source)
983 {
984 ESourceCredentialsReason reason;
985 GTlsCertificateFlags certificate_errors;
986 GError *op_error = NULL;
987
988 g_return_if_fail (E_IS_SOURCE (source));
989 g_return_if_fail (arg_reason != NULL);
990 g_return_if_fail (arg_certificate_pem != NULL);
991 g_return_if_fail (arg_certificate_errors != NULL);
992 g_return_if_fail (arg_dbus_error_name != NULL);
993 g_return_if_fail (arg_dbus_error_message != NULL);
994
995 reason = source_credentials_reason_from_text (arg_reason);
996 certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
997
998 if (*arg_dbus_error_name) {
999 op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
1000 g_dbus_error_strip_remote_error (op_error);
1001 }
1002
1003 /* This is delivered in the GDBus thread */
1004 e_source_emit_credentials_required (source, reason, arg_certificate_pem, certificate_errors, op_error);
1005
1006 g_clear_error (&op_error);
1007 }
1008
1009 static gboolean
source_dbus_authenticate_cb(EDBusSource * dbus_interface,const gchar * const * arg_credentials,ESource * source)1010 source_dbus_authenticate_cb (EDBusSource *dbus_interface,
1011 const gchar *const *arg_credentials,
1012 ESource *source)
1013 {
1014 ENamedParameters *credentials;
1015
1016 credentials = e_named_parameters_new_strv (arg_credentials);
1017
1018 /* This is delivered in the GDBus thread */
1019 g_signal_emit (source, signals[AUTHENTICATE], 0, credentials);
1020
1021 e_named_parameters_free (credentials);
1022
1023 return TRUE;
1024 }
1025
1026
1027 static gboolean
source_idle_changed_cb(gpointer user_data)1028 source_idle_changed_cb (gpointer user_data)
1029 {
1030 ESource *source = E_SOURCE (user_data);
1031
1032 if (g_source_is_destroyed (g_main_current_source ()))
1033 return FALSE;
1034
1035 g_mutex_lock (&source->priv->changed_lock);
1036 g_clear_pointer (&source->priv->changed, g_source_unref);
1037 g_mutex_unlock (&source->priv->changed_lock);
1038
1039 g_signal_emit (source, signals[CHANGED], 0);
1040
1041 return FALSE;
1042 }
1043
1044 static void
source_set_dbus_object(ESource * source,EDBusObject * dbus_object)1045 source_set_dbus_object (ESource *source,
1046 EDBusObject *dbus_object)
1047 {
1048 /* D-Bus object will be NULL when configuring a new source. */
1049 if (dbus_object == NULL)
1050 return;
1051
1052 g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
1053 g_return_if_fail (source->priv->dbus_object == NULL);
1054
1055 source->priv->dbus_object = g_object_ref (dbus_object);
1056 }
1057
1058 static void
source_set_main_context(ESource * source,GMainContext * main_context)1059 source_set_main_context (ESource *source,
1060 GMainContext *main_context)
1061 {
1062 g_return_if_fail (source->priv->main_context == NULL);
1063
1064 source->priv->main_context =
1065 (main_context != NULL) ?
1066 g_main_context_ref (main_context) :
1067 g_main_context_ref_thread_default ();
1068 }
1069
1070 static void
source_set_uid(ESource * source,const gchar * uid)1071 source_set_uid (ESource *source,
1072 const gchar *uid)
1073 {
1074 /* The "uid" argument will usually be NULL unless called
1075 * from e_source_new_with_uid(). If NULL, we'll pick up
1076 * a UID in source_initable_init(). */
1077
1078 g_return_if_fail (source->priv->uid == NULL);
1079
1080 source->priv->uid = g_strdup (uid);
1081 }
1082
1083 static void
source_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1084 source_set_property (GObject *object,
1085 guint property_id,
1086 const GValue *value,
1087 GParamSpec *pspec)
1088 {
1089 switch (property_id) {
1090 case PROP_DBUS_OBJECT:
1091 source_set_dbus_object (
1092 E_SOURCE (object),
1093 g_value_get_object (value));
1094 return;
1095
1096 case PROP_DISPLAY_NAME:
1097 e_source_set_display_name (
1098 E_SOURCE (object),
1099 g_value_get_string (value));
1100 return;
1101
1102 case PROP_ENABLED:
1103 e_source_set_enabled (
1104 E_SOURCE (object),
1105 g_value_get_boolean (value));
1106 return;
1107
1108 case PROP_MAIN_CONTEXT:
1109 source_set_main_context (
1110 E_SOURCE (object),
1111 g_value_get_boxed (value));
1112 return;
1113
1114 case PROP_PARENT:
1115 e_source_set_parent (
1116 E_SOURCE (object),
1117 g_value_get_string (value));
1118 return;
1119
1120 case PROP_UID:
1121 source_set_uid (
1122 E_SOURCE (object),
1123 g_value_get_string (value));
1124 return;
1125
1126 case PROP_CONNECTION_STATUS:
1127 e_source_set_connection_status (E_SOURCE (object),
1128 g_value_get_enum (value));
1129 return;
1130 }
1131
1132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1133 }
1134
1135 static void
source_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)1136 source_get_property (GObject *object,
1137 guint property_id,
1138 GValue *value,
1139 GParamSpec *pspec)
1140 {
1141 switch (property_id) {
1142 case PROP_DBUS_OBJECT:
1143 g_value_take_object (
1144 value, e_source_ref_dbus_object (
1145 E_SOURCE (object)));
1146 return;
1147
1148 case PROP_DISPLAY_NAME:
1149 g_value_take_string (
1150 value, e_source_dup_display_name (
1151 E_SOURCE (object)));
1152 return;
1153
1154 case PROP_ENABLED:
1155 g_value_set_boolean (
1156 value, e_source_get_enabled (
1157 E_SOURCE (object)));
1158 return;
1159
1160 case PROP_MAIN_CONTEXT:
1161 g_value_take_boxed (
1162 value, e_source_ref_main_context (
1163 E_SOURCE (object)));
1164 return;
1165
1166 case PROP_PARENT:
1167 g_value_take_string (
1168 value, e_source_dup_parent (
1169 E_SOURCE (object)));
1170 return;
1171
1172 case PROP_REMOTE_CREATABLE:
1173 g_value_set_boolean (
1174 value, e_source_get_remote_creatable (
1175 E_SOURCE (object)));
1176 return;
1177
1178 case PROP_REMOTE_DELETABLE:
1179 g_value_set_boolean (
1180 value, e_source_get_remote_deletable (
1181 E_SOURCE (object)));
1182 return;
1183
1184 case PROP_REMOVABLE:
1185 g_value_set_boolean (
1186 value, e_source_get_removable (
1187 E_SOURCE (object)));
1188 return;
1189
1190 case PROP_UID:
1191 g_value_take_string (
1192 value, e_source_dup_uid (
1193 E_SOURCE (object)));
1194 return;
1195
1196 case PROP_WRITABLE:
1197 g_value_set_boolean (
1198 value, e_source_get_writable (
1199 E_SOURCE (object)));
1200 return;
1201
1202 case PROP_CONNECTION_STATUS:
1203 g_value_set_enum (value,
1204 e_source_get_connection_status (E_SOURCE (object)));
1205 return;
1206 }
1207
1208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1209 }
1210
1211 static void
source_dispose(GObject * object)1212 source_dispose (GObject *object)
1213 {
1214 ESourcePrivate *priv;
1215
1216 priv = E_SOURCE (object)->priv;
1217
1218 /* Lock & unlock to make sure any pending operations in other threads
1219 which use this lock are already done */
1220 g_rec_mutex_lock (&priv->lock);
1221 g_rec_mutex_unlock (&priv->lock);
1222
1223 g_mutex_lock (&priv->property_lock);
1224
1225 if (priv->dbus_object != NULL) {
1226 EDBusObject *dbus_object;
1227 EDBusSource *dbus_source;
1228
1229 dbus_object = E_DBUS_OBJECT (priv->dbus_object);
1230
1231 dbus_source = e_dbus_object_get_source (dbus_object);
1232 if (dbus_source != NULL) {
1233 g_signal_handlers_disconnect_matched (
1234 dbus_source, G_SIGNAL_MATCH_DATA,
1235 0, 0, NULL, NULL, object);
1236 g_object_unref (dbus_source);
1237 }
1238
1239 g_object_unref (priv->dbus_object);
1240 priv->dbus_object = NULL;
1241 }
1242
1243 g_mutex_unlock (&priv->property_lock);
1244
1245 g_clear_pointer (&priv->main_context, g_main_context_unref);
1246
1247 /* XXX Maybe not necessary to acquire the lock? */
1248 g_mutex_lock (&priv->changed_lock);
1249 if (priv->changed != NULL) {
1250 g_source_destroy (priv->changed);
1251 g_source_unref (priv->changed);
1252 priv->changed = NULL;
1253 }
1254 g_mutex_unlock (&priv->changed_lock);
1255
1256 g_mutex_lock (&priv->connection_status_change_lock);
1257 if (priv->connection_status_change != NULL) {
1258 g_source_destroy (priv->connection_status_change);
1259 g_source_unref (priv->connection_status_change);
1260 priv->connection_status_change = NULL;
1261 }
1262 g_mutex_unlock (&priv->connection_status_change_lock);
1263
1264 g_hash_table_remove_all (priv->extensions);
1265
1266 /* Chain up to parent's dispose() method. */
1267 G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
1268 }
1269
1270 static void
source_finalize(GObject * object)1271 source_finalize (GObject *object)
1272 {
1273 ESourcePrivate *priv;
1274
1275 priv = E_SOURCE (object)->priv;
1276
1277 g_mutex_clear (&priv->changed_lock);
1278 g_mutex_clear (&priv->connection_status_change_lock);
1279 g_mutex_clear (&priv->property_lock);
1280
1281 g_free (priv->display_name);
1282 g_free (priv->collate_key);
1283 g_free (priv->parent);
1284 g_free (priv->uid);
1285
1286 g_key_file_free (priv->key_file);
1287 g_rec_mutex_clear (&priv->lock);
1288 g_hash_table_destroy (priv->extensions);
1289
1290 /* Chain up to parent's finalize() method. */
1291 G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
1292 }
1293
1294 static void
source_notify(GObject * object,GParamSpec * pspec)1295 source_notify (GObject *object,
1296 GParamSpec *pspec)
1297 {
1298 if ((pspec->flags & E_SOURCE_PARAM_SETTING) != 0)
1299 e_source_changed (E_SOURCE (object));
1300 }
1301
1302 /* Helper for source_remove_sync() */
1303 static gboolean
source_remove_main_loop_quit_cb(gpointer user_data)1304 source_remove_main_loop_quit_cb (gpointer user_data)
1305 {
1306 GMainLoop *main_loop = user_data;
1307
1308 g_main_loop_quit (main_loop);
1309
1310 return FALSE;
1311 }
1312
1313 /* Helper for e_source_remove_sync() */
1314 static void
source_remove_notify_dbus_object_cb(ESource * source,GParamSpec * pspec,RemoveContext * remove_context)1315 source_remove_notify_dbus_object_cb (ESource *source,
1316 GParamSpec *pspec,
1317 RemoveContext *remove_context)
1318 {
1319 GDBusObject *dbus_object;
1320
1321 dbus_object = e_source_ref_dbus_object (source);
1322
1323 /* The GDBusObject will be NULL once the ESourceRegistry
1324 * receives an "object-removed" signal for this ESource. */
1325 if (dbus_object == NULL) {
1326 GSource *idle_source;
1327
1328 idle_source = g_idle_source_new ();
1329 g_source_set_callback (
1330 idle_source,
1331 source_remove_main_loop_quit_cb,
1332 g_main_loop_ref (remove_context->main_loop),
1333 (GDestroyNotify) g_main_loop_unref);
1334 g_source_attach (idle_source, remove_context->main_context);
1335 g_source_unref (idle_source);
1336 }
1337
1338 g_clear_object (&dbus_object);
1339 }
1340
1341 static gboolean
source_remove_sync(ESource * source,GCancellable * cancellable,GError ** error)1342 source_remove_sync (ESource *source,
1343 GCancellable *cancellable,
1344 GError **error)
1345 {
1346 EDBusSourceRemovable *dbus_interface = NULL;
1347 GDBusObject *dbus_object;
1348 RemoveContext *remove_context;
1349 gulong notify_dbus_object_id;
1350 GError *local_error = NULL;
1351
1352 dbus_object = e_source_ref_dbus_object (source);
1353 if (dbus_object != NULL) {
1354 dbus_interface =
1355 e_dbus_object_get_source_removable (
1356 E_DBUS_OBJECT (dbus_object));
1357 g_object_unref (dbus_object);
1358 }
1359
1360 if (dbus_interface == NULL) {
1361 g_set_error (
1362 error, G_IO_ERROR,
1363 G_IO_ERROR_PERMISSION_DENIED,
1364 _("Data source “%s” is not removable"),
1365 e_source_get_display_name (source));
1366 return FALSE;
1367 }
1368
1369 remove_context = remove_context_new ();
1370 g_main_context_push_thread_default (remove_context->main_context);
1371
1372 notify_dbus_object_id = g_signal_connect (
1373 source, "notify::dbus-object",
1374 G_CALLBACK (source_remove_notify_dbus_object_cb),
1375 remove_context);
1376
1377 e_dbus_source_removable_call_remove_sync (
1378 dbus_interface, cancellable, &local_error);
1379
1380 /* Wait for the ESourceRegistry to remove our GDBusObject while
1381 * handling an "object-removed" signal from the registry service.
1382 * But also set a short timeout to avoid getting deadlocked here. */
1383 if (local_error == NULL) {
1384 GSource *timeout_source;
1385
1386 timeout_source = g_timeout_source_new_seconds (2);
1387 g_source_set_callback (
1388 timeout_source,
1389 source_remove_main_loop_quit_cb,
1390 g_main_loop_ref (remove_context->main_loop),
1391 (GDestroyNotify) g_main_loop_unref);
1392 g_source_attach (timeout_source, remove_context->main_context);
1393 g_source_unref (timeout_source);
1394
1395 g_main_loop_run (remove_context->main_loop);
1396 }
1397
1398 g_signal_handler_disconnect (source, notify_dbus_object_id);
1399
1400 g_main_context_pop_thread_default (remove_context->main_context);
1401 remove_context_free (remove_context);
1402
1403 g_object_unref (dbus_interface);
1404
1405 if (local_error != NULL) {
1406 g_dbus_error_strip_remote_error (local_error);
1407 g_propagate_error (error, local_error);
1408 return FALSE;
1409 }
1410
1411 return TRUE;
1412 }
1413
1414 /* Helper for source_remove() */
1415 static void
source_remove_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1416 source_remove_thread (GSimpleAsyncResult *simple,
1417 GObject *object,
1418 GCancellable *cancellable)
1419 {
1420 GError *local_error = NULL;
1421
1422 e_source_remove_sync (E_SOURCE (object), cancellable, &local_error);
1423
1424 if (local_error != NULL)
1425 g_simple_async_result_take_error (simple, local_error);
1426 }
1427
1428 static void
source_remove(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1429 source_remove (ESource *source,
1430 GCancellable *cancellable,
1431 GAsyncReadyCallback callback,
1432 gpointer user_data)
1433 {
1434 GSimpleAsyncResult *simple;
1435
1436 simple = g_simple_async_result_new (
1437 G_OBJECT (source), callback, user_data, source_remove);
1438
1439 g_simple_async_result_set_check_cancellable (simple, cancellable);
1440
1441 g_simple_async_result_run_in_thread (
1442 simple, source_remove_thread,
1443 G_PRIORITY_DEFAULT, cancellable);
1444
1445 g_object_unref (simple);
1446 }
1447
1448 static gboolean
source_remove_finish(ESource * source,GAsyncResult * result,GError ** error)1449 source_remove_finish (ESource *source,
1450 GAsyncResult *result,
1451 GError **error)
1452 {
1453 GSimpleAsyncResult *simple;
1454
1455 g_return_val_if_fail (
1456 g_simple_async_result_is_valid (
1457 result, G_OBJECT (source), source_remove), FALSE);
1458
1459 simple = G_SIMPLE_ASYNC_RESULT (result);
1460
1461 /* Assume success unless a GError is set. */
1462 return !g_simple_async_result_propagate_error (simple, error);
1463 }
1464
1465 static gboolean
source_write_sync(ESource * source,GCancellable * cancellable,GError ** error)1466 source_write_sync (ESource *source,
1467 GCancellable *cancellable,
1468 GError **error)
1469 {
1470 EDBusSourceWritable *dbus_interface = NULL;
1471 GDBusObject *dbus_object;
1472 gchar *data;
1473 GError *local_error = NULL;
1474
1475 dbus_object = e_source_ref_dbus_object (source);
1476 if (dbus_object != NULL) {
1477 dbus_interface =
1478 e_dbus_object_get_source_writable (
1479 E_DBUS_OBJECT (dbus_object));
1480 g_object_unref (dbus_object);
1481 }
1482
1483 if (dbus_interface == NULL) {
1484 g_set_error (
1485 error, G_IO_ERROR,
1486 G_IO_ERROR_PERMISSION_DENIED,
1487 _("Data source “%s” is not writable"),
1488 e_source_get_display_name (source));
1489 return FALSE;
1490 }
1491
1492 data = e_source_to_string (source, NULL);
1493
1494 e_dbus_source_writable_call_write_sync (
1495 dbus_interface, data, cancellable, &local_error);
1496
1497 g_free (data);
1498
1499 g_object_unref (dbus_interface);
1500
1501 if (local_error != NULL) {
1502 g_dbus_error_strip_remote_error (local_error);
1503 g_propagate_error (error, local_error);
1504 return FALSE;
1505 }
1506
1507 return TRUE;
1508 }
1509
1510 /* Helper for source_write() */
1511 static void
source_write_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1512 source_write_thread (GSimpleAsyncResult *simple,
1513 GObject *object,
1514 GCancellable *cancellable)
1515 {
1516 GError *local_error = NULL;
1517
1518 e_source_write_sync (E_SOURCE (object), cancellable, &local_error);
1519
1520 if (local_error != NULL)
1521 g_simple_async_result_take_error (simple, local_error);
1522 }
1523
1524 static void
source_write(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1525 source_write (ESource *source,
1526 GCancellable *cancellable,
1527 GAsyncReadyCallback callback,
1528 gpointer user_data)
1529 {
1530 GSimpleAsyncResult *simple;
1531
1532 simple = g_simple_async_result_new (
1533 G_OBJECT (source), callback, user_data, source_write);
1534
1535 g_simple_async_result_set_check_cancellable (simple, cancellable);
1536
1537 g_simple_async_result_run_in_thread (
1538 simple, source_write_thread,
1539 G_PRIORITY_DEFAULT, cancellable);
1540
1541 g_object_unref (simple);
1542 }
1543
1544 static gboolean
source_write_finish(ESource * source,GAsyncResult * result,GError ** error)1545 source_write_finish (ESource *source,
1546 GAsyncResult *result,
1547 GError **error)
1548 {
1549 GSimpleAsyncResult *simple;
1550
1551 g_return_val_if_fail (
1552 g_simple_async_result_is_valid (
1553 result, G_OBJECT (source), source_write), FALSE);
1554
1555 simple = G_SIMPLE_ASYNC_RESULT (result);
1556
1557 /* Assume success unless a GError is set. */
1558 return !g_simple_async_result_propagate_error (simple, error);
1559 }
1560
1561 static gboolean
source_remote_create_sync(ESource * source,ESource * scratch_source,GCancellable * cancellable,GError ** error)1562 source_remote_create_sync (ESource *source,
1563 ESource *scratch_source,
1564 GCancellable *cancellable,
1565 GError **error)
1566 {
1567 EDBusSourceRemoteCreatable *dbus_interface = NULL;
1568 GDBusObject *dbus_object;
1569 gchar *uid, *data;
1570 GError *local_error = NULL;
1571
1572 dbus_object = e_source_ref_dbus_object (source);
1573 if (dbus_object != NULL) {
1574 dbus_interface =
1575 e_dbus_object_get_source_remote_creatable (
1576 E_DBUS_OBJECT (dbus_object));
1577 g_object_unref (dbus_object);
1578 }
1579
1580 if (dbus_interface == NULL) {
1581 g_set_error (
1582 error, G_IO_ERROR,
1583 G_IO_ERROR_NOT_SUPPORTED,
1584 _("Data source “%s” does not "
1585 "support creating remote resources"),
1586 e_source_get_display_name (source));
1587 return FALSE;
1588 }
1589
1590 uid = e_source_dup_uid (scratch_source);
1591 data = e_source_to_string (scratch_source, NULL);
1592
1593 e_dbus_source_remote_creatable_call_create_sync (
1594 dbus_interface, uid, data, cancellable, &local_error);
1595
1596 g_free (data);
1597 g_free (uid);
1598
1599 g_object_unref (dbus_interface);
1600
1601 if (local_error != NULL) {
1602 g_dbus_error_strip_remote_error (local_error);
1603 g_propagate_error (error, local_error);
1604 return FALSE;
1605 }
1606
1607 return TRUE;
1608 }
1609
1610 /* Helper for source_remote_create() */
1611 static void
source_remote_create_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1612 source_remote_create_thread (GSimpleAsyncResult *simple,
1613 GObject *object,
1614 GCancellable *cancellable)
1615 {
1616 AsyncContext *async_context;
1617 GError *local_error = NULL;
1618
1619 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1620
1621 e_source_remote_create_sync (
1622 E_SOURCE (object),
1623 async_context->scratch_source,
1624 cancellable, &local_error);
1625
1626 if (local_error != NULL)
1627 g_simple_async_result_take_error (simple, local_error);
1628 }
1629
1630 static void
source_remote_create(ESource * source,ESource * scratch_source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1631 source_remote_create (ESource *source,
1632 ESource *scratch_source,
1633 GCancellable *cancellable,
1634 GAsyncReadyCallback callback,
1635 gpointer user_data)
1636 {
1637 GSimpleAsyncResult *simple;
1638 AsyncContext *async_context;
1639
1640 async_context = g_slice_new0 (AsyncContext);
1641 async_context->scratch_source = g_object_ref (scratch_source);
1642
1643 simple = g_simple_async_result_new (
1644 G_OBJECT (source), callback,
1645 user_data, source_remote_create);
1646
1647 g_simple_async_result_set_check_cancellable (simple, cancellable);
1648
1649 g_simple_async_result_set_op_res_gpointer (
1650 simple, async_context, (GDestroyNotify) async_context_free);
1651
1652 g_simple_async_result_run_in_thread (
1653 simple, source_remote_create_thread,
1654 G_PRIORITY_DEFAULT, cancellable);
1655
1656 g_object_unref (simple);
1657 }
1658
1659 static gboolean
source_remote_create_finish(ESource * source,GAsyncResult * result,GError ** error)1660 source_remote_create_finish (ESource *source,
1661 GAsyncResult *result,
1662 GError **error)
1663 {
1664 GSimpleAsyncResult *simple;
1665
1666 g_return_val_if_fail (
1667 g_simple_async_result_is_valid (
1668 result, G_OBJECT (source), source_remote_create), FALSE);
1669
1670 simple = G_SIMPLE_ASYNC_RESULT (result);
1671
1672 /* Assume success unless a GError is set. */
1673 return !g_simple_async_result_propagate_error (simple, error);
1674 }
1675
1676 static gboolean
source_remote_delete_sync(ESource * source,GCancellable * cancellable,GError ** error)1677 source_remote_delete_sync (ESource *source,
1678 GCancellable *cancellable,
1679 GError **error)
1680 {
1681 EDBusSourceRemoteDeletable *dbus_interface = NULL;
1682 GDBusObject *dbus_object;
1683 GError *local_error = NULL;
1684
1685 dbus_object = e_source_ref_dbus_object (source);
1686 if (dbus_object != NULL) {
1687 dbus_interface =
1688 e_dbus_object_get_source_remote_deletable (
1689 E_DBUS_OBJECT (dbus_object));
1690 g_object_unref (dbus_object);
1691 }
1692
1693 if (dbus_interface == NULL) {
1694 g_set_error (
1695 error, G_IO_ERROR,
1696 G_IO_ERROR_NOT_SUPPORTED,
1697 _("Data source “%s” does not "
1698 "support deleting remote resources"),
1699 e_source_get_display_name (source));
1700 return FALSE;
1701 }
1702
1703 e_dbus_source_remote_deletable_call_delete_sync (
1704 dbus_interface, cancellable, &local_error);
1705
1706 g_object_unref (dbus_interface);
1707
1708 if (local_error != NULL) {
1709 g_dbus_error_strip_remote_error (local_error);
1710 g_propagate_error (error, local_error);
1711 return FALSE;
1712 }
1713
1714 return TRUE;
1715 }
1716
1717 /* Helper for source_remote_delete() */
1718 static void
source_remote_delete_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1719 source_remote_delete_thread (GSimpleAsyncResult *simple,
1720 GObject *object,
1721 GCancellable *cancellable)
1722 {
1723 GError *local_error = NULL;
1724
1725 e_source_remote_delete_sync (
1726 E_SOURCE (object), cancellable, &local_error);
1727
1728 if (local_error != NULL)
1729 g_simple_async_result_take_error (simple, local_error);
1730 }
1731
1732 static void
source_remote_delete(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1733 source_remote_delete (ESource *source,
1734 GCancellable *cancellable,
1735 GAsyncReadyCallback callback,
1736 gpointer user_data)
1737 {
1738 GSimpleAsyncResult *simple;
1739
1740 simple = g_simple_async_result_new (
1741 G_OBJECT (source), callback,
1742 user_data, source_remote_delete);
1743
1744 g_simple_async_result_set_check_cancellable (simple, cancellable);
1745
1746 g_simple_async_result_run_in_thread (
1747 simple, source_remote_delete_thread,
1748 G_PRIORITY_DEFAULT, cancellable);
1749
1750 g_object_unref (simple);
1751 }
1752
1753 static gboolean
source_remote_delete_finish(ESource * source,GAsyncResult * result,GError ** error)1754 source_remote_delete_finish (ESource *source,
1755 GAsyncResult *result,
1756 GError **error)
1757 {
1758 GSimpleAsyncResult *simple;
1759
1760 g_return_val_if_fail (
1761 g_simple_async_result_is_valid (
1762 result, G_OBJECT (source), source_remote_delete), FALSE);
1763
1764 simple = G_SIMPLE_ASYNC_RESULT (result);
1765
1766 /* Assume success unless a GError is set. */
1767 return !g_simple_async_result_propagate_error (simple, error);
1768 }
1769
1770 static gboolean
source_get_oauth2_access_token_sync(ESource * source,GCancellable * cancellable,gchar ** out_access_token,gint * out_expires_in,GError ** error)1771 source_get_oauth2_access_token_sync (ESource *source,
1772 GCancellable *cancellable,
1773 gchar **out_access_token,
1774 gint *out_expires_in,
1775 GError **error)
1776 {
1777 EDBusSourceOAuth2Support *dbus_interface = NULL;
1778 GDBusObject *dbus_object;
1779 GError *local_error = NULL;
1780
1781 dbus_object = e_source_ref_dbus_object (source);
1782 if (dbus_object != NULL) {
1783 dbus_interface =
1784 e_dbus_object_get_source_oauth2_support (
1785 E_DBUS_OBJECT (dbus_object));
1786 g_object_unref (dbus_object);
1787 }
1788
1789 if (!dbus_interface) {
1790 ESourceRegistry *registry;
1791
1792 registry = e_source_registry_new_sync (NULL, NULL);
1793
1794 if (registry) {
1795 EOAuth2Services *oauth2_services;
1796 EOAuth2Service *service = NULL;
1797
1798 oauth2_services = e_source_registry_get_oauth2_services (registry);
1799
1800 if (oauth2_services)
1801 service = e_oauth2_services_find (oauth2_services, source);
1802
1803 if (service) {
1804 EOAuth2ServiceRefSourceFunc ref_source;
1805 gboolean success;
1806
1807 ref_source = (EOAuth2ServiceRefSourceFunc) e_source_registry_ref_source;
1808
1809 success = e_oauth2_service_get_access_token_sync (service, source, ref_source, registry,
1810 out_access_token, out_expires_in, cancellable, error);
1811
1812 g_clear_object (&service);
1813 g_object_unref (registry);
1814
1815 return success;
1816 }
1817
1818 g_object_unref (registry);
1819 }
1820 }
1821
1822 if (dbus_interface == NULL) {
1823 g_set_error (
1824 error, G_IO_ERROR,
1825 G_IO_ERROR_NOT_SUPPORTED,
1826 _("Data source “%s” does not "
1827 "support OAuth 2.0 authentication"),
1828 e_source_get_display_name (source));
1829 return FALSE;
1830 }
1831
1832 e_dbus_source_oauth2_support_call_get_access_token_sync (
1833 dbus_interface, out_access_token,
1834 out_expires_in, cancellable, &local_error);
1835
1836 g_object_unref (dbus_interface);
1837
1838 if (local_error != NULL) {
1839 g_dbus_error_strip_remote_error (local_error);
1840 g_propagate_error (error, local_error);
1841 return FALSE;
1842 }
1843
1844 return TRUE;
1845 }
1846
1847 /* Helper for source_get_oauth2_access_token() */
1848 static void
source_get_oauth2_access_token_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1849 source_get_oauth2_access_token_thread (GSimpleAsyncResult *simple,
1850 GObject *object,
1851 GCancellable *cancellable)
1852 {
1853 AsyncContext *async_context;
1854 GError *local_error = NULL;
1855
1856 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1857
1858 e_source_get_oauth2_access_token_sync (
1859 E_SOURCE (object), cancellable,
1860 &async_context->access_token,
1861 &async_context->expires_in,
1862 &local_error);
1863
1864 if (local_error != NULL)
1865 g_simple_async_result_take_error (simple, local_error);
1866 }
1867
1868 static void
source_get_oauth2_access_token(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1869 source_get_oauth2_access_token (ESource *source,
1870 GCancellable *cancellable,
1871 GAsyncReadyCallback callback,
1872 gpointer user_data)
1873 {
1874 GSimpleAsyncResult *simple;
1875 AsyncContext *async_context;
1876
1877 async_context = g_slice_new0 (AsyncContext);
1878
1879 simple = g_simple_async_result_new (
1880 G_OBJECT (source), callback, user_data,
1881 source_get_oauth2_access_token);
1882
1883 g_simple_async_result_set_check_cancellable (simple, cancellable);
1884
1885 g_simple_async_result_set_op_res_gpointer (
1886 simple, async_context, (GDestroyNotify) async_context_free);
1887
1888 g_simple_async_result_run_in_thread (
1889 simple, source_get_oauth2_access_token_thread,
1890 G_PRIORITY_DEFAULT, cancellable);
1891
1892 g_object_unref (simple);
1893 }
1894
1895 static gboolean
source_get_oauth2_access_token_finish(ESource * source,GAsyncResult * result,gchar ** out_access_token,gint * out_expires_in,GError ** error)1896 source_get_oauth2_access_token_finish (ESource *source,
1897 GAsyncResult *result,
1898 gchar **out_access_token,
1899 gint *out_expires_in,
1900 GError **error)
1901 {
1902 GSimpleAsyncResult *simple;
1903 AsyncContext *async_context;
1904
1905 g_return_val_if_fail (
1906 g_simple_async_result_is_valid (
1907 result, G_OBJECT (source),
1908 source_get_oauth2_access_token), FALSE);
1909
1910 simple = G_SIMPLE_ASYNC_RESULT (result);
1911 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1912
1913 if (g_simple_async_result_propagate_error (simple, error))
1914 return FALSE;
1915
1916 g_return_val_if_fail (async_context->access_token != NULL, FALSE);
1917
1918 if (out_access_token != NULL) {
1919 *out_access_token = async_context->access_token;
1920 async_context->access_token = NULL;
1921 }
1922
1923 if (out_expires_in != NULL)
1924 *out_expires_in = async_context->expires_in;
1925
1926 return TRUE;
1927 }
1928
1929
1930 static gboolean
source_invoke_credentials_required_impl(ESource * source,gpointer dbus_source,const gchar * arg_reason,const gchar * arg_certificate_pem,const gchar * arg_certificate_errors,const gchar * arg_dbus_error_name,const gchar * arg_dbus_error_message,GCancellable * cancellable,GError ** error)1931 source_invoke_credentials_required_impl (ESource *source,
1932 gpointer dbus_source, /* EDBusSource * */
1933 const gchar *arg_reason,
1934 const gchar *arg_certificate_pem,
1935 const gchar *arg_certificate_errors,
1936 const gchar *arg_dbus_error_name,
1937 const gchar *arg_dbus_error_message,
1938 GCancellable *cancellable,
1939 GError **error)
1940 {
1941 g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1942
1943 return e_dbus_source_call_invoke_credentials_required_sync (dbus_source,
1944 arg_reason ? arg_reason : "",
1945 arg_certificate_pem ? arg_certificate_pem : "",
1946 arg_certificate_errors ? arg_certificate_errors : "",
1947 arg_dbus_error_name ? arg_dbus_error_name : "",
1948 arg_dbus_error_message ? arg_dbus_error_message : "",
1949 cancellable, error);
1950 }
1951
1952 static gboolean
source_invoke_authenticate_impl(ESource * source,gpointer dbus_source,const gchar * const * arg_credentials,GCancellable * cancellable,GError ** error)1953 source_invoke_authenticate_impl (ESource *source,
1954 gpointer dbus_source, /* EDBusSource * */
1955 const gchar * const *arg_credentials,
1956 GCancellable *cancellable,
1957 GError **error)
1958 {
1959 g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1960
1961 return e_dbus_source_call_invoke_authenticate_sync (dbus_source, arg_credentials, cancellable, error);
1962 }
1963
1964 static gboolean
source_unset_last_credentials_required_arguments_impl(ESource * source,GCancellable * cancellable,GError ** error)1965 source_unset_last_credentials_required_arguments_impl (ESource *source,
1966 GCancellable *cancellable,
1967 GError **error)
1968 {
1969 GDBusObject *dbus_object;
1970 EDBusSource *dbus_source = NULL;
1971 gboolean success;
1972 GError *local_error = NULL;
1973
1974 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1975
1976 dbus_object = e_source_ref_dbus_object (source);
1977 if (dbus_object != NULL) {
1978 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1979 g_object_unref (dbus_object);
1980 }
1981
1982 if (!dbus_source)
1983 return FALSE;
1984
1985 success = e_dbus_source_call_unset_last_credentials_required_arguments_sync (dbus_source, cancellable, &local_error);
1986
1987 g_object_unref (dbus_source);
1988
1989 if (local_error != NULL) {
1990 g_dbus_error_strip_remote_error (local_error);
1991 g_propagate_error (error, local_error);
1992 return FALSE;
1993 }
1994
1995 return success;
1996 }
1997
1998 static void
source_connect_dbus_source(ESource * source)1999 source_connect_dbus_source (ESource *source)
2000 {
2001 EDBusObject *dbus_object;
2002 EDBusSource *dbus_source;
2003
2004 g_return_if_fail (E_IS_SOURCE (source));
2005
2006 if (!source->priv->dbus_object)
2007 return;
2008
2009 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
2010
2011 /* An EDBusObject lacking an EDBusSource
2012 * interface indicates a programmer error. */
2013 dbus_source = e_dbus_object_get_source (dbus_object);
2014 g_return_if_fail (E_DBUS_IS_SOURCE (dbus_source));
2015
2016 g_signal_connect_object (
2017 dbus_source, "notify::data",
2018 G_CALLBACK (source_notify_dbus_data_cb), source, 0);
2019 g_signal_connect_object (
2020 dbus_source, "notify::connection-status",
2021 G_CALLBACK (source_notify_dbus_connection_status_cb), source, 0);
2022 g_signal_connect_object (
2023 dbus_source, "credentials-required",
2024 G_CALLBACK (source_dbus_credentials_required_cb), source, 0);
2025 g_signal_connect_object (
2026 dbus_source, "authenticate",
2027 G_CALLBACK (source_dbus_authenticate_cb), source, 0);
2028
2029 g_clear_object (&dbus_source);
2030 }
2031
2032 static gboolean
source_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)2033 source_initable_init (GInitable *initable,
2034 GCancellable *cancellable,
2035 GError **error)
2036 {
2037 ESource *source;
2038 gboolean success = TRUE;
2039
2040 source = E_SOURCE (initable);
2041
2042 /* The D-Bus object has the unique identifier (UID). */
2043 if (source->priv->dbus_object != NULL) {
2044 EDBusObject *dbus_object;
2045 EDBusSource *dbus_source;
2046
2047 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
2048
2049 /* An EDBusObject lacking an EDBusSource
2050 * interface indicates a programmer error. */
2051 dbus_source = e_dbus_object_get_source (dbus_object);
2052 g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
2053
2054 /* The UID never changes, so we can cache a copy.
2055 *
2056 * XXX Note, EServerSideSource may have already set this
2057 * by way of the "uid" construct-only property, hence
2058 * the g_free() call. Not a problem, we'll just free
2059 * our UID string and set it to the same value again. */
2060 g_free (source->priv->uid);
2061 source->priv->uid = e_dbus_source_dup_uid (dbus_source);
2062
2063 source_update_connection_status_internal (source, dbus_source);
2064 source_connect_dbus_source (source);
2065
2066 success = source_parse_dbus_data (source, error);
2067
2068 g_object_unref (dbus_source);
2069
2070 /* No D-Bus object implies we're configuring a new source,
2071 * so generate a new unique identifier (UID) unless one was
2072 * explicitly provided through e_source_new_with_uid(). */
2073 } else if (source->priv->uid == NULL) {
2074 source->priv->uid = e_util_generate_uid ();
2075 }
2076
2077 source->priv->initialized = TRUE;
2078
2079 return success;
2080 }
2081
2082 static gboolean
source_proxy_resolver_is_supported(GProxyResolver * resolver)2083 source_proxy_resolver_is_supported (GProxyResolver *resolver)
2084 {
2085 return e_source_has_extension (
2086 E_SOURCE (resolver), E_SOURCE_EXTENSION_PROXY);
2087 }
2088
2089 static gchar **
source_proxy_resolver_lookup(GProxyResolver * resolver,const gchar * uri,GCancellable * cancellable,GError ** error)2090 source_proxy_resolver_lookup (GProxyResolver *resolver,
2091 const gchar *uri,
2092 GCancellable *cancellable,
2093 GError **error)
2094 {
2095 return e_source_proxy_lookup_sync (
2096 E_SOURCE (resolver), uri, cancellable, error);
2097 }
2098
2099 /* Helper for source_proxy_resolver_lookup_async() */
2100 static void
source_proxy_resolver_lookup_ready_cb(GObject * object,GAsyncResult * result,gpointer user_data)2101 source_proxy_resolver_lookup_ready_cb (GObject *object,
2102 GAsyncResult *result,
2103 gpointer user_data)
2104 {
2105 GSimpleAsyncResult *simple;
2106 gchar **proxies;
2107 GError *local_error = NULL;
2108
2109 simple = G_SIMPLE_ASYNC_RESULT (user_data);
2110
2111 proxies = e_source_proxy_lookup_finish (
2112 E_SOURCE (object), result, &local_error);
2113
2114 /* Sanity check. */
2115 g_return_if_fail (
2116 ((proxies != NULL) && (local_error == NULL)) ||
2117 ((proxies == NULL) && (local_error != NULL)));
2118
2119 if (proxies != NULL) {
2120 g_simple_async_result_set_op_res_gpointer (
2121 simple, proxies, (GDestroyNotify) g_strfreev);
2122 } else {
2123 g_simple_async_result_take_error (simple, local_error);
2124 }
2125
2126 g_simple_async_result_complete (simple);
2127
2128 g_object_unref (simple);
2129 }
2130
2131 static void
source_proxy_resolver_lookup_async(GProxyResolver * resolver,const gchar * uri,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2132 source_proxy_resolver_lookup_async (GProxyResolver *resolver,
2133 const gchar *uri,
2134 GCancellable *cancellable,
2135 GAsyncReadyCallback callback,
2136 gpointer user_data)
2137 {
2138 GSimpleAsyncResult *simple;
2139
2140 simple = g_simple_async_result_new (
2141 G_OBJECT (resolver), callback, user_data,
2142 source_proxy_resolver_lookup_async);
2143
2144 g_simple_async_result_set_check_cancellable (simple, cancellable);
2145
2146 e_source_proxy_lookup (
2147 E_SOURCE (resolver), uri, cancellable,
2148 source_proxy_resolver_lookup_ready_cb,
2149 g_object_ref (simple));
2150
2151 g_object_unref (simple);
2152 }
2153
2154 static gchar **
source_proxy_resolver_lookup_finish(GProxyResolver * resolver,GAsyncResult * result,GError ** error)2155 source_proxy_resolver_lookup_finish (GProxyResolver *resolver,
2156 GAsyncResult *result,
2157 GError **error)
2158 {
2159 GSimpleAsyncResult *simple;
2160 gchar **proxies;
2161
2162 g_return_val_if_fail (
2163 g_simple_async_result_is_valid (
2164 result, G_OBJECT (resolver),
2165 source_proxy_resolver_lookup_async), NULL);
2166
2167 simple = G_SIMPLE_ASYNC_RESULT (result);
2168
2169 if (g_simple_async_result_propagate_error (simple, error))
2170 return NULL;
2171
2172 proxies = g_simple_async_result_get_op_res_gpointer (simple);
2173
2174 return g_strdupv (proxies);
2175 }
2176
2177 static void
e_source_class_init(ESourceClass * class)2178 e_source_class_init (ESourceClass *class)
2179 {
2180 GObjectClass *object_class;
2181
2182 object_class = G_OBJECT_CLASS (class);
2183 object_class->set_property = source_set_property;
2184 object_class->get_property = source_get_property;
2185 object_class->dispose = source_dispose;
2186 object_class->finalize = source_finalize;
2187 object_class->notify = source_notify;
2188
2189 class->remove_sync = source_remove_sync;
2190 class->remove = source_remove;
2191 class->remove_finish = source_remove_finish;
2192 class->write_sync = source_write_sync;
2193 class->write = source_write;
2194 class->write_finish = source_write_finish;
2195 class->remote_create_sync = source_remote_create_sync;
2196 class->remote_create = source_remote_create;
2197 class->remote_create_finish = source_remote_create_finish;
2198 class->remote_delete_sync = source_remote_delete_sync;
2199 class->remote_delete = source_remote_delete;
2200 class->remote_delete_finish = source_remote_delete_finish;
2201 class->get_oauth2_access_token_sync = source_get_oauth2_access_token_sync;
2202 class->get_oauth2_access_token = source_get_oauth2_access_token;
2203 class->get_oauth2_access_token_finish = source_get_oauth2_access_token_finish;
2204 class->invoke_credentials_required_impl = source_invoke_credentials_required_impl;
2205 class->invoke_authenticate_impl = source_invoke_authenticate_impl;
2206 class->unset_last_credentials_required_arguments_impl = source_unset_last_credentials_required_arguments_impl;
2207
2208 g_object_class_install_property (
2209 object_class,
2210 PROP_DBUS_OBJECT,
2211 g_param_spec_object (
2212 "dbus-object",
2213 "D-Bus Object",
2214 "The D-Bus object for the data source",
2215 E_DBUS_TYPE_OBJECT,
2216 G_PARAM_READWRITE |
2217 G_PARAM_CONSTRUCT_ONLY |
2218 G_PARAM_STATIC_STRINGS));
2219
2220 g_object_class_install_property (
2221 object_class,
2222 PROP_DISPLAY_NAME,
2223 g_param_spec_string (
2224 "display-name",
2225 "Display Name",
2226 "The human-readable name of the data source",
2227 _("Unnamed"),
2228 G_PARAM_READWRITE |
2229 G_PARAM_CONSTRUCT |
2230 G_PARAM_EXPLICIT_NOTIFY |
2231 G_PARAM_STATIC_STRINGS |
2232 E_SOURCE_PARAM_SETTING));
2233
2234 g_object_class_install_property (
2235 object_class,
2236 PROP_ENABLED,
2237 g_param_spec_boolean (
2238 "enabled",
2239 "Enabled",
2240 "Whether the data source is enabled",
2241 TRUE,
2242 G_PARAM_READWRITE |
2243 G_PARAM_CONSTRUCT |
2244 G_PARAM_EXPLICIT_NOTIFY |
2245 G_PARAM_STATIC_STRINGS |
2246 E_SOURCE_PARAM_SETTING));
2247
2248 g_object_class_install_property (
2249 object_class,
2250 PROP_MAIN_CONTEXT,
2251 g_param_spec_boxed (
2252 "main-context",
2253 "Main Context",
2254 "The main loop context on "
2255 "which to attach event sources",
2256 G_TYPE_MAIN_CONTEXT,
2257 G_PARAM_READWRITE |
2258 G_PARAM_CONSTRUCT_ONLY |
2259 G_PARAM_STATIC_STRINGS));
2260
2261 g_object_class_install_property (
2262 object_class,
2263 PROP_PARENT,
2264 g_param_spec_string (
2265 "parent",
2266 "Parent",
2267 "The unique identity of the parent data source",
2268 NULL,
2269 G_PARAM_READWRITE |
2270 G_PARAM_EXPLICIT_NOTIFY |
2271 G_PARAM_STATIC_STRINGS |
2272 E_SOURCE_PARAM_SETTING));
2273
2274 g_object_class_install_property (
2275 object_class,
2276 PROP_REMOTE_CREATABLE,
2277 g_param_spec_boolean (
2278 "remote-creatable",
2279 "Remote Creatable",
2280 "Whether the data source "
2281 "can create remote resources",
2282 FALSE,
2283 G_PARAM_READABLE |
2284 G_PARAM_STATIC_STRINGS));
2285
2286 g_object_class_install_property (
2287 object_class,
2288 PROP_REMOTE_DELETABLE,
2289 g_param_spec_boolean (
2290 "remote-deletable",
2291 "Remote Deletable",
2292 "Whether the data source "
2293 "can delete remote resources",
2294 FALSE,
2295 G_PARAM_READABLE |
2296 G_PARAM_STATIC_STRINGS));
2297
2298 g_object_class_install_property (
2299 object_class,
2300 PROP_REMOVABLE,
2301 g_param_spec_boolean (
2302 "removable",
2303 "Removable",
2304 "Whether the data source is removable",
2305 FALSE,
2306 G_PARAM_READABLE |
2307 G_PARAM_STATIC_STRINGS));
2308
2309 g_object_class_install_property (
2310 object_class,
2311 PROP_UID,
2312 g_param_spec_string (
2313 "uid",
2314 "UID",
2315 "The unique identity of the data source",
2316 NULL,
2317 G_PARAM_READWRITE |
2318 G_PARAM_CONSTRUCT_ONLY |
2319 G_PARAM_STATIC_STRINGS));
2320
2321 g_object_class_install_property (
2322 object_class,
2323 PROP_WRITABLE,
2324 g_param_spec_boolean (
2325 "writable",
2326 "Writable",
2327 "Whether the data source is writable",
2328 FALSE,
2329 G_PARAM_READABLE |
2330 G_PARAM_STATIC_STRINGS));
2331
2332 g_object_class_install_property (
2333 object_class,
2334 PROP_CONNECTION_STATUS,
2335 g_param_spec_enum (
2336 "connection-status",
2337 "Connection Status",
2338 "Connection status of the source",
2339 E_TYPE_SOURCE_CONNECTION_STATUS,
2340 E_SOURCE_CONNECTION_STATUS_DISCONNECTED,
2341 G_PARAM_READABLE |
2342 G_PARAM_STATIC_STRINGS));
2343
2344 /**
2345 * ESource::changed:
2346 * @source: the #ESource that received the signal
2347 *
2348 * The ::changed signal is emitted when a property in @source or
2349 * one of its extension objects changes. A common use for this
2350 * signal is to notify a #GtkTreeModel containing data collected
2351 * from #ESource<!-- -->s that it needs to update a row.
2352 **/
2353 signals[CHANGED] = g_signal_new (
2354 "changed",
2355 G_TYPE_FROM_CLASS (class),
2356 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2357 G_STRUCT_OFFSET (ESourceClass, changed),
2358 NULL, NULL, NULL,
2359 G_TYPE_NONE, 0);
2360
2361 /**
2362 * ESource::credentials-required:
2363 * @source: the #ESource that received the signal
2364 * @reason: an #ESourceCredentialsReason indicating why the credentials are requested
2365 * @certificate_pem: PEM-encoded secure connection certificate for failed SSL/TLS checks
2366 * @certificate_errors: what failed with the SSL/TLS certificate
2367 * @error: a text description of the error, if any
2368 *
2369 * The ::credentials-required signal is emitted when the @source
2370 * requires credentials to connect to (possibly remote)
2371 * data store. The credentials can be passed to the backend using
2372 * e_source_invoke_authenticate() function.
2373 **/
2374 signals[CREDENTIALS_REQUIRED] = g_signal_new (
2375 "credentials-required",
2376 G_TYPE_FROM_CLASS (class),
2377 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2378 G_STRUCT_OFFSET (ESourceClass, credentials_required),
2379 NULL, NULL, NULL,
2380 G_TYPE_NONE, 4,
2381 E_TYPE_SOURCE_CREDENTIALS_REASON,
2382 G_TYPE_STRING,
2383 G_TYPE_TLS_CERTIFICATE_FLAGS,
2384 G_TYPE_ERROR);
2385
2386 /**
2387 * ESource::authenticate
2388 * @source: the #ESource that received the signal
2389 * @credentials: an #ENamedParameters with provided credentials
2390 *
2391 * Let's the backend know provided credentials to use to login
2392 * to (possibly remote) data store.
2393 **/
2394 signals[AUTHENTICATE] = g_signal_new (
2395 "authenticate",
2396 G_TYPE_FROM_CLASS (class),
2397 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2398 G_STRUCT_OFFSET (ESourceClass, authenticate),
2399 NULL, NULL, NULL,
2400 G_TYPE_NONE, 1, E_TYPE_NAMED_PARAMETERS);
2401
2402 /* Register built-in ESourceExtension types. */
2403 g_type_ensure (E_TYPE_SOURCE_ADDRESS_BOOK);
2404 g_type_ensure (E_TYPE_SOURCE_ALARMS);
2405 g_type_ensure (E_TYPE_SOURCE_AUTHENTICATION);
2406 g_type_ensure (E_TYPE_SOURCE_AUTOCOMPLETE);
2407 g_type_ensure (E_TYPE_SOURCE_AUTOCONFIG);
2408 g_type_ensure (E_TYPE_SOURCE_CALENDAR);
2409 g_type_ensure (E_TYPE_SOURCE_COLLECTION);
2410 g_type_ensure (E_TYPE_SOURCE_CONTACTS);
2411 g_type_ensure (E_TYPE_SOURCE_GOA);
2412 g_type_ensure (E_TYPE_SOURCE_LDAP);
2413 g_type_ensure (E_TYPE_SOURCE_LOCAL);
2414 g_type_ensure (E_TYPE_SOURCE_MAIL_ACCOUNT);
2415 g_type_ensure (E_TYPE_SOURCE_MAIL_COMPOSITION);
2416 g_type_ensure (E_TYPE_SOURCE_MAIL_IDENTITY);
2417 g_type_ensure (E_TYPE_SOURCE_MAIL_SIGNATURE);
2418 g_type_ensure (E_TYPE_SOURCE_MAIL_SUBMISSION);
2419 g_type_ensure (E_TYPE_SOURCE_MAIL_TRANSPORT);
2420 g_type_ensure (E_TYPE_SOURCE_MDN);
2421 g_type_ensure (E_TYPE_SOURCE_MEMO_LIST);
2422 g_type_ensure (E_TYPE_SOURCE_OFFLINE);
2423 g_type_ensure (E_TYPE_SOURCE_OPENPGP);
2424 g_type_ensure (E_TYPE_SOURCE_PROXY);
2425 g_type_ensure (E_TYPE_SOURCE_REFRESH);
2426 g_type_ensure (E_TYPE_SOURCE_RESOURCE);
2427 g_type_ensure (E_TYPE_SOURCE_REVISION_GUARDS);
2428 g_type_ensure (E_TYPE_SOURCE_SECURITY);
2429 g_type_ensure (E_TYPE_SOURCE_SELECTABLE);
2430 g_type_ensure (E_TYPE_SOURCE_SMIME);
2431 g_type_ensure (E_TYPE_SOURCE_TASK_LIST);
2432 g_type_ensure (E_TYPE_SOURCE_UOA);
2433 g_type_ensure (E_TYPE_SOURCE_WEATHER);
2434 g_type_ensure (E_TYPE_SOURCE_WEBDAV);
2435 }
2436
2437 static void
e_source_initable_init(GInitableIface * iface)2438 e_source_initable_init (GInitableIface *iface)
2439 {
2440 iface->init = source_initable_init;
2441 }
2442
2443 static void
e_source_proxy_resolver_init(GProxyResolverInterface * iface)2444 e_source_proxy_resolver_init (GProxyResolverInterface *iface)
2445 {
2446 iface->is_supported = source_proxy_resolver_is_supported;
2447 iface->lookup = source_proxy_resolver_lookup;
2448 iface->lookup_async = source_proxy_resolver_lookup_async;
2449 iface->lookup_finish = source_proxy_resolver_lookup_finish;
2450 }
2451
2452 static void
e_source_init(ESource * source)2453 e_source_init (ESource *source)
2454 {
2455 GHashTable *extensions;
2456
2457 /* Don't do this as part of class initialization because it
2458 * loads Camel modules and can screw up introspection, which
2459 * occurs at compile-time before Camel modules are installed. */
2460 e_source_camel_register_types ();
2461
2462 extensions = g_hash_table_new_full (
2463 (GHashFunc) g_str_hash,
2464 (GEqualFunc) g_str_equal,
2465 (GDestroyNotify) g_free,
2466 (GDestroyNotify) g_object_unref);
2467
2468 source->priv = e_source_get_instance_private (source);
2469 g_mutex_init (&source->priv->changed_lock);
2470 g_mutex_init (&source->priv->connection_status_change_lock);
2471 g_mutex_init (&source->priv->property_lock);
2472 source->priv->key_file = g_key_file_new ();
2473 source->priv->extensions = extensions;
2474 source->priv->connection_status = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
2475
2476 g_rec_mutex_init (&source->priv->lock);
2477 }
2478
2479 void
__e_source_private_replace_dbus_object(ESource * source,GDBusObject * dbus_object)2480 __e_source_private_replace_dbus_object (ESource *source,
2481 GDBusObject *dbus_object)
2482 {
2483 /* XXX This function is only ever called by ESourceRegistry
2484 * either when the registry service reported an ESource
2485 * removal, or while recovering from a registry service
2486 * restart. In the first case the GDBusObject is NULL,
2487 * in the second case the GDBusObject is an equivalent
2488 * proxy for the newly-started registry service. */
2489
2490 g_return_if_fail (E_IS_SOURCE (source));
2491
2492 if (dbus_object != NULL) {
2493 g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
2494 dbus_object = g_object_ref (dbus_object);
2495 }
2496
2497 g_mutex_lock (&source->priv->property_lock);
2498
2499 if (source->priv->dbus_object) {
2500 EDBusSource *dbus_source;
2501
2502 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (source->priv->dbus_object));
2503
2504 if (dbus_source) {
2505 g_signal_handlers_disconnect_by_data (dbus_source, source),
2506 g_object_unref (dbus_source);
2507 }
2508 }
2509
2510 g_clear_object (&source->priv->dbus_object);
2511 source->priv->dbus_object = dbus_object;
2512
2513 g_mutex_unlock (&source->priv->property_lock);
2514
2515 source_connect_dbus_source (source);
2516 source_update_connection_status (source);
2517
2518 g_object_notify (G_OBJECT (source), "dbus-object");
2519 }
2520
2521 /**
2522 * e_source_new:
2523 * @dbus_object: (nullable): a #GDBusObject or %NULL
2524 * @main_context: (nullable): a #GMainContext or %NULL
2525 * @error: return location for a #GError, or %NULL
2526 *
2527 * Creates a new #ESource instance.
2528 *
2529 * The #ESource::changed signal will be emitted from @main_context if given,
2530 * or else from the thread-default #GMainContext at the time this function is
2531 * called.
2532 *
2533 * The only time the function should be called outside of #ESourceRegistry
2534 * is to create a so-called "scratch" #ESource for editing in a Properties
2535 * window or an account setup assistant.
2536 *
2537 * FIXME: Elaborate on scratch sources.
2538 *
2539 * Returns: a new #ESource, or %NULL on error
2540 *
2541 * Since: 3.6
2542 **/
2543 ESource *
e_source_new(GDBusObject * dbus_object,GMainContext * main_context,GError ** error)2544 e_source_new (GDBusObject *dbus_object,
2545 GMainContext *main_context,
2546 GError **error)
2547 {
2548 if (dbus_object != NULL)
2549 g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), NULL);
2550
2551 return g_initable_new (
2552 E_TYPE_SOURCE, NULL, error,
2553 "dbus-object", dbus_object,
2554 "main-context", main_context,
2555 NULL);
2556 }
2557
2558 /**
2559 * e_source_new_with_uid:
2560 * @uid: a new unique identifier string
2561 * @main_context: (nullable): a #GMainContext or %NULL
2562 * @error: return location for a #GError, or %NULL
2563 *
2564 * Creates a new "scratch" #ESource with a predetermined unique identifier.
2565 *
2566 * The #ESource::changed signal will be emitted from @main_context if given,
2567 * or else from the thread-default #GMainContext at the time this function is
2568 * called.
2569 *
2570 * Returns: a new scratch #ESource, or %NULL on error
2571 *
2572 * Since: 3.6
2573 **/
2574 ESource *
e_source_new_with_uid(const gchar * uid,GMainContext * main_context,GError ** error)2575 e_source_new_with_uid (const gchar *uid,
2576 GMainContext *main_context,
2577 GError **error)
2578 {
2579 g_return_val_if_fail (uid != NULL, NULL);
2580
2581 return g_initable_new (
2582 E_TYPE_SOURCE, NULL, error,
2583 "main-context", main_context,
2584 "uid", uid, NULL);
2585 }
2586
2587 /**
2588 * e_source_hash:
2589 * @source: an #ESource
2590 *
2591 * Generates a hash value for @source. This function is intended for
2592 * easily hashing an #ESource to add to a #GHashTable or similar data
2593 * structure.
2594 *
2595 * Returns: a hash value for @source.
2596 *
2597 * Since: 3.6
2598 **/
2599 guint
e_source_hash(ESource * source)2600 e_source_hash (ESource *source)
2601 {
2602 const gchar *uid;
2603
2604 g_return_val_if_fail (E_IS_SOURCE (source), 0);
2605
2606 uid = e_source_get_uid (source);
2607
2608 return g_str_hash (uid);
2609 }
2610
2611 /**
2612 * e_source_equal:
2613 * @source1: the first #ESource
2614 * @source2: the second #ESource
2615 *
2616 * Checks two #ESource instances for equality. #ESource instances are
2617 * equal if their unique identifier strings are equal.
2618 *
2619 * Returns: %TRUE if @source1 and @source2 are equal
2620 *
2621 * Since: 3.6
2622 **/
2623 gboolean
e_source_equal(ESource * source1,ESource * source2)2624 e_source_equal (ESource *source1,
2625 ESource *source2)
2626 {
2627 const gchar *uid1, *uid2;
2628
2629 g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
2630 g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
2631
2632 if (source1 == source2)
2633 return TRUE;
2634
2635 uid1 = e_source_get_uid (source1);
2636 uid2 = e_source_get_uid (source2);
2637
2638 return g_str_equal (uid1, uid2);
2639 }
2640
2641 /**
2642 * e_source_changed:
2643 * @source: an #ESource
2644 *
2645 * Emits the #ESource::changed signal from an idle callback in
2646 * @source's #ESource:main-context.
2647 *
2648 * This function is primarily intended for use by #ESourceExtension
2649 * when emitting a #GObject::notify signal on one of its properties.
2650 *
2651 * Since: 3.6
2652 **/
2653 void
e_source_changed(ESource * source)2654 e_source_changed (ESource *source)
2655 {
2656 g_return_if_fail (E_IS_SOURCE (source));
2657
2658 g_mutex_lock (&source->priv->changed_lock);
2659 if (!source->priv->ignore_changed_signal &&
2660 source->priv->initialized &&
2661 source->priv->changed == NULL) {
2662 source->priv->changed = g_idle_source_new ();
2663 g_source_set_callback (
2664 source->priv->changed,
2665 source_idle_changed_cb,
2666 g_object_ref (source), g_object_unref);
2667 g_source_attach (
2668 source->priv->changed,
2669 source->priv->main_context);
2670 }
2671 g_mutex_unlock (&source->priv->changed_lock);
2672 }
2673
2674 /**
2675 * e_source_get_uid:
2676 * @source: an #ESource
2677 *
2678 * Returns the unique identifier string for @source.
2679 *
2680 * Returns: the UID for @source
2681 *
2682 * Since: 3.6
2683 **/
2684 const gchar *
e_source_get_uid(ESource * source)2685 e_source_get_uid (ESource *source)
2686 {
2687 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2688
2689 return source->priv->uid;
2690 }
2691
2692 /**
2693 * e_source_dup_uid:
2694 * @source: an #ESource
2695 *
2696 * Thread-safe variation of e_source_get_uid().
2697 * Use this function when accessing @source from multiple threads.
2698 *
2699 * The returned string should be freed with g_free() when no longer needed.
2700 *
2701 * Returns: a newly-allocated copy of #ESource:uid
2702 *
2703 * Since: 3.6
2704 **/
2705 gchar *
e_source_dup_uid(ESource * source)2706 e_source_dup_uid (ESource *source)
2707 {
2708 const gchar *protected;
2709 gchar *duplicate;
2710
2711 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2712
2713 /* Perhaps we don't need to lock the mutex since
2714 * this is a read-only property but it can't hurt. */
2715
2716 g_mutex_lock (&source->priv->property_lock);
2717
2718 protected = e_source_get_uid (source);
2719 duplicate = g_strdup (protected);
2720
2721 g_mutex_unlock (&source->priv->property_lock);
2722
2723 return duplicate;
2724 }
2725
2726 /**
2727 * e_source_get_parent:
2728 * @source: an #ESource
2729 *
2730 * Returns the unique identifier string of the parent #ESource.
2731 *
2732 * Returns: (nullable): the UID of the parent #ESource
2733 *
2734 * Since: 3.6
2735 **/
2736 const gchar *
e_source_get_parent(ESource * source)2737 e_source_get_parent (ESource *source)
2738 {
2739 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2740
2741 return source->priv->parent;
2742 }
2743
2744 /**
2745 * e_source_dup_parent:
2746 * @source: an #ESource
2747 *
2748 * Thread-safe variation of e_source_get_parent().
2749 * Use this function when accessing @source from multiple threads.
2750 *
2751 * The returned string should be freed with g_free() when no longer needed.
2752 *
2753 * Returns: (nullable): a newly-allocated copy of #ESource:parent
2754 *
2755 * Since: 3.6
2756 **/
2757 gchar *
e_source_dup_parent(ESource * source)2758 e_source_dup_parent (ESource *source)
2759 {
2760 const gchar *protected;
2761 gchar *duplicate;
2762
2763 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2764
2765 g_mutex_lock (&source->priv->property_lock);
2766
2767 protected = e_source_get_parent (source);
2768 duplicate = g_strdup (protected);
2769
2770 g_mutex_unlock (&source->priv->property_lock);
2771
2772 return duplicate;
2773 }
2774
2775 /**
2776 * e_source_set_parent:
2777 * @source: an #ESource
2778 * @parent: (nullable): the UID of the parent #ESource, or %NULL
2779 *
2780 * Identifies the parent of @source by its unique identifier string.
2781 * This can only be set prior to adding @source to an #ESourceRegistry.
2782 *
2783 * The internal copy of #ESource:parent is automatically stripped of leading
2784 * and trailing whitespace. If the resulting string is empty, %NULL is set
2785 * instead.
2786 *
2787 * Since: 3.6
2788 **/
2789 void
e_source_set_parent(ESource * source,const gchar * parent)2790 e_source_set_parent (ESource *source,
2791 const gchar *parent)
2792 {
2793 g_return_if_fail (E_IS_SOURCE (source));
2794
2795 g_mutex_lock (&source->priv->property_lock);
2796
2797 if (e_util_strcmp0 (source->priv->parent, parent) == 0) {
2798 g_mutex_unlock (&source->priv->property_lock);
2799 return;
2800 }
2801
2802 g_free (source->priv->parent);
2803 source->priv->parent = e_util_strdup_strip (parent);
2804
2805 g_mutex_unlock (&source->priv->property_lock);
2806
2807 g_object_notify (G_OBJECT (source), "parent");
2808 }
2809
2810 /**
2811 * e_source_get_enabled:
2812 * @source: an #ESource
2813 *
2814 * Returns %TRUE if @source is enabled.
2815 *
2816 * An application should try to honor this setting if at all possible,
2817 * even if it does not provide a way to change the setting through its
2818 * user interface. Disabled data sources should generally be hidden.
2819 *
2820 * <note><para>
2821 * This function does not take into account @source's ancestors in the
2822 * #ESource hierarchy, each of which have their own enabled state. If
2823 * any of @source's ancestors are disabled, then @source itself should
2824 * be treated as disabled. Use e_source_registry_check_enabled() to
2825 * easily check for this.
2826 * </para></note>
2827 *
2828 * Returns: whether @source is enabled
2829 *
2830 * Since: 3.6
2831 **/
2832 gboolean
e_source_get_enabled(ESource * source)2833 e_source_get_enabled (ESource *source)
2834 {
2835 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2836
2837 return source->priv->enabled;
2838 }
2839
2840 /**
2841 * e_source_set_enabled:
2842 * @source: an #ESource
2843 * @enabled: whether to enable @source
2844 *
2845 * Enables or disables @source.
2846 *
2847 * An application should try to honor this setting if at all possible,
2848 * even if it does not provide a way to change the setting through its
2849 * user interface. Disabled data sources should generally be hidden.
2850 *
2851 * Since: 3.6
2852 **/
2853 void
e_source_set_enabled(ESource * source,gboolean enabled)2854 e_source_set_enabled (ESource *source,
2855 gboolean enabled)
2856 {
2857 g_return_if_fail (E_IS_SOURCE (source));
2858
2859 if (source->priv->enabled == enabled)
2860 return;
2861
2862 source->priv->enabled = enabled;
2863
2864 g_object_notify (G_OBJECT (source), "enabled");
2865 }
2866
2867 /**
2868 * e_source_get_writable:
2869 * @source: an #ESource
2870 *
2871 * Returns whether the D-Bus service will accept changes to @source.
2872 * If @source is not writable, calls to e_source_write() will fail.
2873 *
2874 * Returns: whether @source is writable
2875 *
2876 * Since: 3.6
2877 **/
2878 gboolean
e_source_get_writable(ESource * source)2879 e_source_get_writable (ESource *source)
2880 {
2881 GDBusObject *dbus_object;
2882 gboolean writable = FALSE;
2883
2884 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2885
2886 dbus_object = e_source_ref_dbus_object (source);
2887 if (dbus_object != NULL) {
2888 EDBusSourceWritable *dbus_interface;
2889
2890 dbus_interface =
2891 e_dbus_object_peek_source_writable (
2892 E_DBUS_OBJECT (dbus_object));
2893 writable = (dbus_interface != NULL);
2894 g_object_unref (dbus_object);
2895 }
2896
2897 return writable;
2898 }
2899
2900 /**
2901 * e_source_get_removable:
2902 * @source: an #ESource
2903 *
2904 * Returns whether the D-Bus service will allow @source to be removed.
2905 * If @source is not writable, calls to e_source_remove() will fail.
2906 *
2907 * Returns: whether @source is removable
2908 *
2909 * Since: 3.6
2910 **/
2911 gboolean
e_source_get_removable(ESource * source)2912 e_source_get_removable (ESource *source)
2913 {
2914 GDBusObject *dbus_object;
2915 gboolean removable = FALSE;
2916
2917 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2918
2919 dbus_object = e_source_ref_dbus_object (source);
2920 if (dbus_object != NULL) {
2921 EDBusSourceRemovable *dbus_interface;
2922
2923 dbus_interface =
2924 e_dbus_object_peek_source_removable (
2925 E_DBUS_OBJECT (dbus_object));
2926 removable = (dbus_interface != NULL);
2927 g_object_unref (dbus_object);
2928 }
2929
2930 return removable;
2931 }
2932
2933 /**
2934 * e_source_get_remote_creatable:
2935 * @source: an #ESource
2936 *
2937 * Returns whether new resources can be created on a remote server by
2938 * calling e_source_remote_create() on @source.
2939 *
2940 * Generally this is only %TRUE if @source has an #ESourceCollection
2941 * extension, which means there is an #ECollectionBackend in the D-Bus
2942 * service that can handle create requests. If @source does not have
2943 * this capability, calls to e_source_remote_create() will fail.
2944 *
2945 * Returns: whether @source can create remote resources
2946 *
2947 * Since: 3.6
2948 **/
2949 gboolean
e_source_get_remote_creatable(ESource * source)2950 e_source_get_remote_creatable (ESource *source)
2951 {
2952 GDBusObject *dbus_object;
2953 gboolean remote_creatable = FALSE;
2954
2955 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2956
2957 dbus_object = e_source_ref_dbus_object (source);
2958 if (dbus_object != NULL) {
2959 EDBusSourceRemoteCreatable *dbus_interface;
2960
2961 dbus_interface =
2962 e_dbus_object_peek_source_remote_creatable (
2963 E_DBUS_OBJECT (dbus_object));
2964 remote_creatable = (dbus_interface != NULL);
2965 g_object_unref (dbus_object);
2966 }
2967
2968 return remote_creatable;
2969 }
2970
2971 /**
2972 * e_source_get_remote_deletable:
2973 * @source: an #ESource
2974 *
2975 * Returns whether the resource represented by @source can be deleted
2976 * from a remote server by calling e_source_remote_delete().
2977 *
2978 * Generally this is only %TRUE if @source is a child of an #ESource
2979 * which has an #ESourceCollection extension, which means there is an
2980 * #ECollectionBackend in the D-Bus service that can handle delete
2981 * requests. If @source does not have this capability, calls to
2982 * e_source_remote_delete() will fail.
2983 *
2984 * Returns: whether @source can delete remote resources
2985 *
2986 * Since: 3.6
2987 **/
2988 gboolean
e_source_get_remote_deletable(ESource * source)2989 e_source_get_remote_deletable (ESource *source)
2990 {
2991 GDBusObject *dbus_object;
2992 gboolean remote_deletable = FALSE;
2993
2994 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2995
2996 dbus_object = e_source_ref_dbus_object (source);
2997 if (dbus_object != NULL) {
2998 EDBusSourceRemoteDeletable *dbus_interface;
2999
3000 dbus_interface =
3001 e_dbus_object_peek_source_remote_deletable (
3002 E_DBUS_OBJECT (dbus_object));
3003 remote_deletable = (dbus_interface != NULL);
3004 g_object_unref (dbus_object);
3005 }
3006
3007 return remote_deletable;
3008 }
3009
3010 /**
3011 * e_source_get_extension:
3012 * @source: an #ESource
3013 * @extension_name: an extension name
3014 *
3015 * Returns an instance of some #ESourceExtension subclass which registered
3016 * itself under @extension_name. If no such instance exists within @source,
3017 * one will be created. It is the caller's responsibility to know which
3018 * subclass is being returned.
3019 *
3020 * If you just want to test for the existence of an extension within @source
3021 * without creating it, use e_source_has_extension().
3022 *
3023 * Extension instances are owned by their #ESource and should not be
3024 * referenced directly. Instead, reference the #ESource instance and
3025 * use this function to fetch the extension instance as needed.
3026 *
3027 * Returns: (type ESourceExtension) (transfer none): an instance of some
3028 * #ESourceExtension subclass
3029 *
3030 * Since: 3.6
3031 **/
3032 gpointer
e_source_get_extension(ESource * source,const gchar * extension_name)3033 e_source_get_extension (ESource *source,
3034 const gchar *extension_name)
3035 {
3036 ESourceExtension *extension;
3037 GHashTable *hash_table;
3038 GTypeClass *class;
3039
3040 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3041 g_return_val_if_fail (extension_name != NULL, NULL);
3042
3043 g_rec_mutex_lock (&source->priv->lock);
3044
3045 /* Check if we already have the extension. */
3046 extension = g_hash_table_lookup (
3047 source->priv->extensions, extension_name);
3048 if (extension != NULL)
3049 goto exit;
3050
3051 /* Find all subclasses of ESourceExtensionClass. */
3052 hash_table = source_find_extension_classes ();
3053 class = g_hash_table_lookup (hash_table, extension_name);
3054
3055 /* Create a new instance of the appropriate GType. */
3056 if (class != NULL) {
3057 g_mutex_lock (&source->priv->changed_lock);
3058 source->priv->ignore_changed_signal++;
3059 g_mutex_unlock (&source->priv->changed_lock);
3060
3061 extension = g_object_new (
3062 G_TYPE_FROM_CLASS (class),
3063 "source", source, NULL);
3064 source_load_from_key_file (
3065 G_OBJECT (extension),
3066 source->priv->key_file,
3067 extension_name);
3068 g_hash_table_insert (
3069 source->priv->extensions,
3070 g_strdup (extension_name), extension);
3071
3072 g_mutex_lock (&source->priv->changed_lock);
3073 source->priv->ignore_changed_signal--;
3074 g_mutex_unlock (&source->priv->changed_lock);
3075 } else {
3076 /* XXX Tie this into a debug setting for ESources. */
3077 #ifdef DEBUG
3078 g_critical (
3079 "No registered GType for ESource "
3080 "extension '%s'", extension_name);
3081 #endif
3082 }
3083
3084 g_hash_table_destroy (hash_table);
3085
3086 exit:
3087 g_rec_mutex_unlock (&source->priv->lock);
3088
3089 return extension;
3090 }
3091
3092 /**
3093 * e_source_has_extension:
3094 * @source: an #ESource
3095 * @extension_name: an extension name
3096 *
3097 * Checks whether @source has an #ESourceExtension with the given name.
3098 *
3099 * Returns: %TRUE if @source has such an extension, %FALSE if not
3100 *
3101 * Since: 3.6
3102 **/
3103 gboolean
e_source_has_extension(ESource * source,const gchar * extension_name)3104 e_source_has_extension (ESource *source,
3105 const gchar *extension_name)
3106 {
3107 ESourceExtension *extension;
3108
3109 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3110 g_return_val_if_fail (extension_name != NULL, FALSE);
3111
3112 g_rec_mutex_lock (&source->priv->lock);
3113
3114 /* Two cases to check for, either one is good enough:
3115 * 1) Our internal GKeyFile has a group named 'extension_name'.
3116 * 2) Our 'extensions' table has an entry for 'extension_name'.
3117 *
3118 * We have to check both data structures in case a new extension
3119 * not present in the GKeyFile was instantiated, but we have not
3120 * yet updated our internal GKeyFile. A common occurrence when
3121 * editing a brand new data source.
3122 *
3123 * When checking the GKeyFile we want to actually fetch the
3124 * extension with e_source_get_extension() to make sure it's
3125 * a registered extension name and not just an arbitrary key
3126 * file group name. */
3127
3128 if (g_key_file_has_group (source->priv->key_file, extension_name)) {
3129 extension = e_source_get_extension (source, extension_name);
3130 } else {
3131 GHashTable *hash_table = source->priv->extensions;
3132 extension = g_hash_table_lookup (hash_table, extension_name);
3133 }
3134
3135 g_rec_mutex_unlock (&source->priv->lock);
3136
3137 return (extension != NULL);
3138 }
3139
3140 /**
3141 * e_source_ref_dbus_object:
3142 * @source: an #ESource
3143 *
3144 * Returns the #GDBusObject that was passed to e_source_new().
3145 *
3146 * The returned #GDBusObject is referenced for thread-safety and must be
3147 * unreferenced with g_object_unref() when finished with it.
3148 *
3149 * Returns: (transfer full) (nullable): the #GDBusObject for @source, or %NULL
3150 *
3151 * Since: 3.6
3152 **/
3153 GDBusObject *
e_source_ref_dbus_object(ESource * source)3154 e_source_ref_dbus_object (ESource *source)
3155 {
3156 GDBusObject *dbus_object = NULL;
3157
3158 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3159
3160 g_mutex_lock (&source->priv->property_lock);
3161
3162 if (source->priv->dbus_object != NULL)
3163 dbus_object = g_object_ref (source->priv->dbus_object);
3164
3165 g_mutex_unlock (&source->priv->property_lock);
3166
3167 return dbus_object;
3168 }
3169
3170 /**
3171 * e_source_ref_main_context:
3172 * @source: an #ESource
3173 *
3174 * Returns the #GMainContext on which event sources for @source are to
3175 * be attached.
3176 *
3177 * The returned #GMainContext is referenced for thread-safety and must be
3178 * unreferenced with g_main_context_unref() when finished with it.
3179 *
3180 * Returns: (transfer full): a #GMainContext
3181 *
3182 * Since: 3.6
3183 **/
3184 GMainContext *
e_source_ref_main_context(ESource * source)3185 e_source_ref_main_context (ESource *source)
3186 {
3187 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3188
3189 return g_main_context_ref (source->priv->main_context);
3190 }
3191
3192 /**
3193 * e_source_get_display_name:
3194 * @source: an #ESource
3195 *
3196 * Returns the display name for @source. Use the display name to
3197 * represent the #ESource in a user interface.
3198 *
3199 * Returns: the display name for @source
3200 *
3201 * Since: 3.6
3202 **/
3203 const gchar *
e_source_get_display_name(ESource * source)3204 e_source_get_display_name (ESource *source)
3205 {
3206 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3207
3208 return source->priv->display_name;
3209 }
3210
3211 /**
3212 * e_source_dup_display_name:
3213 * @source: an #ESource
3214 *
3215 * Thread-safe variation of e_source_get_display_name().
3216 * Use this function when accessing @source from multiple threads.
3217 *
3218 * The returned string should be freed with g_free() when no longer needed.
3219 *
3220 * Returns: a newly-allocated copy of #ESource:display-name
3221 *
3222 * Since: 3.6
3223 **/
3224 gchar *
e_source_dup_display_name(ESource * source)3225 e_source_dup_display_name (ESource *source)
3226 {
3227 const gchar *protected;
3228 gchar *duplicate;
3229
3230 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3231
3232 g_mutex_lock (&source->priv->property_lock);
3233
3234 protected = e_source_get_display_name (source);
3235 duplicate = g_strdup (protected);
3236
3237 g_mutex_unlock (&source->priv->property_lock);
3238
3239 return duplicate;
3240 }
3241
3242 /**
3243 * e_source_set_display_name:
3244 * @source: an #ESource
3245 * @display_name: a display name
3246 *
3247 * Sets the display name for @source. The @display_name argument must be a
3248 * valid UTF-8 string. Use the display name to represent the #ESource in a
3249 * user interface.
3250 *
3251 * The internal copy of @display_name is automatically stripped of leading
3252 * and trailing whitespace.
3253 *
3254 * Since: 3.6
3255 **/
3256 void
e_source_set_display_name(ESource * source,const gchar * display_name)3257 e_source_set_display_name (ESource *source,
3258 const gchar *display_name)
3259 {
3260 g_return_if_fail (E_IS_SOURCE (source));
3261 g_return_if_fail (display_name != NULL);
3262 g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
3263
3264 g_mutex_lock (&source->priv->property_lock);
3265
3266 if (g_strcmp0 (source->priv->display_name, display_name) == 0) {
3267 g_mutex_unlock (&source->priv->property_lock);
3268 return;
3269 }
3270
3271 g_free (source->priv->display_name);
3272 source->priv->display_name = g_strdup (display_name);
3273
3274 /* Strip leading and trailing whitespace. */
3275 g_strstrip (source->priv->display_name);
3276
3277 /* This is used in e_source_compare_by_display_name(). */
3278 g_free (source->priv->collate_key);
3279 source->priv->collate_key = g_utf8_collate_key (display_name, -1);
3280
3281 g_mutex_unlock (&source->priv->property_lock);
3282
3283 g_object_notify (G_OBJECT (source), "display-name");
3284 }
3285
3286 /**
3287 * e_source_dup_secret_label:
3288 * @source: an #ESource
3289 *
3290 * Creates a label string based on @source's #ESource:display-name for use
3291 * with #SecretItem.
3292 *
3293 * Returns: a newly-allocated secret label
3294 *
3295 * Since: 3.12
3296 **/
3297 gchar *
e_source_dup_secret_label(ESource * source)3298 e_source_dup_secret_label (ESource *source)
3299 {
3300 gchar *display_name;
3301 gchar *backend_name = NULL;
3302 const gchar *type = NULL;
3303 const gchar *parent;
3304 GString *secret_label;
3305
3306 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3307
3308 display_name = e_source_dup_display_name (source);
3309
3310 if (display_name == NULL || *display_name == '\0') {
3311 g_free (display_name);
3312 display_name = e_source_dup_uid (source);
3313 }
3314
3315 #define update_backend_name(ext) G_STMT_START { \
3316 ESourceBackend *backend_extension; \
3317 backend_extension = e_source_get_extension (source, ext); \
3318 g_free (backend_name); \
3319 backend_name = e_source_backend_dup_backend_name (backend_extension); \
3320 } G_STMT_END
3321
3322 if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
3323 type = "Addressbook";
3324 update_backend_name (E_SOURCE_EXTENSION_ADDRESS_BOOK);
3325 }
3326
3327 if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
3328 if (!type) {
3329 type = "Calendar";
3330 update_backend_name (E_SOURCE_EXTENSION_CALENDAR);
3331 } else
3332 type = "";
3333 }
3334
3335 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
3336 if (!type) {
3337 type = "Mail Account";
3338 update_backend_name (E_SOURCE_EXTENSION_MAIL_ACCOUNT);
3339 } else
3340 type = "";
3341 }
3342
3343 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
3344 if (!type) {
3345 type = "Mail Transport";
3346 update_backend_name (E_SOURCE_EXTENSION_MAIL_TRANSPORT);
3347 } else
3348 type = "";
3349 }
3350
3351 if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
3352 if (!type) {
3353 type = "Memo List";
3354 update_backend_name (E_SOURCE_EXTENSION_MEMO_LIST);
3355 } else
3356 type = "";
3357 }
3358
3359 if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
3360 if (!type) {
3361 type = "Task List";
3362 update_backend_name (E_SOURCE_EXTENSION_TASK_LIST);
3363 } else
3364 type = "";
3365 }
3366
3367 if (e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION)) {
3368 if (!type) {
3369 type = "Collection";
3370 update_backend_name (E_SOURCE_EXTENSION_COLLECTION);
3371 } else
3372 type = "";
3373 }
3374
3375 if (!type || !*type) {
3376 g_free (backend_name);
3377 backend_name = NULL;
3378 type = NULL;
3379 }
3380
3381 if (backend_name && !*backend_name) {
3382 g_free (backend_name);
3383 backend_name = NULL;
3384 }
3385
3386 secret_label = g_string_new (NULL);
3387
3388 if (type && backend_name)
3389 g_string_append_printf (secret_label, "Evolution Data Source \"%s\" (%s - %s) ", display_name, type, backend_name);
3390 else if (type)
3391 g_string_append_printf (secret_label, "Evolution Data Source \"%s\" (%s)", display_name, type);
3392 else
3393 g_string_append_printf (secret_label, "Evolution Data Source \"%s\"", display_name);
3394
3395 g_free (backend_name);
3396 g_free (display_name);
3397
3398 parent = e_source_get_parent (source);
3399 if (parent && *parent)
3400 g_string_append_printf (secret_label, " of %s", parent);
3401
3402 return g_string_free (secret_label, FALSE);
3403 }
3404
3405 /**
3406 * e_source_compare_by_display_name:
3407 * @source1: the first #ESource
3408 * @source2: the second #ESource
3409 *
3410 * Compares two #ESource instances by their display names. Useful for
3411 * ordering sources in a user interface.
3412 *
3413 * Returns: a negative value if @source1 compares before @source2, zero if
3414 * they compare equal, or a positive value if @source1 compares
3415 * after @source2
3416 *
3417 * Since: 3.6
3418 **/
3419 gint
e_source_compare_by_display_name(ESource * source1,ESource * source2)3420 e_source_compare_by_display_name (ESource *source1,
3421 ESource *source2)
3422 {
3423 gint res;
3424
3425 res = g_strcmp0 (
3426 source1->priv->collate_key,
3427 source2->priv->collate_key);
3428
3429 if (res == 0)
3430 res = g_strcmp0 (source1->priv->uid, source2->priv->uid);
3431
3432 return res;
3433 }
3434
3435 /**
3436 * e_source_to_string:
3437 * @source: an #ESource
3438 * @length: (optional) (out): return location for the length of the returned
3439 * string, or %NULL
3440 *
3441 * Outputs the current contents of @source as a key file string.
3442 * Free the returned string with g_free().
3443 *
3444 * Returns: a newly-allocated string
3445 *
3446 * Since: 3.6
3447 **/
3448 gchar *
e_source_to_string(ESource * source,gsize * length)3449 e_source_to_string (ESource *source,
3450 gsize *length)
3451 {
3452 GHashTableIter iter;
3453 GKeyFile *key_file;
3454 gpointer group_name;
3455 gpointer extension;
3456 gchar *data;
3457
3458 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3459
3460 g_rec_mutex_lock (&source->priv->lock);
3461
3462 key_file = source->priv->key_file;
3463
3464 source_save_to_key_file (
3465 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
3466
3467 g_hash_table_iter_init (&iter, source->priv->extensions);
3468 while (g_hash_table_iter_next (&iter, &group_name, &extension))
3469 source_save_to_key_file (extension, key_file, group_name);
3470
3471 data = g_key_file_to_data (key_file, length, NULL);
3472
3473 g_rec_mutex_unlock (&source->priv->lock);
3474
3475 return data;
3476 }
3477
3478 /**
3479 * e_source_parameter_to_key:
3480 * @param_name: a #GParamSpec name
3481 *
3482 * Converts a #GParamSpec name (e.g. "foo-bar" or "foo_bar")
3483 * to "CamelCase" for use as a #GKeyFile key (e.g. "FooBar").
3484 *
3485 * This function is made public only to aid in account migration.
3486 * Applications should not need to use this.
3487 *
3488 * Since: 3.6
3489 **/
3490 gchar *
e_source_parameter_to_key(const gchar * param_name)3491 e_source_parameter_to_key (const gchar *param_name)
3492 {
3493 gboolean uppercase = TRUE;
3494 gchar *key, *cp;
3495 gint ii;
3496
3497 g_return_val_if_fail (param_name != NULL, NULL);
3498
3499 key = cp = g_malloc0 (strlen (param_name) + 1);
3500
3501 for (ii = 0; param_name[ii] != '\0'; ii++) {
3502 if (g_ascii_isalnum (param_name[ii]) && uppercase) {
3503 *cp++ = g_ascii_toupper (param_name[ii]);
3504 uppercase = FALSE;
3505 } else if (param_name[ii] == '-' || param_name[ii] == '_')
3506 uppercase = TRUE;
3507 else
3508 *cp++ = param_name[ii];
3509 }
3510
3511 return key;
3512 }
3513
3514 /**
3515 * e_source_get_connection_status:
3516 * @source: an #ESource
3517 *
3518 * Obtain current connection status of the @source.
3519 *
3520 * Returns: Current connection status of the @source.
3521 *
3522 * Since: 3.16
3523 **/
3524 ESourceConnectionStatus
e_source_get_connection_status(ESource * source)3525 e_source_get_connection_status (ESource *source)
3526 {
3527 g_return_val_if_fail (E_IS_SOURCE (source), E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
3528
3529 return source->priv->connection_status;
3530 }
3531
3532 /**
3533 * e_source_set_connection_status:
3534 * @source: an #ESource
3535 * @connection_status: one of the #ESourceConnectionStatus
3536 *
3537 * Set's current connection status of the @source.
3538 *
3539 * Since: 3.16
3540 **/
3541 void
e_source_set_connection_status(ESource * source,ESourceConnectionStatus connection_status)3542 e_source_set_connection_status (ESource *source,
3543 ESourceConnectionStatus connection_status)
3544 {
3545 GEnumClass *enum_class;
3546 GEnumValue *enum_value;
3547
3548 g_return_if_fail (E_IS_SOURCE (source));
3549
3550 if (source->priv->connection_status == connection_status)
3551 return;
3552
3553 source->priv->connection_status = connection_status;
3554
3555 enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
3556 enum_value = g_enum_get_value (enum_class, connection_status);
3557
3558 if (enum_value) {
3559 GDBusObject *dbus_object;
3560 EDBusSource *dbus_source;
3561
3562 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
3563 if (dbus_object) {
3564 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
3565 if (dbus_source) {
3566 e_dbus_source_set_connection_status (dbus_source, enum_value->value_nick);
3567 g_object_unref (dbus_source);
3568 }
3569
3570 g_object_unref (dbus_object);
3571 }
3572 } else {
3573 g_warning ("%s: Unknown connection status: %x", G_STRFUNC, connection_status);
3574 }
3575
3576 g_type_class_unref (enum_class);
3577
3578 g_object_notify (G_OBJECT (source), "connection-status");
3579 }
3580
3581 /**
3582 * e_source_remove_sync:
3583 * @source: the #ESource to be removed
3584 * @cancellable: optional #GCancellable object, or %NULL
3585 * @error: return location for a #GError, or %NULL
3586 *
3587 * Requests the D-Bus service to delete the key files for @source and all of
3588 * its descendants and broadcast their removal to all clients. The @source
3589 * must be #ESource:removable.
3590 *
3591 * If an error occurs, the functon will set @error and return %FALSE.
3592 *
3593 * Returns: %TRUE on success, %FALSE on error
3594 *
3595 * Since: 3.6
3596 **/
3597 gboolean
e_source_remove_sync(ESource * source,GCancellable * cancellable,GError ** error)3598 e_source_remove_sync (ESource *source,
3599 GCancellable *cancellable,
3600 GError **error)
3601 {
3602 ESourceClass *class;
3603
3604 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3605
3606 class = E_SOURCE_GET_CLASS (source);
3607 g_return_val_if_fail (class != NULL, FALSE);
3608 g_return_val_if_fail (class->remove_sync != NULL, FALSE);
3609
3610 return class->remove_sync (source, cancellable, error);
3611 }
3612
3613 /**
3614 * e_source_remove:
3615 * @source: the #ESource to be removed
3616 * @cancellable: optional #GCancellable object, or %NULL
3617 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3618 * @user_data: data to pass to the callback function
3619 *
3620 * Asynchronously requests the D-Bus service to delete the key files for
3621 * @source and all of its descendants and broadcast their removal to all
3622 * clients. The @source must be #ESource:removable.
3623 *
3624 * When the operation is finished, @callback will be called. You can then
3625 * call e_source_remove_finish() to get the result of the operation.
3626 *
3627 * Since: 3.6
3628 **/
3629 void
e_source_remove(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3630 e_source_remove (ESource *source,
3631 GCancellable *cancellable,
3632 GAsyncReadyCallback callback,
3633 gpointer user_data)
3634 {
3635 ESourceClass *class;
3636
3637 g_return_if_fail (E_IS_SOURCE (source));
3638
3639 class = E_SOURCE_GET_CLASS (source);
3640 g_return_if_fail (class != NULL);
3641 g_return_if_fail (class->remove != NULL);
3642
3643 class->remove (source, cancellable, callback, user_data);
3644 }
3645
3646 /**
3647 * e_source_remove_finish:
3648 * @source: the #ESource to be removed
3649 * @result: a #GAsyncResult
3650 * @error: return location for a #GError, or %NULL
3651 *
3652 * Finishes the operation started with e_source_remove(). If an
3653 * error occurred, the function will set @error and return %FALSE.
3654 *
3655 * Returns: %TRUE on success, %FALSE of failure
3656 *
3657 * Since: 3.6
3658 **/
3659 gboolean
e_source_remove_finish(ESource * source,GAsyncResult * result,GError ** error)3660 e_source_remove_finish (ESource *source,
3661 GAsyncResult *result,
3662 GError **error)
3663 {
3664 ESourceClass *class;
3665
3666 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3667 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3668
3669 class = E_SOURCE_GET_CLASS (source);
3670 g_return_val_if_fail (class != NULL, FALSE);
3671 g_return_val_if_fail (class->remove_finish != NULL, FALSE);
3672
3673 return class->remove_finish (source, result, error);
3674 }
3675
3676 /**
3677 * e_source_write_sync:
3678 * @source: a writable #ESource
3679 * @cancellable: optional #GCancellable object, or %NULL
3680 * @error: return location for a #GError, or %NULL
3681 *
3682 * Submits the current contents of @source to the D-Bus service to be
3683 * written to disk and broadcast to other clients. The @source must
3684 * be #ESource:writable.
3685 *
3686 * If an error occurs, the functon will set @error and return %FALSE.
3687 *
3688 * Returns: %TRUE on success, %FALSE on error
3689 *
3690 * Since: 3.6
3691 **/
3692 gboolean
e_source_write_sync(ESource * source,GCancellable * cancellable,GError ** error)3693 e_source_write_sync (ESource *source,
3694 GCancellable *cancellable,
3695 GError **error)
3696 {
3697 ESourceClass *class;
3698
3699 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3700
3701 class = E_SOURCE_GET_CLASS (source);
3702 g_return_val_if_fail (class != NULL, FALSE);
3703 g_return_val_if_fail (class->write_sync != NULL, FALSE);
3704
3705 return class->write_sync (source, cancellable, error);
3706 }
3707
3708 /**
3709 * e_source_write:
3710 * @source: a writable #ESource
3711 * @cancellable: optional #GCancellable object, or %NULL
3712 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3713 * @user_data: data to pass to the callback function
3714 *
3715 * Asynchronously submits the current contents of @source to the D-Bus
3716 * service to be written to disk and broadcast to other clients. The
3717 * @source must be #ESource:writable.
3718 *
3719 * When the operation is finished, @callback will be called. You can then
3720 * call e_source_write_finish() to get the result of the operation.
3721 *
3722 * Since: 3.6
3723 **/
3724 void
e_source_write(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3725 e_source_write (ESource *source,
3726 GCancellable *cancellable,
3727 GAsyncReadyCallback callback,
3728 gpointer user_data)
3729 {
3730 ESourceClass *class;
3731
3732 g_return_if_fail (E_IS_SOURCE (source));
3733
3734 class = E_SOURCE_GET_CLASS (source);
3735 g_return_if_fail (class != NULL);
3736 g_return_if_fail (class->write != NULL);
3737
3738 class->write (source, cancellable, callback, user_data);
3739 }
3740
3741 /**
3742 * e_source_write_finish:
3743 * @source: a writable #ESource
3744 * @result: a #GAsyncResult
3745 * @error: return location for a #GError, or %NULL
3746 *
3747 * Finishes the operation started with e_source_write(). If an
3748 * error occurred, the function will set @error and return %FALSE.
3749 *
3750 * Returns: %TRUE on success, %FALSE on error
3751 *
3752 * Since: 3.6
3753 **/
3754 gboolean
e_source_write_finish(ESource * source,GAsyncResult * result,GError ** error)3755 e_source_write_finish (ESource *source,
3756 GAsyncResult *result,
3757 GError **error)
3758 {
3759 ESourceClass *class;
3760
3761 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3762 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3763
3764 class = E_SOURCE_GET_CLASS (source);
3765 g_return_val_if_fail (class != NULL, FALSE);
3766 g_return_val_if_fail (class->write_finish != NULL, FALSE);
3767
3768 return class->write_finish (source, result, error);
3769 }
3770
3771 /**
3772 * e_source_remote_create_sync:
3773 * @source: an #ESource
3774 * @scratch_source: an #ESource describing the resource to create
3775 * @cancellable: optional #GCancellable object, or %NULL
3776 * @error: return location for a #GError, or %NULL
3777 *
3778 * Creates a new remote resource by picking out relevant details from
3779 * @scratch_source. The @scratch_source must be an #ESource with no
3780 * #GDBusObject. The @source must be #ESource:remote-creatable.
3781 *
3782 * The details required to create the resource vary by #ECollectionBackend,
3783 * but in most cases the @scratch_source need only define the resource type
3784 * (address book, calendar, etc.), a display name for the resource, and
3785 * possibly a server-side path or ID for the resource.
3786 *
3787 * If an error occurs, the function will set @error and return %FALSE.
3788 *
3789 * Returns: %TRUE on success, %FALSE on error
3790 *
3791 * Since: 3.6
3792 **/
3793 gboolean
e_source_remote_create_sync(ESource * source,ESource * scratch_source,GCancellable * cancellable,GError ** error)3794 e_source_remote_create_sync (ESource *source,
3795 ESource *scratch_source,
3796 GCancellable *cancellable,
3797 GError **error)
3798 {
3799 ESourceClass *class;
3800
3801 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3802 g_return_val_if_fail (E_IS_SOURCE (scratch_source), FALSE);
3803
3804 class = E_SOURCE_GET_CLASS (source);
3805 g_return_val_if_fail (class != NULL, FALSE);
3806 g_return_val_if_fail (class->remote_create_sync != NULL, FALSE);
3807
3808 return class->remote_create_sync (
3809 source, scratch_source, cancellable, error);
3810 }
3811
3812 /**
3813 * e_source_remote_create:
3814 * @source: an #ESource
3815 * @scratch_source: an #ESource describing the resource to create
3816 * @cancellable: optional #GCancellable object, or %NULL
3817 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3818 * @user_data: data to pass to the callback function
3819 *
3820 * Asynchronously creates a new remote resource by picking out relevant
3821 * details from @scratch_source. The @scratch_source must be an #ESource
3822 * with no #GDBusObject. The @source must be #ESource:remote-creatable.
3823 *
3824 * The details required to create the resource vary by #ECollectionBackend,
3825 * but in most cases the @scratch_source need only define the resource type
3826 * (address book, calendar, etc.), a display name for the resource, and
3827 * possibly a server-side path or ID for the resource.
3828 *
3829 * When the operation is finished, @callback will be called. You can then
3830 * call e_source_remote_create_finish() to get the result of the operation.
3831 *
3832 * Since: 3.6
3833 **/
3834 void
e_source_remote_create(ESource * source,ESource * scratch_source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3835 e_source_remote_create (ESource *source,
3836 ESource *scratch_source,
3837 GCancellable *cancellable,
3838 GAsyncReadyCallback callback,
3839 gpointer user_data)
3840 {
3841 ESourceClass *class;
3842
3843 g_return_if_fail (E_IS_SOURCE (source));
3844 g_return_if_fail (E_IS_SOURCE (scratch_source));
3845
3846 class = E_SOURCE_GET_CLASS (source);
3847 g_return_if_fail (class != NULL);
3848 g_return_if_fail (class->remote_create != NULL);
3849
3850 class->remote_create (
3851 source, scratch_source,
3852 cancellable, callback, user_data);
3853 }
3854
3855 /**
3856 * e_source_remote_create_finish:
3857 * @source: an #ESource
3858 * @result: a #GAsyncResult
3859 * @error: return location for a #GError, or %NULL
3860 *
3861 * Finishes the operation started with e_source_remote_create(). If
3862 * an error occurred, the function will set @error and return %FALSE.
3863 *
3864 * Returns: %TRUE on success, %FALSE on error
3865 *
3866 * Since: 3.6
3867 **/
3868 gboolean
e_source_remote_create_finish(ESource * source,GAsyncResult * result,GError ** error)3869 e_source_remote_create_finish (ESource *source,
3870 GAsyncResult *result,
3871 GError **error)
3872 {
3873 ESourceClass *class;
3874
3875 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3876
3877 class = E_SOURCE_GET_CLASS (source);
3878 g_return_val_if_fail (class != NULL, FALSE);
3879 g_return_val_if_fail (class->remote_create_finish != NULL, FALSE);
3880
3881 return class->remote_create_finish (source, result, error);
3882 }
3883
3884 /**
3885 * e_source_remote_delete_sync:
3886 * @source: an #ESource
3887 * @cancellable: optional #GCancellable object, or %NULL
3888 * @error: return location for a #GError, or %NULL
3889 *
3890 * Deletes the resource represented by @source from a remote server.
3891 * The @source must be #ESource:remote-deletable. This will also delete
3892 * the key file for @source and broadcast its removal to all clients,
3893 * similar to e_source_remove_sync().
3894 *
3895 * If an error occurs, the function will set @error and return %FALSE.
3896 *
3897 * Returns: %TRUE on success, %FALSE on error
3898 *
3899 * Since: 3.6
3900 **/
3901 gboolean
e_source_remote_delete_sync(ESource * source,GCancellable * cancellable,GError ** error)3902 e_source_remote_delete_sync (ESource *source,
3903 GCancellable *cancellable,
3904 GError **error)
3905 {
3906 ESourceClass *class;
3907
3908 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3909
3910 class = E_SOURCE_GET_CLASS (source);
3911 g_return_val_if_fail (class != NULL, FALSE);
3912 g_return_val_if_fail (class->remote_delete_sync != NULL, FALSE);
3913
3914 return class->remote_delete_sync (source, cancellable, error);
3915 }
3916
3917 /**
3918 * e_source_remote_delete:
3919 * @source: an #ESource
3920 * @cancellable: optional #GCancellable object, or %NULL
3921 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3922 * @user_data: data to pass to the callback function
3923 *
3924 * Asynchronously deletes the resource represented by @source from a remote
3925 * server. The @source must be #ESource:remote-deletable. This will also
3926 * delete the key file for @source and broadcast its removal to all clients,
3927 * similar to e_source_remove().
3928 *
3929 * When the operation is finished, @callback will be called. You can then
3930 * call e_source_remote_delete_finish() to get the result of the operation.
3931 *
3932 * Since: 3.6
3933 **/
3934 void
e_source_remote_delete(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3935 e_source_remote_delete (ESource *source,
3936 GCancellable *cancellable,
3937 GAsyncReadyCallback callback,
3938 gpointer user_data)
3939 {
3940 ESourceClass *class;
3941
3942 g_return_if_fail (E_IS_SOURCE (source));
3943
3944 class = E_SOURCE_GET_CLASS (source);
3945 g_return_if_fail (class != NULL);
3946 g_return_if_fail (class->remote_delete != NULL);
3947
3948 class->remote_delete (source, cancellable, callback, user_data);
3949 }
3950
3951 /**
3952 * e_source_remote_delete_finish:
3953 * @source: an #ESource
3954 * @result: a #GAsyncResult
3955 * @error: return location for a #GError, or %NULL
3956 *
3957 * Finishes the operation started with e_source_remote_delete(). If
3958 * an error occurred, the function will set @error and return %FALSE.
3959 *
3960 * Returns: %TRUE on success, %FALSE on error
3961 *
3962 * Since: 3.6
3963 **/
3964 gboolean
e_source_remote_delete_finish(ESource * source,GAsyncResult * result,GError ** error)3965 e_source_remote_delete_finish (ESource *source,
3966 GAsyncResult *result,
3967 GError **error)
3968 {
3969 ESourceClass *class;
3970
3971 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3972
3973 class = E_SOURCE_GET_CLASS (source);
3974 g_return_val_if_fail (class != NULL, FALSE);
3975 g_return_val_if_fail (class->remote_delete_finish != NULL, FALSE);
3976
3977 return class->remote_delete_finish (source, result, error);
3978 }
3979
3980 /**
3981 * e_source_get_oauth2_access_token_sync:
3982 * @source: an #ESource
3983 * @cancellable: optional #GCancellable object, or %NULL
3984 * @out_access_token: (optional) (out): return location for the access token,
3985 * or %NULL
3986 * @out_expires_in: (optional) (out): return location for the token expiry,
3987 * or %NULL
3988 * @error: return location for a #GError, or %NULL
3989 *
3990 * Obtains the OAuth 2.0 access token for @source along with its expiry
3991 * in seconds from the current time (or 0 if unknown).
3992 *
3993 * Free the returned access token with g_free() when finished with it.
3994 * If an error occurs, the function will set @error and return %FALSE.
3995 *
3996 * Returns: %TRUE on success, %FALSE on error
3997 *
3998 * Since: 3.8
3999 **/
4000 gboolean
e_source_get_oauth2_access_token_sync(ESource * source,GCancellable * cancellable,gchar ** out_access_token,gint * out_expires_in,GError ** error)4001 e_source_get_oauth2_access_token_sync (ESource *source,
4002 GCancellable *cancellable,
4003 gchar **out_access_token,
4004 gint *out_expires_in,
4005 GError **error)
4006 {
4007 ESourceClass *class;
4008
4009 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4010
4011 class = E_SOURCE_GET_CLASS (source);
4012 g_return_val_if_fail (class != NULL, FALSE);
4013 g_return_val_if_fail (class->get_oauth2_access_token_sync != NULL, FALSE);
4014
4015 return class->get_oauth2_access_token_sync (
4016 source, cancellable, out_access_token, out_expires_in, error);
4017 }
4018
4019 /**
4020 * e_source_get_oauth2_access_token:
4021 * @source: an #ESource
4022 * @cancellable: optional #GCancellable object, or %NULL
4023 * @callback: a #GAsyncReadyCallback to call when the request
4024 * is satisfied
4025 * @user_data: data to pass to the callback function
4026 *
4027 * Asynchronously obtains the OAuth 2.0 access token for @source along
4028 * with its expiry in seconds from the current time (or 0 if unknown).
4029 *
4030 * When the operation is finished, @callback will be called. You can then
4031 * call e_source_get_oauth2_access_token_finish() to get the result of the
4032 * operation.
4033 *
4034 * Since: 3.8
4035 **/
4036 void
e_source_get_oauth2_access_token(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4037 e_source_get_oauth2_access_token (ESource *source,
4038 GCancellable *cancellable,
4039 GAsyncReadyCallback callback,
4040 gpointer user_data)
4041 {
4042 ESourceClass *class;
4043
4044 g_return_if_fail (E_IS_SOURCE (source));
4045
4046 class = E_SOURCE_GET_CLASS (source);
4047 g_return_if_fail (class != NULL);
4048 g_return_if_fail (class->get_oauth2_access_token != NULL);
4049
4050 return class->get_oauth2_access_token (
4051 source, cancellable, callback, user_data);
4052 }
4053
4054 /**
4055 * e_source_get_oauth2_access_token_finish:
4056 * @source: an #ESource
4057 * @result: a #GAsyncResult
4058 * @out_access_token: (optional) (out): return location for the access token,
4059 * or %NULL
4060 * @out_expires_in: (optional) (out): return location for the token expiry,
4061 * or %NULL
4062 * @error: return location for a #GError, or %NULL
4063 *
4064 * Finishes the operation started with e_source_get_oauth2_access_token().
4065 *
4066 * Free the returned access token with g_free() when finished with it.
4067 * If an error occurred, the function will set @error and return %FALSE.
4068 *
4069 * Returns: %TRUE on success, %FALSE on error
4070 *
4071 * Since: 3.8
4072 **/
4073 gboolean
e_source_get_oauth2_access_token_finish(ESource * source,GAsyncResult * result,gchar ** out_access_token,gint * out_expires_in,GError ** error)4074 e_source_get_oauth2_access_token_finish (ESource *source,
4075 GAsyncResult *result,
4076 gchar **out_access_token,
4077 gint *out_expires_in,
4078 GError **error)
4079 {
4080 ESourceClass *class;
4081
4082 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4083 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
4084
4085 class = E_SOURCE_GET_CLASS (source);
4086 g_return_val_if_fail (class != NULL, FALSE);
4087 g_return_val_if_fail (class->get_oauth2_access_token_finish != NULL, FALSE);
4088
4089 return class->get_oauth2_access_token_finish (
4090 source, result, out_access_token, out_expires_in, error);
4091 }
4092
4093 /**
4094 * e_source_store_password_sync:
4095 * @source: an #ESource
4096 * @password: the password to store
4097 * @permanently: store permanently or just for the session
4098 * @cancellable: optional #GCancellable object, or %NULL
4099 * @error: return location for a #GError, or %NULL
4100 *
4101 * Stores a password for @source. This operation does not rely on the
4102 * registry service and therefore works for any #ESource -- registered
4103 * or "scratch".
4104 *
4105 * If @permanently is %TRUE, the password is stored in the default keyring.
4106 * Otherwise the password is stored in the memory-only session keyring. If
4107 * an error occurs, the function sets @error and returns %FALSE.
4108 *
4109 * Returns: %TRUE on success, %FALSE on error
4110 *
4111 * Since: 3.12
4112 **/
4113 gboolean
e_source_store_password_sync(ESource * source,const gchar * password,gboolean permanently,GCancellable * cancellable,GError ** error)4114 e_source_store_password_sync (ESource *source,
4115 const gchar *password,
4116 gboolean permanently,
4117 GCancellable *cancellable,
4118 GError **error)
4119 {
4120 gboolean success;
4121 const gchar *uid;
4122 gchar *label;
4123
4124 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4125 g_return_val_if_fail (password != NULL, FALSE);
4126
4127 uid = e_source_get_uid (source);
4128 label = e_source_dup_secret_label (source);
4129
4130 success = e_secret_store_store_sync (uid, password, label, permanently, cancellable, error);
4131
4132 g_free (label);
4133
4134 return success;
4135 }
4136
4137 /* Helper for e_source_store_password() */
4138 static void
source_store_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4139 source_store_password_thread (GTask *task,
4140 gpointer source_object,
4141 gpointer task_data,
4142 GCancellable *cancellable)
4143 {
4144 gboolean success;
4145 AsyncContext *async_context;
4146 GError *local_error = NULL;
4147
4148 async_context = (AsyncContext *) task_data;
4149
4150 success = e_source_store_password_sync (
4151 E_SOURCE (source_object),
4152 async_context->password,
4153 async_context->permanently,
4154 cancellable, &local_error);
4155
4156 if (local_error != NULL) {
4157 g_task_return_error (task, local_error);
4158 } else {
4159 g_task_return_boolean (task, success);
4160 }
4161 }
4162
4163 /**
4164 * e_source_store_password:
4165 * @source: an #ESource
4166 * @password: the password to store
4167 * @permanently: store permanently or just for the session
4168 * @cancellable: optional #GCancellable object, or %NULL
4169 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4170 * @user_data: data to pass to the callback function
4171 *
4172 * Asynchronously stores a password for @source. This operation does
4173 * not rely on the registry service and therefore works for any #ESource
4174 * -- registered or "scratch".
4175 *
4176 * If @permanently is %TRUE, the password is stored in the default keyring.
4177 * Otherwise the password is stored in the memory-only session keyring. If
4178 * an error occurs, the function sets @error and returns %FALSE.
4179 *
4180 * When the operation is finished, @callback will be called. You can then
4181 * call e_source_store_password_finish() to get the result of the operation.
4182 *
4183 * Since: 3.12
4184 **/
4185 void
e_source_store_password(ESource * source,const gchar * password,gboolean permanently,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4186 e_source_store_password (ESource *source,
4187 const gchar *password,
4188 gboolean permanently,
4189 GCancellable *cancellable,
4190 GAsyncReadyCallback callback,
4191 gpointer user_data)
4192 {
4193 GTask *task;
4194 AsyncContext *async_context;
4195
4196 g_return_if_fail (E_IS_SOURCE (source));
4197 g_return_if_fail (password != NULL);
4198
4199 async_context = g_slice_new0 (AsyncContext);
4200 async_context->password = g_strdup (password);
4201 async_context->permanently = permanently;
4202
4203 task = g_task_new (source, cancellable, callback, user_data);
4204 g_task_set_source_tag (task, e_source_store_password);
4205
4206 g_task_set_task_data (
4207 task, async_context,
4208 (GDestroyNotify) async_context_free);
4209
4210 g_task_run_in_thread (task, source_store_password_thread);
4211
4212 g_object_unref (task);
4213 }
4214
4215 /**
4216 * e_source_store_password_finish:
4217 * @source: an #ESource
4218 * @result: a #GAsyncResult
4219 * @error: return location for a #GError, or %NULL
4220 *
4221 * Finishes the operation started with e_source_store_password().
4222 *
4223 * Returns: %TRUE on success, %FALSE on error
4224 *
4225 * Since: 3.12
4226 **/
4227 gboolean
e_source_store_password_finish(ESource * source,GAsyncResult * result,GError ** error)4228 e_source_store_password_finish (ESource *source,
4229 GAsyncResult *result,
4230 GError **error)
4231 {
4232 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4233 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4234
4235 g_return_val_if_fail (
4236 g_async_result_is_tagged (
4237 result, e_source_store_password), FALSE);
4238
4239 return g_task_propagate_boolean (G_TASK (result), error);
4240 }
4241
4242 /**
4243 * e_source_lookup_password_sync:
4244 * @source: an #ESource
4245 * @cancellable: optional #GCancellable object, or %NULL
4246 * @out_password: (out) (optional) (nullable): return location for the password, or %NULL
4247 * @error: return location for a #GError, or %NULL
4248 *
4249 * Looks up a password for @source. Both the default and session keyrings
4250 * are queried. This operation does not rely on the registry service and
4251 * therefore works for any #ESource -- registered or "scratch".
4252 *
4253 * Note the boolean return value indicates whether the lookup operation
4254 * itself completed successfully, not whether a password was found. If
4255 * no password was found, the function will set @out_password to %NULL
4256 * but still return %TRUE. If an error occurs, the function sets @error
4257 * and returns %FALSE.
4258 *
4259 * Returns: %TRUE on success, %FALSE on error
4260 *
4261 * Since: 3.12
4262 **/
4263 gboolean
e_source_lookup_password_sync(ESource * source,GCancellable * cancellable,gchar ** out_password,GError ** error)4264 e_source_lookup_password_sync (ESource *source,
4265 GCancellable *cancellable,
4266 gchar **out_password,
4267 GError **error)
4268 {
4269 const gchar *uid;
4270
4271 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4272
4273 uid = e_source_get_uid (source);
4274
4275 return e_secret_store_lookup_sync (uid, out_password, cancellable, error);
4276 }
4277
4278 /* Helper for e_source_lookup_password() */
4279 static void
source_lookup_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4280 source_lookup_password_thread (GTask *task,
4281 gpointer source_object,
4282 gpointer task_data,
4283 GCancellable *cancellable)
4284 {
4285 gboolean success;
4286 AsyncContext *async_context;
4287 GError *local_error = NULL;
4288
4289 async_context = (AsyncContext *) task_data;
4290
4291 success = e_source_lookup_password_sync (
4292 E_SOURCE (source_object),
4293 cancellable,
4294 &async_context->password,
4295 &local_error);
4296
4297 if (local_error != NULL) {
4298 g_task_return_error (task, local_error);
4299 } else {
4300 g_task_return_boolean (task, success);
4301 }
4302 }
4303
4304 /**
4305 * e_source_lookup_password:
4306 * @source: an #ESource
4307 * @cancellable: optional #GCancellable object, or %NULL
4308 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4309 * @user_data: data to pass to the callback function
4310 *
4311 * Asynchronously looks up a password for @source. Both the default and
4312 * session keyrings are queried. This operation does not rely on the
4313 * registry service and therefore works for any #ESource -- registered
4314 * or "scratch".
4315 *
4316 * When the operation is finished, @callback will be called. You can then
4317 * call e_source_lookup_password_finish() to get the result of the operation.
4318 *
4319 * Since: 3.12
4320 **/
4321 void
e_source_lookup_password(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4322 e_source_lookup_password (ESource *source,
4323 GCancellable *cancellable,
4324 GAsyncReadyCallback callback,
4325 gpointer user_data)
4326 {
4327 GTask *task;
4328 AsyncContext *async_context;
4329
4330 g_return_if_fail (E_IS_SOURCE (source));
4331
4332 async_context = g_slice_new0 (AsyncContext);
4333
4334 task = g_task_new (source, cancellable, callback, user_data);
4335 g_task_set_source_tag (task, e_source_lookup_password);
4336
4337 g_task_set_task_data (
4338 task, async_context,
4339 (GDestroyNotify) async_context_free);
4340
4341 g_task_run_in_thread (task, source_lookup_password_thread);
4342
4343 g_object_unref (task);
4344 }
4345
4346 /**
4347 * e_source_lookup_password_finish:
4348 * @source: an #ESource
4349 * @result: a #GAsyncResult
4350 * @out_password: (out) (optional) (nullable): return location for the password, or %NULL
4351 * @error: return location for a #GError, or %NULL
4352 *
4353 * Finishes the operation started with e_source_lookup_password().
4354 *
4355 * Note the boolean return value indicates whether the lookup operation
4356 * itself completed successfully, not whether a password was found. If
4357 * no password was found, the function will set @out_password to %NULL
4358 * but still return %TRUE. If an error occurs, the function sets @error
4359 * and returns %FALSE.
4360 *
4361 * Returns: %TRUE on success, %FALSE on error
4362 *
4363 * Since: 3.12
4364 **/
4365 gboolean
e_source_lookup_password_finish(ESource * source,GAsyncResult * result,gchar ** out_password,GError ** error)4366 e_source_lookup_password_finish (ESource *source,
4367 GAsyncResult *result,
4368 gchar **out_password,
4369 GError **error)
4370 {
4371 AsyncContext *async_context;
4372
4373 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4374 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4375
4376 g_return_val_if_fail (
4377 g_async_result_is_tagged (
4378 result, e_source_lookup_password), FALSE);
4379
4380 async_context = g_task_get_task_data (G_TASK (result));
4381
4382 if (!g_task_had_error (G_TASK (result))) {
4383 if (out_password != NULL) {
4384 *out_password = async_context->password;
4385 async_context->password = NULL;
4386 }
4387 }
4388
4389 return g_task_propagate_boolean (G_TASK (result), error);
4390 }
4391
4392 /**
4393 * e_source_delete_password_sync:
4394 * @source: an #ESource
4395 * @cancellable: optional #GCancellable object, or %NULL
4396 * @error: return location for a #GError, or %NULL
4397 *
4398 * Deletes the password for @source from either the default keyring or
4399 * session keyring. This operation does not rely on the registry service
4400 * and therefore works for any #ESource -- registered or "scratch".
4401 *
4402 * Note the boolean return value indicates whether the delete operation
4403 * itself completed successfully, not whether a password was found and
4404 * deleted. If no password was found, the function will still return
4405 * %TRUE. If an error occurs, the function sets @error and returns %FALSE.
4406 *
4407 * Returns: %TRUE on success, %FALSE on error
4408 *
4409 * Since: 3.12
4410 **/
4411 gboolean
e_source_delete_password_sync(ESource * source,GCancellable * cancellable,GError ** error)4412 e_source_delete_password_sync (ESource *source,
4413 GCancellable *cancellable,
4414 GError **error)
4415 {
4416 const gchar *uid;
4417
4418 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4419
4420 uid = e_source_get_uid (source);
4421
4422 return e_secret_store_delete_sync (uid, cancellable, error);
4423 }
4424
4425 /* Helper for e_source_delete_password() */
4426 static void
source_delete_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4427 source_delete_password_thread (GTask *task,
4428 gpointer source_object,
4429 gpointer task_data,
4430 GCancellable *cancellable)
4431 {
4432 gboolean success;
4433 GError *local_error = NULL;
4434
4435 success = e_source_delete_password_sync (
4436 E_SOURCE (source_object),
4437 cancellable, &local_error);
4438
4439 if (local_error != NULL) {
4440 g_task_return_error (task, local_error);
4441 } else {
4442 g_task_return_boolean (task, success);
4443 }
4444 }
4445
4446 /**
4447 * e_source_delete_password:
4448 * @source: an #ESource
4449 * @cancellable: optional #GCancellable object, or %NULL
4450 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4451 * @user_data: data to pass to the callback function
4452 *
4453 * Asynchronously deletes the password for @source from either the default
4454 * keyring or session keyring. This operation does not rely on the registry
4455 * service and therefore works for any #ESource -- registered or "scratch".
4456 *
4457 * When the operation is finished, @callback will be called. You can then
4458 * call e_source_delete_password_finish() to get the result of the operation.
4459 *
4460 * Since: 3.12
4461 **/
4462 void
e_source_delete_password(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4463 e_source_delete_password (ESource *source,
4464 GCancellable *cancellable,
4465 GAsyncReadyCallback callback,
4466 gpointer user_data)
4467 {
4468 GTask *task;
4469
4470 g_return_if_fail (E_IS_SOURCE (source));
4471
4472 task = g_task_new (source, cancellable, callback, user_data);
4473 g_task_set_source_tag (task, e_source_delete_password);
4474
4475 g_task_run_in_thread (task, source_delete_password_thread);
4476
4477 g_object_unref (task);
4478 }
4479
4480 /**
4481 * e_source_delete_password_finish:
4482 * @source: an #ESource
4483 * @result: a #GAsyncResult
4484 * @error: return location for a #GError, or %NULL
4485 *
4486 * Finishes the operation started with e_source_delete_password().
4487 *
4488 * Note the boolean return value indicates whether the delete operation
4489 * itself completed successfully, not whether a password was found and
4490 * deleted. If no password was found, the function will still return
4491 * %TRUE. If an error occurs, the function sets @error and returns %FALSE.
4492 *
4493 * Returns: %TRUE on success, %FALSE on error
4494 *
4495 * Since: 3.12
4496 **/
4497 gboolean
e_source_delete_password_finish(ESource * source,GAsyncResult * result,GError ** error)4498 e_source_delete_password_finish (ESource *source,
4499 GAsyncResult *result,
4500 GError **error)
4501 {
4502 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4503 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4504
4505 g_return_val_if_fail (
4506 g_async_result_is_tagged (
4507 result, e_source_delete_password), FALSE);
4508
4509 return g_task_propagate_boolean (G_TASK (result), error);
4510 }
4511
4512 /**
4513 * e_source_invoke_credentials_required_sync:
4514 * @source: an #ESource
4515 * @reason: an #ESourceCredentialsReason, why the credentials are required
4516 * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4517 * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4518 * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4519 * @cancellable: optional #GCancellable object, or %NULL
4520 * @error: return location for a #GError, or %NULL
4521 *
4522 * Let's the client-side know that credentials are required. The @reason defines which
4523 * parameters are used. The client passed the credentials with an e_source_invoke_authenticate()
4524 * call.
4525 *
4526 * The %E_SOURCE_CREDENTIALS_REASON_REQUIRED is used for the first credentials prompt,
4527 * when the client can return credentials as stored from the previous success login.
4528 *
4529 * The %E_SOURCE_CREDENTIALS_REASON_REJECTED is used when the previously used credentials
4530 * had been rejected by the server. That usually means that the user should be asked
4531 * to provide/correct the credentials.
4532 *
4533 * The %E_SOURCE_CREDENTIALS_REASON_SSL_FAILED is used when a secured connection failed
4534 * due to some server-side certificate issues.
4535 *
4536 * The %E_SOURCE_CREDENTIALS_REASON_ERROR is used when the server returned an error.
4537 * It is not possible to connect to it at the moment usually.
4538 *
4539 * If an error occurs, the function sets @error and returns %FALSE.
4540 *
4541 * Returns: %TRUE on success, %FALSE on error
4542 *
4543 * Since: 3.16
4544 **/
4545 gboolean
e_source_invoke_credentials_required_sync(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error,GCancellable * cancellable,GError ** error)4546 e_source_invoke_credentials_required_sync (ESource *source,
4547 ESourceCredentialsReason reason,
4548 const gchar *certificate_pem,
4549 GTlsCertificateFlags certificate_errors,
4550 const GError *op_error,
4551 GCancellable *cancellable,
4552 GError **error)
4553 {
4554 GDBusObject *dbus_object;
4555 EDBusSource *dbus_source = NULL;
4556 ESourceClass *klass;
4557 gchar *arg_reason, *arg_certificate_errors;
4558 GEnumClass *enum_class;
4559 GEnumValue *enum_value;
4560 GFlagsClass *flags_class;
4561 GFlagsValue *flags_value;
4562 GString *certificate_errors_str;
4563 gchar *dbus_error_name = NULL;
4564 GError *local_error = NULL;
4565
4566 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4567
4568 klass = E_SOURCE_GET_CLASS (source);
4569 g_return_val_if_fail (klass != NULL, FALSE);
4570 g_return_val_if_fail (klass->invoke_credentials_required_impl != NULL, FALSE);
4571
4572 dbus_object = e_source_ref_dbus_object (source);
4573 if (dbus_object != NULL) {
4574 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
4575 g_object_unref (dbus_object);
4576 }
4577
4578 if (!dbus_source) {
4579 g_warn_if_fail (dbus_source != NULL);
4580 return FALSE;
4581 }
4582
4583 enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
4584 enum_value = g_enum_get_value (enum_class, reason);
4585
4586 g_return_val_if_fail (enum_value != NULL, FALSE);
4587
4588 arg_reason = g_strdup (enum_value->value_nick);
4589 g_type_class_unref (enum_class);
4590
4591 certificate_errors_str = g_string_new ("");
4592
4593 flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
4594 for (flags_value = g_flags_get_first_value (flags_class, certificate_errors);
4595 flags_value;
4596 flags_value = g_flags_get_first_value (flags_class, certificate_errors)) {
4597 if (certificate_errors_str->len)
4598 g_string_append_c (certificate_errors_str, ':');
4599 g_string_append (certificate_errors_str, flags_value->value_nick);
4600 certificate_errors &= ~flags_value->value;
4601 }
4602 g_type_class_unref (flags_class);
4603
4604 arg_certificate_errors = g_string_free (certificate_errors_str, FALSE);
4605
4606 if (reason == E_SOURCE_CREDENTIALS_REASON_SSL_FAILED)
4607 e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
4608 else if (reason != E_SOURCE_CREDENTIALS_REASON_ERROR)
4609 e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS);
4610
4611 if (op_error)
4612 dbus_error_name = g_dbus_error_encode_gerror (op_error);
4613
4614 klass->invoke_credentials_required_impl (source, dbus_source,
4615 arg_reason ? arg_reason : "",
4616 certificate_pem ? certificate_pem : "",
4617 arg_certificate_errors ? arg_certificate_errors : "",
4618 dbus_error_name ? dbus_error_name : "",
4619 op_error ? op_error->message : "",
4620 cancellable, &local_error);
4621
4622 g_free (arg_reason);
4623 g_free (arg_certificate_errors);
4624 g_free (dbus_error_name);
4625 g_object_unref (dbus_source);
4626
4627 if (local_error != NULL) {
4628 g_dbus_error_strip_remote_error (local_error);
4629 g_propagate_error (error, local_error);
4630 return FALSE;
4631 }
4632
4633 return TRUE;
4634 }
4635
4636 typedef struct _InvokeCredentialsRequiredData {
4637 ESourceCredentialsReason reason;
4638 gchar *certificate_pem;
4639 GTlsCertificateFlags certificate_errors;
4640 GError *op_error;
4641 } InvokeCredentialsRequiredData;
4642
4643 static void
invoke_credentials_required_data_free(gpointer ptr)4644 invoke_credentials_required_data_free (gpointer ptr)
4645 {
4646 InvokeCredentialsRequiredData *data = ptr;
4647
4648 if (data) {
4649 g_free (data->certificate_pem);
4650 g_clear_error (&data->op_error);
4651 g_slice_free (InvokeCredentialsRequiredData, data);
4652 }
4653 }
4654
4655 static void
source_invoke_credentials_required_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4656 source_invoke_credentials_required_thread (GTask *task,
4657 gpointer source_object,
4658 gpointer task_data,
4659 GCancellable *cancellable)
4660 {
4661 InvokeCredentialsRequiredData *data = task_data;
4662 gboolean success;
4663 GError *local_error = NULL;
4664
4665 success = e_source_invoke_credentials_required_sync (
4666 E_SOURCE (source_object), data->reason, data->certificate_pem,
4667 data->certificate_errors, data->op_error,
4668 cancellable, &local_error);
4669
4670 if (local_error != NULL) {
4671 g_task_return_error (task, local_error);
4672 } else {
4673 g_task_return_boolean (task, success);
4674 }
4675 }
4676
4677 /**
4678 * e_source_invoke_credentials_required:
4679 * @source: an #ESource
4680 * @reason: an #ESourceCredentialsReason, why the credentials are required
4681 * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4682 * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4683 * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4684 * @cancellable: optional #GCancellable object, or %NULL
4685 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4686 * @user_data: data to pass to the callback function
4687 *
4688 * Asynchronously calls the InvokeCredentialsRequired method on the server side,
4689 * to inform clients that credentials are required.
4690 *
4691 * When the operation is finished, @callback will be called. You can then
4692 * call e_source_invoke_credentials_required_finish() to get the result of the operation.
4693 *
4694 * Since: 3.16
4695 **/
4696 void
e_source_invoke_credentials_required(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4697 e_source_invoke_credentials_required (ESource *source,
4698 ESourceCredentialsReason reason,
4699 const gchar *certificate_pem,
4700 GTlsCertificateFlags certificate_errors,
4701 const GError *op_error,
4702 GCancellable *cancellable,
4703 GAsyncReadyCallback callback,
4704 gpointer user_data)
4705 {
4706 InvokeCredentialsRequiredData *data;
4707 GTask *task;
4708
4709 g_return_if_fail (E_IS_SOURCE (source));
4710
4711 data = g_slice_new0 (InvokeCredentialsRequiredData);
4712 data->reason = reason;
4713 data->certificate_pem = g_strdup (certificate_pem);
4714 data->certificate_errors = certificate_errors;
4715 data->op_error = op_error ? g_error_copy (op_error) : NULL;
4716
4717 task = g_task_new (source, cancellable, callback, user_data);
4718 g_task_set_source_tag (task, e_source_invoke_credentials_required);
4719 g_task_set_task_data (task, data, invoke_credentials_required_data_free);
4720
4721 g_task_run_in_thread (task, source_invoke_credentials_required_thread);
4722
4723 g_object_unref (task);
4724 }
4725
4726 /**
4727 * e_source_invoke_credentials_required_finish:
4728 * @source: an #ESource
4729 * @result: a #GAsyncResult
4730 * @error: return location for a #GError, or %NULL
4731 *
4732 * Finishes the operation started with e_source_invoke_credentials_required().
4733 *
4734 * If an error occurs, the function sets @error and returns %FALSE.
4735 *
4736 * Returns: %TRUE on success, %FALSE on error
4737 *
4738 * Since: 3.16
4739 **/
4740 gboolean
e_source_invoke_credentials_required_finish(ESource * source,GAsyncResult * result,GError ** error)4741 e_source_invoke_credentials_required_finish (ESource *source,
4742 GAsyncResult *result,
4743 GError **error)
4744 {
4745 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4746 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4747
4748 g_return_val_if_fail (
4749 g_async_result_is_tagged (
4750 result, e_source_invoke_credentials_required), FALSE);
4751
4752 return g_task_propagate_boolean (G_TASK (result), error);
4753 }
4754
4755 /**
4756 * e_source_invoke_authenticate_sync:
4757 * @source: an #ESource
4758 * @credentials: (nullable): an #ENamedParameters structure with credentials to use; can be %NULL
4759 * to use those from the last call
4760 * @cancellable: optional #GCancellable object, or %NULL
4761 * @error: return location for a #GError, or %NULL
4762 *
4763 * Calls the InvokeAuthenticate method on the server side, thus the backend
4764 * knows what credentials to use to connect to its (possibly remote) data store.
4765 *
4766 * If an error occurs, the function sets @error and returns %FALSE.
4767 *
4768 * Returns: %TRUE on success, %FALSE on error
4769 *
4770 * Since: 3.16
4771 **/
4772 gboolean
e_source_invoke_authenticate_sync(ESource * source,const ENamedParameters * credentials,GCancellable * cancellable,GError ** error)4773 e_source_invoke_authenticate_sync (ESource *source,
4774 const ENamedParameters *credentials,
4775 GCancellable *cancellable,
4776 GError **error)
4777 {
4778 GDBusObject *dbus_object;
4779 EDBusSource *dbus_source = NULL;
4780 ESourceClass *klass;
4781 gchar **credentials_strv;
4782 gboolean success;
4783 GError *local_error = NULL;
4784
4785 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4786
4787 klass = E_SOURCE_GET_CLASS (source);
4788 g_return_val_if_fail (klass != NULL, FALSE);
4789 g_return_val_if_fail (klass->invoke_authenticate_impl != NULL, FALSE);
4790
4791 dbus_object = e_source_ref_dbus_object (source);
4792 if (dbus_object != NULL) {
4793 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
4794 g_object_unref (dbus_object);
4795 }
4796
4797 if (!dbus_source) {
4798 g_warn_if_fail (dbus_source != NULL);
4799 return FALSE;
4800 }
4801
4802 if (credentials) {
4803 if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND) &&
4804 !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_SSL_TRUST)) {
4805 ENamedParameters *clone;
4806 ESourceWebdav *webdav_extension;
4807
4808 clone = e_named_parameters_new_clone (credentials);
4809
4810 webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
4811 e_named_parameters_set (clone, E_SOURCE_CREDENTIAL_SSL_TRUST,
4812 e_source_webdav_get_ssl_trust (webdav_extension));
4813
4814 credentials_strv = e_named_parameters_to_strv (clone);
4815
4816 e_named_parameters_free (clone);
4817 } else {
4818 credentials_strv = e_named_parameters_to_strv (credentials);
4819 }
4820 } else {
4821 ENamedParameters *empty_credentials;
4822
4823 empty_credentials = e_named_parameters_new ();
4824 credentials_strv = e_named_parameters_to_strv (empty_credentials);
4825 e_named_parameters_free (empty_credentials);
4826 }
4827
4828 success = klass->invoke_authenticate_impl (source, dbus_source, (const gchar * const *) credentials_strv, cancellable, &local_error);
4829
4830 g_strfreev (credentials_strv);
4831 g_object_unref (dbus_source);
4832
4833 if (local_error != NULL) {
4834 g_dbus_error_strip_remote_error (local_error);
4835 g_propagate_error (error, local_error);
4836 return FALSE;
4837 }
4838
4839 return success;
4840 }
4841
4842 static void
source_invoke_authenticate_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4843 source_invoke_authenticate_thread (GTask *task,
4844 gpointer source_object,
4845 gpointer task_data,
4846 GCancellable *cancellable)
4847 {
4848 gboolean success;
4849 GError *local_error = NULL;
4850
4851 success = e_source_invoke_authenticate_sync (
4852 E_SOURCE (source_object), task_data,
4853 cancellable, &local_error);
4854
4855 if (local_error != NULL) {
4856 g_task_return_error (task, local_error);
4857 } else {
4858 g_task_return_boolean (task, success);
4859 }
4860 }
4861
4862 /**
4863 * e_source_invoke_authenticate:
4864 * @source: an #ESource
4865 * @credentials: (nullable): an #ENamedParameters structure with credentials to use; can be %NULL
4866 * to use those from the last call
4867 * @cancellable: optional #GCancellable object, or %NULL
4868 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4869 * @user_data: data to pass to the callback function
4870 *
4871 * Asynchronously calls the InvokeAuthenticate method on the server side,
4872 * thus the backend knows what credentials to use to connect to its (possibly
4873 * remote) data store.
4874 *
4875 * When the operation is finished, @callback will be called. You can then
4876 * call e_source_invoke_authenticate_finish() to get the result of the operation.
4877 *
4878 * Since: 3.16
4879 **/
4880 void
e_source_invoke_authenticate(ESource * source,const ENamedParameters * credentials,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4881 e_source_invoke_authenticate (ESource *source,
4882 const ENamedParameters *credentials,
4883 GCancellable *cancellable,
4884 GAsyncReadyCallback callback,
4885 gpointer user_data)
4886 {
4887 ENamedParameters *credentials_copy;
4888 GTask *task;
4889
4890 g_return_if_fail (E_IS_SOURCE (source));
4891
4892 credentials_copy = e_named_parameters_new_clone (credentials);
4893
4894 task = g_task_new (source, cancellable, callback, user_data);
4895 g_task_set_source_tag (task, e_source_invoke_authenticate);
4896 g_task_set_task_data (task, credentials_copy, (GDestroyNotify) e_named_parameters_free);
4897
4898 g_task_run_in_thread (task, source_invoke_authenticate_thread);
4899
4900 g_object_unref (task);
4901 }
4902
4903 /**
4904 * e_source_invoke_authenticate_finish:
4905 * @source: an #ESource
4906 * @result: a #GAsyncResult
4907 * @error: return location for a #GError, or %NULL
4908 *
4909 * Finishes the operation started with e_source_invoke_authenticate().
4910 *
4911 * If an error occurs, the function sets @error and returns %FALSE.
4912 *
4913 * Returns: %TRUE on success, %FALSE on error
4914 *
4915 * Since: 3.16
4916 **/
4917 gboolean
e_source_invoke_authenticate_finish(ESource * source,GAsyncResult * result,GError ** error)4918 e_source_invoke_authenticate_finish (ESource *source,
4919 GAsyncResult *result,
4920 GError **error)
4921 {
4922 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4923 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4924
4925 g_return_val_if_fail (
4926 g_async_result_is_tagged (
4927 result, e_source_invoke_authenticate), FALSE);
4928
4929 return g_task_propagate_boolean (G_TASK (result), error);
4930 }
4931
4932 /**
4933 * e_source_emit_credentials_required:
4934 * @source: an #ESource
4935 * @reason: an #ESourceCredentialsReason, why the credentials are required
4936 * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4937 * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4938 * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4939 *
4940 * Emits localy (in this process only) the ESource::credentials-required
4941 * signal with given parameters. That's the difference with e_source_invoke_credentials_required(),
4942 * which calls the signal globally, within each client.
4943 *
4944 * Since: 3.16
4945 **/
4946 void
e_source_emit_credentials_required(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error)4947 e_source_emit_credentials_required (ESource *source,
4948 ESourceCredentialsReason reason,
4949 const gchar *certificate_pem,
4950 GTlsCertificateFlags certificate_errors,
4951 const GError *op_error)
4952 {
4953 g_return_if_fail (E_IS_SOURCE (source));
4954
4955 g_signal_emit (source, signals[CREDENTIALS_REQUIRED], 0, reason, certificate_pem, certificate_errors, op_error);
4956 }
4957
4958 /**
4959 * e_source_get_last_credentials_required_arguments_sync:
4960 * @source: an #ESource
4961 * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
4962 * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
4963 * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
4964 * @out_op_error: (out): a #GError with a description of the previous credentials error
4965 * @cancellable: optional #GCancellable object, or %NULL
4966 * @error: return location for a #GError, or %NULL
4967 *
4968 * Retrieves the last used arguments of the 'credentials-required' signal emission.
4969 * If there was none emitted yet, or a corresponding 'authenitcate' had been emitted
4970 * already, then the @out_reason is set to #E_SOURCE_CREDENTIALS_REASON_UNKNOWN
4971 * and the value of other 'out' arguments is set to no values.
4972 *
4973 * If an error occurs, the function sets @error and returns %FALSE. The result gchar
4974 * values should be freed with g_free() when no longer needed.
4975 *
4976 * Returns: %TRUE on success, %FALSE on error
4977 *
4978 * Since: 3.16
4979 **/
4980 gboolean
e_source_get_last_credentials_required_arguments_sync(ESource * source,ESourceCredentialsReason * out_reason,gchar ** out_certificate_pem,GTlsCertificateFlags * out_certificate_errors,GError ** out_op_error,GCancellable * cancellable,GError ** error)4981 e_source_get_last_credentials_required_arguments_sync (ESource *source,
4982 ESourceCredentialsReason *out_reason,
4983 gchar **out_certificate_pem,
4984 GTlsCertificateFlags *out_certificate_errors,
4985 GError **out_op_error,
4986 GCancellable *cancellable,
4987 GError **error)
4988 {
4989 GDBusObject *dbus_object;
4990 EDBusSource *dbus_source = NULL;
4991 gboolean success;
4992 gchar *arg_reason = NULL, *arg_certificate_errors = NULL;
4993 gchar *arg_dbus_error_name = NULL, *arg_dbus_error_message = NULL;
4994 GError *local_error = NULL;
4995
4996 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4997 g_return_val_if_fail (out_reason != NULL, FALSE);
4998 g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
4999 g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
5000 g_return_val_if_fail (out_op_error != NULL, FALSE);
5001
5002 *out_reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
5003 *out_certificate_pem = NULL;
5004 *out_certificate_errors = 0;
5005 *out_op_error = NULL;
5006
5007 dbus_object = e_source_ref_dbus_object (source);
5008 if (dbus_object != NULL) {
5009 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
5010 g_object_unref (dbus_object);
5011 }
5012
5013 if (!dbus_source)
5014 return FALSE;
5015
5016 success = e_dbus_source_call_get_last_credentials_required_arguments_sync (dbus_source,
5017 &arg_reason, out_certificate_pem, &arg_certificate_errors,
5018 &arg_dbus_error_name, &arg_dbus_error_message, cancellable, &local_error);
5019
5020 g_object_unref (dbus_source);
5021
5022 *out_reason = source_credentials_reason_from_text (arg_reason);
5023 *out_certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
5024
5025 if (arg_dbus_error_name && *arg_dbus_error_name && arg_dbus_error_message) {
5026 *out_op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
5027 g_dbus_error_strip_remote_error (*out_op_error);
5028 }
5029
5030 if (*out_certificate_pem && !**out_certificate_pem) {
5031 g_free (*out_certificate_pem);
5032 *out_certificate_pem = NULL;
5033 }
5034
5035 g_free (arg_reason);
5036 g_free (arg_certificate_errors);
5037 g_free (arg_dbus_error_name);
5038 g_free (arg_dbus_error_message);
5039
5040 if (local_error != NULL) {
5041 g_dbus_error_strip_remote_error (local_error);
5042 g_propagate_error (error, local_error);
5043 return FALSE;
5044 }
5045
5046 return success;
5047 }
5048
5049 static void
source_get_last_credentials_required_arguments_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)5050 source_get_last_credentials_required_arguments_thread (GTask *task,
5051 gpointer source_object,
5052 gpointer task_data,
5053 GCancellable *cancellable)
5054 {
5055 InvokeCredentialsRequiredData *data;
5056 GError *local_error = NULL;
5057
5058 data = g_slice_new0 (InvokeCredentialsRequiredData);
5059 data->reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
5060 data->certificate_pem = NULL;
5061 data->certificate_errors = 0;
5062 data->op_error = NULL;
5063
5064 e_source_get_last_credentials_required_arguments_sync (
5065 E_SOURCE (source_object), &data->reason, &data->certificate_pem,
5066 &data->certificate_errors, &data->op_error,
5067 cancellable, &local_error);
5068
5069 if (local_error != NULL) {
5070 g_task_return_error (task, local_error);
5071 invoke_credentials_required_data_free (data);
5072 } else {
5073 g_task_return_pointer (task, data, invoke_credentials_required_data_free);
5074 }
5075 }
5076
5077 /**
5078 * e_source_get_last_credentials_required_arguments:
5079 * @source: an #ESource
5080 * @cancellable: optional #GCancellable object, or %NULL
5081 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
5082 * @user_data: data to pass to the callback function
5083 *
5084 * Asynchronously calls the GetLastCredentialsRequiredArguments method
5085 * on the server side, to get the last values used for the 'credentials-required'
5086 * signal. See e_source_get_last_credentials_required_arguments_sync() for
5087 * more information.
5088 *
5089 * When the operation is finished, @callback will be called. You can then
5090 * call e_source_get_last_credentials_required_arguments_finish() to get
5091 * the result of the operation.
5092 *
5093 * Since: 3.16
5094 **/
5095 void
e_source_get_last_credentials_required_arguments(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)5096 e_source_get_last_credentials_required_arguments (ESource *source,
5097 GCancellable *cancellable,
5098 GAsyncReadyCallback callback,
5099 gpointer user_data)
5100 {
5101 GTask *task;
5102
5103 g_return_if_fail (E_IS_SOURCE (source));
5104
5105 task = g_task_new (source, cancellable, callback, user_data);
5106 g_task_set_source_tag (task, e_source_get_last_credentials_required_arguments);
5107
5108 g_task_run_in_thread (task, source_get_last_credentials_required_arguments_thread);
5109
5110 g_object_unref (task);
5111 }
5112
5113 /**
5114 * e_source_get_last_credentials_required_arguments_finish:
5115 * @source: an #ESource
5116 * @result: a #GAsyncResult
5117 * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
5118 * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
5119 * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
5120 * @out_op_error: (out): a #GError with a description of the previous credentials error
5121 * @error: return location for a #GError, or %NULL
5122 *
5123 * Finishes the operation started with e_source_get_last_credentials_required_arguments().
5124 * See e_source_get_last_credentials_required_arguments_sync() for more information
5125 * about the output arguments.
5126 *
5127 * If an error occurs, the function sets @error and returns %FALSE.
5128 *
5129 * Returns: %TRUE on success, %FALSE on error
5130 *
5131 * Since: 3.16
5132 **/
5133 gboolean
e_source_get_last_credentials_required_arguments_finish(ESource * source,GAsyncResult * result,ESourceCredentialsReason * out_reason,gchar ** out_certificate_pem,GTlsCertificateFlags * out_certificate_errors,GError ** out_op_error,GError ** error)5134 e_source_get_last_credentials_required_arguments_finish (ESource *source,
5135 GAsyncResult *result,
5136 ESourceCredentialsReason *out_reason,
5137 gchar **out_certificate_pem,
5138 GTlsCertificateFlags *out_certificate_errors,
5139 GError **out_op_error,
5140 GError **error)
5141 {
5142 InvokeCredentialsRequiredData *data;
5143
5144 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5145 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
5146 g_return_val_if_fail (out_reason != NULL, FALSE);
5147 g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
5148 g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
5149 g_return_val_if_fail (out_op_error != NULL, FALSE);
5150
5151 g_return_val_if_fail (
5152 g_async_result_is_tagged (
5153 result, e_source_get_last_credentials_required_arguments), FALSE);
5154
5155 data = g_task_propagate_pointer (G_TASK (result), error);
5156 if (!data)
5157 return FALSE;
5158
5159 *out_reason = data->reason;
5160 *out_certificate_pem = g_strdup (data->certificate_pem);
5161 *out_certificate_errors = data->certificate_errors;
5162 *out_op_error = data->op_error ? g_error_copy (data->op_error) : NULL;
5163
5164 invoke_credentials_required_data_free (data);
5165
5166 return TRUE;
5167 }
5168
5169 /**
5170 * e_source_unset_last_credentials_required_arguments_sync:
5171 * @source: an #ESource
5172 * @cancellable: optional #GCancellable object, or %NULL
5173 * @error: return location for a #GError, or %NULL
5174 *
5175 * Unsets the last used arguments of the 'credentials-required' signal emission.
5176 *
5177 * If an error occurs, the function sets @error and returns %FALSE.
5178 *
5179 * Returns: %TRUE on success, %FALSE on error
5180 *
5181 * Since: 3.18
5182 **/
5183 gboolean
e_source_unset_last_credentials_required_arguments_sync(ESource * source,GCancellable * cancellable,GError ** error)5184 e_source_unset_last_credentials_required_arguments_sync (ESource *source,
5185 GCancellable *cancellable,
5186 GError **error)
5187 {
5188 ESourceClass *klass;
5189
5190 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5191
5192 klass = E_SOURCE_GET_CLASS (source);
5193 g_return_val_if_fail (klass != NULL, FALSE);
5194 g_return_val_if_fail (klass->unset_last_credentials_required_arguments_impl != NULL, FALSE);
5195
5196 return klass->unset_last_credentials_required_arguments_impl (source, cancellable, error);
5197 }
5198
5199 static void
source_unset_last_credentials_required_arguments_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)5200 source_unset_last_credentials_required_arguments_thread (GTask *task,
5201 gpointer source_object,
5202 gpointer task_data,
5203 GCancellable *cancellable)
5204 {
5205 GError *local_error = NULL;
5206
5207 e_source_unset_last_credentials_required_arguments_sync (
5208 E_SOURCE (source_object), cancellable, &local_error);
5209
5210 if (local_error != NULL) {
5211 g_task_return_error (task, local_error);
5212 } else {
5213 g_task_return_boolean (task, TRUE);
5214 }
5215 }
5216
5217 /**
5218 * e_source_unset_last_credentials_required_arguments:
5219 * @source: an #ESource
5220 * @cancellable: optional #GCancellable object, or %NULL
5221 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
5222 * @user_data: data to pass to the callback function
5223 *
5224 * Asynchronously calls the UnsetLastCredentialsRequiredArguments method
5225 * on the server side, to unset the last values used for the 'credentials-required'
5226 * signal.
5227 *
5228 * When the operation is finished, @callback will be called. You can then
5229 * call e_source_unset_last_credentials_required_arguments_finish() to get
5230 * the result of the operation.
5231 *
5232 * Since: 3.18
5233 **/
5234 void
e_source_unset_last_credentials_required_arguments(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)5235 e_source_unset_last_credentials_required_arguments (ESource *source,
5236 GCancellable *cancellable,
5237 GAsyncReadyCallback callback,
5238 gpointer user_data)
5239 {
5240 GTask *task;
5241
5242 g_return_if_fail (E_IS_SOURCE (source));
5243
5244 task = g_task_new (source, cancellable, callback, user_data);
5245 g_task_set_source_tag (task, e_source_unset_last_credentials_required_arguments);
5246
5247 g_task_run_in_thread (task, source_unset_last_credentials_required_arguments_thread);
5248
5249 g_object_unref (task);
5250 }
5251
5252 /**
5253 * e_source_unset_last_credentials_required_arguments_finish:
5254 * @source: an #ESource
5255 * @result: a #GAsyncResult
5256 * @error: return location for a #GError, or %NULL
5257 *
5258 * Finishes the operation started with e_source_unset_last_credentials_required_arguments().
5259 *
5260 * If an error occurs, the function sets @error and returns %FALSE.
5261 *
5262 * Returns: %TRUE on success, %FALSE on error
5263 *
5264 * Since: 3.18
5265 **/
5266 gboolean
e_source_unset_last_credentials_required_arguments_finish(ESource * source,GAsyncResult * result,GError ** error)5267 e_source_unset_last_credentials_required_arguments_finish (ESource *source,
5268 GAsyncResult *result,
5269 GError **error)
5270 {
5271 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5272 g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
5273
5274 g_return_val_if_fail (
5275 g_async_result_is_tagged (
5276 result, e_source_unset_last_credentials_required_arguments), FALSE);
5277
5278 return g_task_propagate_boolean (G_TASK (result), error);
5279 }
5280