Add e_source_registry_check_enabled().
[platform/upstream/evolution-data-server.git] / libedataserver / e-source-registry.c
1 /*
2  * e-source-registry.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  */
18
19 /**
20  * SECTION: e-source-registry
21  * @include: libedataserver/libedataserver.h
22  * @short_description: A central repository for data sources
23  *
24  * The #ESourceRegistry is a global singleton store for all #ESource
25  * instances.  It uses file monitors to react to key file creation and
26  * deletion events, either constructing an #ESource instance from the
27  * newly created key file, or removing from the logical #ESource
28  * hierarchy the instance corresponding to the deleted key file.
29  *
30  * The #ESourceRegistry can be queried for individual #ESource instances
31  * by their unique identifier string or key file path, for collections of
32  * #ESource instances having a particular extension, or for all available
33  * #ESource instances.
34  *
35  * The #ESourceRegistry API also provides a front-end for the
36  * "org.gnome.Evolution.DefaultSources" #GSettings schema which tracks
37  * which #ESource instances are designated to be the user's default address
38  * book, calendar, memo list and task list for desktop integration.
39  **/
40
41 #include "e-source-registry.h"
42
43 #include <config.h>
44 #include <glib/gstdio.h>
45 #include <glib/gi18n-lib.h>
46
47 /* XXX Yeah, yeah... */
48 #define GCR_API_SUBJECT_TO_CHANGE
49
50 #include <gcr/gcr-base.h>
51
52 /* Private D-Bus classes. */
53 #include <e-dbus-source.h>
54 #include <e-dbus-source-manager.h>
55
56 #include <libedataserver/e-marshal.h>
57 #include <libedataserver/e-data-server-util.h>
58 #include <libedataserver/e-source-collection.h>
59
60 /* Needed for the defaults API. */
61 #include <libedataserver/e-source-address-book.h>
62 #include <libedataserver/e-source-calendar.h>
63 #include <libedataserver/e-source-mail-account.h>
64 #include <libedataserver/e-source-mail-identity.h>
65
66 #include "e-dbus-authenticator.h"
67
68 #define E_SOURCE_REGISTRY_GET_PRIVATE(obj) \
69         (G_TYPE_INSTANCE_GET_PRIVATE \
70         ((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistryPrivate))
71
72 #define DBUS_OBJECT_PATH "/org/gnome/evolution/dataserver/SourceManager"
73 #define GSETTINGS_SCHEMA "org.gnome.Evolution.DefaultSources"
74
75 /* Built-in data source UIDs. */
76 #define E_SOURCE_BUILTIN_ADDRESS_BOOK_UID       "system-address-book"
77 #define E_SOURCE_BUILTIN_CALENDAR_UID           "system-calendar"
78 #define E_SOURCE_BUILTIN_MAIL_ACCOUNT_UID       "local"
79 #define E_SOURCE_BUILTIN_MEMO_LIST_UID          "system-memo-list"
80 #define E_SOURCE_BUILTIN_TASK_LIST_UID          "system-task-list"
81
82 /* GSettings keys for default data sources. */
83 #define E_SETTINGS_DEFAULT_ADDRESS_BOOK_KEY     "default-address-book"
84 #define E_SETTINGS_DEFAULT_CALENDAR_KEY         "default-calendar"
85 #define E_SETTINGS_DEFAULT_MAIL_ACCOUNT_KEY     "default-mail-account"
86 #define E_SETTINGS_DEFAULT_MAIL_IDENTITY_KEY    "default-mail-identity"
87 #define E_SETTINGS_DEFAULT_MEMO_LIST_KEY        "default-memo-list"
88 #define E_SETTINGS_DEFAULT_TASK_LIST_KEY        "default-task-list"
89
90 /* This forces the GType to be registered in a way that
91  * avoids a "statement with no effect" compiler warning.
92  * FIXME Use g_type_ensure() once we require GLib 2.34. */
93 #define REGISTER_TYPE(type) \
94         (g_type_class_unref (g_type_class_ref (type)))
95
96 typedef struct _AsyncContext AsyncContext;
97 typedef struct _AuthContext AuthContext;
98 typedef struct _SourceClosure SourceClosure;
99 typedef struct _ThreadClosure ThreadClosure;
100
101 struct _ESourceRegistryPrivate {
102         GMainContext *main_context;
103
104         GThread *manager_thread;
105         ThreadClosure *thread_closure;
106
107         GDBusObjectManager *dbus_object_manager;
108         EDBusSourceManager *dbus_source_manager;
109
110         GHashTable *object_path_table;
111         GMutex *object_path_table_lock;
112
113         GHashTable *sources;
114         GMutex *sources_lock;
115
116         GSettings *settings;
117 };
118
119 struct _AsyncContext {
120         ESource *source;
121         GList *list_of_sources;
122         ESourceAuthenticator *auth;
123 };
124
125 /* Used in e_source_registry_authenticate_sync() */
126 struct _AuthContext {
127         ESourceAuthenticator *auth;
128         EDBusAuthenticator *dbus_auth;
129         GCancellable *cancellable;
130         GMainLoop *main_loop;
131         ESourceAuthenticationResult auth_result;
132         GcrSecretExchange *secret_exchange;
133         gboolean authenticating;
134         gboolean success;
135         GError **error;
136 };
137
138 struct _SourceClosure {
139         ESourceRegistry *registry;
140         ESource *source;
141 };
142
143 struct _ThreadClosure {
144         ESourceRegistry *registry;
145         GMainContext *main_context;
146         GMainLoop *main_loop;
147         GCond *main_loop_cond;
148         GMutex *main_loop_mutex;
149         GError *error;
150 };
151
152 enum {
153         PROP_0,
154         PROP_DEFAULT_ADDRESS_BOOK,
155         PROP_DEFAULT_CALENDAR,
156         PROP_DEFAULT_MAIL_ACCOUNT,
157         PROP_DEFAULT_MAIL_IDENTITY,
158         PROP_DEFAULT_MEMO_LIST,
159         PROP_DEFAULT_TASK_LIST
160 };
161
162 enum {
163         SOURCE_ADDED,
164         SOURCE_CHANGED,
165         SOURCE_REMOVED,
166         SOURCE_ENABLED,
167         SOURCE_DISABLED,
168         LAST_SIGNAL
169 };
170
171 /* Forward Declarations */
172 static void     source_registry_add_source      (ESourceRegistry *registry,
173                                                  ESource *source);
174 static void     e_source_registry_initable_init (GInitableIface *interface);
175
176 static guint signals[LAST_SIGNAL];
177
178 /* By default, the GAsyncInitable interface calls GInitable.init()
179  * from a separate thread, so we only have to override GInitable. */
180 G_DEFINE_TYPE_WITH_CODE (
181         ESourceRegistry,
182         e_source_registry,
183         G_TYPE_OBJECT,
184         G_IMPLEMENT_INTERFACE (
185                 G_TYPE_INITABLE, e_source_registry_initable_init)
186         G_IMPLEMENT_INTERFACE (
187                 G_TYPE_ASYNC_INITABLE, NULL))
188
189 static void
190 async_context_free (AsyncContext *async_context)
191 {
192         if (async_context->source != NULL)
193                 g_object_unref (async_context->source);
194
195         g_list_free_full (
196                 async_context->list_of_sources,
197                 (GDestroyNotify) g_object_unref);
198
199         if (async_context->auth != NULL)
200                 g_object_unref (async_context->auth);
201
202         g_slice_free (AsyncContext, async_context);
203 }
204
205 static void
206 auth_context_free (AuthContext *auth_context)
207 {
208         if (auth_context->auth != NULL)
209                 g_object_unref (auth_context->auth);
210
211         if (auth_context->dbus_auth != NULL)
212                 g_object_unref (auth_context->dbus_auth);
213
214         if (auth_context->cancellable != NULL)
215                 g_object_unref (auth_context->cancellable);
216
217         if (auth_context->main_loop != NULL)
218                 g_main_loop_unref (auth_context->main_loop);
219
220         if (auth_context->secret_exchange != NULL)
221                 g_object_unref (auth_context->secret_exchange);
222
223         g_slice_free (AuthContext, auth_context);
224 }
225
226 static void
227 source_closure_free (SourceClosure *closure)
228 {
229         g_object_unref (closure->registry);
230         g_object_unref (closure->source);
231
232         g_slice_free (SourceClosure, closure);
233 }
234
235 static void
236 thread_closure_free (ThreadClosure *closure)
237 {
238         /* The registry member is not referenced. */
239
240         g_main_context_unref (closure->main_context);
241         g_main_loop_unref (closure->main_loop);
242         g_cond_free (closure->main_loop_cond);
243         g_mutex_free (closure->main_loop_mutex);
244
245         /* The GError should be NULL at this point,
246          * regardless of whether an error occurred. */
247         g_warn_if_fail (closure->error == NULL);
248
249         g_slice_free (ThreadClosure, closure);
250 }
251
252 static void
253 source_registry_object_path_table_insert (ESourceRegistry *registry,
254                                           const gchar *object_path,
255                                           ESource *source)
256 {
257         g_return_if_fail (object_path != NULL);
258         g_return_if_fail (E_IS_SOURCE (source));
259
260         g_mutex_lock (registry->priv->object_path_table_lock);
261
262         g_hash_table_insert (
263                 registry->priv->object_path_table,
264                 g_strdup (object_path),
265                 g_object_ref (source));
266
267         g_mutex_unlock (registry->priv->object_path_table_lock);
268 }
269
270 static ESource *
271 source_registry_object_path_table_lookup (ESourceRegistry *registry,
272                                           const gchar *object_path)
273 {
274         ESource *source;
275
276         g_return_val_if_fail (object_path != NULL, NULL);
277
278         g_mutex_lock (registry->priv->object_path_table_lock);
279
280         source = g_hash_table_lookup (
281                 registry->priv->object_path_table, object_path);
282         if (source != NULL)
283                 g_object_ref (source);
284
285         g_mutex_unlock (registry->priv->object_path_table_lock);
286
287         return source;
288 }
289
290 static gboolean
291 source_registry_object_path_table_remove (ESourceRegistry *registry,
292                                           const gchar *object_path)
293 {
294         gboolean removed;
295
296         g_return_val_if_fail (object_path != NULL, FALSE);
297
298         g_mutex_lock (registry->priv->object_path_table_lock);
299
300         removed = g_hash_table_remove (
301                 registry->priv->object_path_table, object_path);
302
303         g_mutex_unlock (registry->priv->object_path_table_lock);
304
305         return removed;
306 }
307
308 static void
309 source_registry_sources_insert (ESourceRegistry *registry,
310                                 ESource *source)
311 {
312         const gchar *uid;
313
314         uid = e_source_get_uid (source);
315         g_return_if_fail (uid != NULL);
316
317         g_mutex_lock (registry->priv->sources_lock);
318
319         g_hash_table_insert (
320                 registry->priv->sources,
321                 g_strdup (uid), g_object_ref (source));
322
323         g_mutex_unlock (registry->priv->sources_lock);
324 }
325
326 static gboolean
327 source_registry_sources_remove (ESourceRegistry *registry,
328                                 ESource *source)
329 {
330         const gchar *uid;
331         gboolean removed;
332
333         uid = e_source_get_uid (source);
334         g_return_val_if_fail (uid != NULL, FALSE);
335
336         g_mutex_lock (registry->priv->sources_lock);
337
338         removed = g_hash_table_remove (registry->priv->sources, uid);
339
340         g_mutex_unlock (registry->priv->sources_lock);
341
342         return removed;
343 }
344
345 static ESource *
346 source_registry_sources_lookup (ESourceRegistry *registry,
347                                 const gchar *uid)
348 {
349         ESource *source;
350
351         g_return_val_if_fail (uid != NULL, NULL);
352
353         g_mutex_lock (registry->priv->sources_lock);
354
355         source = g_hash_table_lookup (registry->priv->sources, uid);
356
357         if (source != NULL)
358                 g_object_ref (source);
359
360         g_mutex_unlock (registry->priv->sources_lock);
361
362         return source;
363 }
364
365 static GList *
366 source_registry_sources_get_values (ESourceRegistry *registry)
367 {
368         GList *values;
369
370         g_mutex_lock (registry->priv->sources_lock);
371
372         values = g_hash_table_get_values (registry->priv->sources);
373
374         g_list_foreach (values, (GFunc) g_object_ref, NULL);
375
376         g_mutex_unlock (registry->priv->sources_lock);
377
378         return values;
379 }
380
381 static GNode *
382 source_registry_sources_build_tree (ESourceRegistry *registry)
383 {
384         GNode *root;
385         GHashTable *index;
386         GHashTableIter iter;
387         gpointer key, value;
388
389         g_mutex_lock (registry->priv->sources_lock);
390
391         root = g_node_new (NULL);
392         index = g_hash_table_new (g_str_hash, g_str_equal);
393
394         /* Add a GNode for each ESource to the index. */
395         g_hash_table_iter_init (&iter, registry->priv->sources);
396         while (g_hash_table_iter_next (&iter, &key, &value)) {
397                 ESource *source = g_object_ref (value);
398                 g_hash_table_insert (index, key, g_node_new (source));
399         }
400
401         /* Traverse the index and link the nodes together. */
402         g_hash_table_iter_init (&iter, index);
403         while (g_hash_table_iter_next (&iter, NULL, &value)) {
404                 ESource *source;
405                 GNode *source_node;
406                 GNode *parent_node;
407                 const gchar *parent_uid;
408
409                 source_node = (GNode *) value;
410                 source = E_SOURCE (source_node->data);
411                 parent_uid = e_source_get_parent (source);
412
413                 if (parent_uid == NULL || *parent_uid == '\0') {
414                         parent_node = root;
415                 } else {
416                         parent_node = g_hash_table_lookup (index, parent_uid);
417                         g_warn_if_fail (parent_node != NULL);
418                 }
419
420                 /* Should never be NULL, but just to be safe. */
421                 if (parent_node != NULL)
422                         g_node_append (parent_node, source_node);
423         }
424
425         g_hash_table_destroy (index);
426
427         g_mutex_unlock (registry->priv->sources_lock);
428
429         return root;
430 }
431
432 static void
433 source_registry_settings_changed_cb (GSettings *settings,
434                                      const gchar *key,
435                                      ESourceRegistry *registry)
436 {
437         /* We define a property name that matches every key in
438          * the "org.gnome.Evolution.DefaultSources" schema. */
439         g_object_notify (G_OBJECT (registry), key);
440 }
441
442 static gboolean
443 source_registry_source_changed_idle_cb (gpointer user_data)
444 {
445         SourceClosure *closure = user_data;
446
447         g_signal_emit (
448                 closure->registry,
449                 signals[SOURCE_CHANGED], 0,
450                 closure->source);
451
452         return FALSE;
453 }
454
455 static gboolean
456 source_registry_source_notify_enabled_idle_cb (gpointer user_data)
457 {
458         SourceClosure *closure = user_data;
459
460         if (e_source_get_enabled (closure->source))
461                 g_signal_emit (
462                         closure->registry,
463                         signals[SOURCE_ENABLED], 0,
464                         closure->source);
465         else
466                 g_signal_emit (
467                         closure->registry,
468                         signals[SOURCE_DISABLED], 0,
469                         closure->source);
470
471         return FALSE;
472 }
473
474 static void
475 source_registry_source_changed_cb (ESource *source,
476                                    ESourceRegistry *registry)
477 {
478         GSource *idle_source;
479         SourceClosure *closure;
480
481         closure = g_slice_new0 (SourceClosure);
482         closure->registry = g_object_ref (registry);
483         closure->source = g_object_ref (source);
484
485         idle_source = g_idle_source_new ();
486         g_source_set_callback (
487                 idle_source,
488                 source_registry_source_changed_idle_cb,
489                 closure, (GDestroyNotify) source_closure_free);
490         g_source_attach (idle_source, registry->priv->main_context);
491         g_source_unref (idle_source);
492 }
493
494 static void
495 source_registry_source_notify_enabled_cb (ESource *source,
496                                           GParamSpec *pspec,
497                                           ESourceRegistry *registry)
498 {
499         GSource *idle_source;
500         SourceClosure *closure;
501
502         closure = g_slice_new0 (SourceClosure);
503         closure->registry = g_object_ref (registry);
504         closure->source = g_object_ref (source);
505
506         idle_source = g_idle_source_new ();
507         g_source_set_callback (
508                 idle_source,
509                 source_registry_source_notify_enabled_idle_cb,
510                 closure, (GDestroyNotify) source_closure_free);
511         g_source_attach (idle_source, registry->priv->main_context);
512         g_source_unref (idle_source);
513 }
514
515 static ESource *
516 source_registry_new_source (ESourceRegistry *registry,
517                             GDBusObject *dbus_object)
518 {
519         GMainContext *main_context;
520         ESource *source;
521         const gchar *object_path;
522         GError *error = NULL;
523
524         /* We don't want the ESource emitting "changed" signals from
525          * the manager thread, so we pass it the same main context the
526          * registry uses for scheduling signal emissions. */
527         main_context = registry->priv->main_context;
528         source = e_source_new (dbus_object, main_context, &error);
529         object_path = g_dbus_object_get_object_path (dbus_object);
530
531         /* The likelihood of an error here is slim, so it's
532          * sufficient to just print a warning if one occurs. */
533         if (error != NULL) {
534                 g_warn_if_fail (source == NULL);
535                 g_critical (
536                         "ESourceRegistry: Failed to create a "
537                         "data source object for path '%s': %s",
538                         object_path, error->message);
539                 g_error_free (error);
540                 return NULL;
541         }
542
543         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
544
545         /* Add the ESource to the object path table immediately. */
546         source_registry_object_path_table_insert (
547                 registry, object_path, source);
548
549         return source;
550 }
551
552 static void
553 source_registry_unref_source (ESource *source)
554 {
555         g_signal_handlers_disconnect_matched (
556                 source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
557                 source_registry_source_changed_cb, NULL);
558
559         g_signal_handlers_disconnect_matched (
560                 source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
561                 source_registry_source_notify_enabled_cb, NULL);
562
563         g_object_unref (source);
564 }
565
566 static void
567 source_registry_add_source (ESourceRegistry *registry,
568                             ESource *source)
569 {
570         const gchar *uid;
571
572         uid = e_source_get_uid (source);
573         g_return_if_fail (uid != NULL);
574
575         g_mutex_lock (registry->priv->sources_lock);
576
577         /* Check if we already have this source in the registry. */
578         if (g_hash_table_lookup (registry->priv->sources, uid) != NULL) {
579                 g_mutex_unlock (registry->priv->sources_lock);
580                 return;
581         }
582
583         g_signal_connect (
584                 source, "changed",
585                 G_CALLBACK (source_registry_source_changed_cb),
586                 registry);
587
588         g_signal_connect (
589                 source, "notify::enabled",
590                 G_CALLBACK (source_registry_source_notify_enabled_cb),
591                 registry);
592
593         g_mutex_unlock (registry->priv->sources_lock);
594
595         source_registry_sources_insert (registry, source);
596
597         g_signal_emit (registry, signals[SOURCE_ADDED], 0, source);
598 }
599
600 static void
601 source_registry_remove_source (ESourceRegistry *registry,
602                                ESource *source)
603 {
604         g_object_ref (source);
605
606         if (source_registry_sources_remove (registry, source))
607                 g_signal_emit (registry, signals[SOURCE_REMOVED], 0, source);
608
609         g_object_unref (source);
610 }
611
612 static gboolean
613 source_registry_object_added_idle_cb (gpointer user_data)
614 {
615         SourceClosure *closure = user_data;
616
617         source_registry_add_source (closure->registry, closure->source);
618
619         return FALSE;
620 }
621
622 static void
623 source_registry_object_added_cb (GDBusObjectManager *object_manager,
624                                  GDBusObject *dbus_object,
625                                  ESourceRegistry *registry)
626 {
627         SourceClosure *closure;
628         GSource *idle_source;
629         ESource *source;
630
631         g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
632
633         source = source_registry_new_source (registry, dbus_object);
634         g_return_if_fail (source != NULL);
635
636         /* Schedule a callback on the ESourceRegistry's GMainContext. */
637
638         closure = g_slice_new0 (SourceClosure);
639         closure->registry = g_object_ref (registry);
640         closure->source = g_object_ref (source);
641
642         idle_source = g_idle_source_new ();
643         g_source_set_callback (
644                 idle_source,
645                 source_registry_object_added_idle_cb,
646                 closure, (GDestroyNotify) source_closure_free);
647         g_source_attach (idle_source, registry->priv->main_context);
648         g_source_unref (idle_source);
649
650         g_object_unref (source);
651 }
652
653 static gboolean
654 source_registry_object_removed_idle_cb (gpointer user_data)
655 {
656         SourceClosure *closure = user_data;
657
658         source_registry_remove_source (closure->registry, closure->source);
659
660         return FALSE;
661 }
662
663 static void
664 source_registry_object_removed_cb (GDBusObjectManager *manager,
665                                    GDBusObject *dbus_object,
666                                    ESourceRegistry *registry)
667 {
668         SourceClosure *closure;
669         GSource *idle_source;
670         ESource *source;
671         const gchar *object_path;
672
673         /* Find the corresponding ESource in the object path table.
674          * Note that the lookup returns a new ESource reference. */
675         object_path = g_dbus_object_get_object_path (dbus_object);
676         source = source_registry_object_path_table_lookup (
677                 registry, object_path);
678         g_return_if_fail (E_IS_SOURCE (source));
679
680         /* Remove the ESource from the object path table immediately. */
681         source_registry_object_path_table_remove (registry, object_path);
682
683         /* Schedule a callback on the ESourceRegistry's GMainContext. */
684
685         closure = g_slice_new0 (SourceClosure);
686         closure->registry = g_object_ref (registry);
687         closure->source = g_object_ref (source);
688
689         idle_source = g_idle_source_new ();
690         g_source_set_callback (
691                 idle_source,
692                 source_registry_object_removed_idle_cb,
693                 closure, (GDestroyNotify) source_closure_free);
694         g_source_attach (idle_source, registry->priv->main_context);
695         g_source_unref (idle_source);
696
697         g_object_unref (source);
698 }
699
700 static gboolean
701 source_registry_object_manager_running (gpointer data)
702 {
703         ThreadClosure *closure = data;
704
705         g_mutex_lock (closure->main_loop_mutex);
706         g_cond_broadcast (closure->main_loop_cond);
707         g_mutex_unlock (closure->main_loop_mutex);
708
709         return FALSE;
710 }
711
712 static gpointer
713 source_registry_object_manager_thread (gpointer data)
714 {
715         GDBusObjectManager *object_manager;
716         ThreadClosure *closure = data;
717         GSource *idle_source;
718         GList *list, *link;
719         gulong object_added_id = 0;
720         gulong object_removed_id = 0;
721
722         /* GDBusObjectManagerClient grabs the thread-default GMainContext
723          * at creation time and only emits signals from that GMainContext.
724          * Running it in a separate thread prevents its signal emissions
725          * from being inhibited by someone overriding the thread-default
726          * GMainContext. */
727
728         /* This becomes the GMainContext that GDBusObjectManagerClient
729          * will emit signals from.  Make it the thread-default context
730          * for this thread before creating the client. */
731         g_main_context_push_thread_default (closure->main_context);
732
733         object_manager = e_dbus_object_manager_client_new_for_bus_sync (
734                 G_BUS_TYPE_SESSION,
735                 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
736                 SOURCES_DBUS_SERVICE_NAME,
737                 DBUS_OBJECT_PATH,
738                 NULL, &closure->error);
739
740         /* Sanity check. */
741         g_warn_if_fail (
742                 ((object_manager != NULL) && (closure->error == NULL)) ||
743                 ((object_manager == NULL) && (closure->error != NULL)));
744
745         /* If we failed to create the GDBusObjectManagerClient, skip
746          * straight to the main loop.  The GError will be propagated
747          * back to the caller, the main loop will terminate, and the
748          * partially-initialized ESourceRegistry will be destroyed. */
749         if (object_manager == NULL)
750                 goto notify;
751
752         /* Give the registry a handle to the object manager. */
753         closure->registry->priv->dbus_object_manager =
754                 g_object_ref (object_manager);
755
756         /* Now populate the registry with an initial set of ESources. */
757
758         list = g_dbus_object_manager_get_objects (object_manager);
759
760         for (link = list; link != NULL; link = g_list_next (link)) {
761                 GDBusObject *dbus_object;
762                 ESource *source;
763
764                 dbus_object = G_DBUS_OBJECT (link->data);
765
766                 source = source_registry_new_source (
767                         closure->registry, dbus_object);
768
769                 if (source != NULL) {
770                         source_registry_add_source (
771                                 closure->registry, source);
772                         g_object_unref (source);
773                 }
774         }
775
776         g_list_free_full (list, (GDestroyNotify) g_object_unref);
777
778         /* Listen for D-Bus object additions and removals. */
779
780         object_added_id = g_signal_connect (
781                 object_manager, "object-added",
782                 G_CALLBACK (source_registry_object_added_cb),
783                 closure->registry);
784
785         object_removed_id = g_signal_connect (
786                 object_manager, "object-removed",
787                 G_CALLBACK (source_registry_object_removed_cb),
788                 closure->registry);
789
790 notify:
791         /* Schedule a one-time idle callback to broadcast through a
792          * condition variable that our main loop is up and running. */
793
794         idle_source = g_idle_source_new ();
795         g_source_set_callback (
796                 idle_source,
797                 source_registry_object_manager_running,
798                 closure, (GDestroyNotify) NULL);
799         g_source_attach (idle_source, closure->main_context);
800         g_source_unref (idle_source);
801
802         /* Now we mostly idle here for the rest of the session. */
803
804         g_main_loop_run (closure->main_loop);
805
806         /* Clean up and exit. */
807
808         if (object_manager != NULL) {
809                 g_signal_handler_disconnect (object_manager, object_added_id);
810                 g_signal_handler_disconnect (object_manager, object_removed_id);
811                 g_object_unref (object_manager);
812         }
813
814         g_main_context_pop_thread_default (closure->main_context);
815
816         return NULL;
817 }
818
819 static void
820 source_registry_set_property (GObject *object,
821                               guint property_id,
822                               const GValue *value,
823                               GParamSpec *pspec)
824 {
825         switch (property_id) {
826                 case PROP_DEFAULT_ADDRESS_BOOK:
827                         e_source_registry_set_default_address_book (
828                                 E_SOURCE_REGISTRY (object),
829                                 g_value_get_object (value));
830                         return;
831
832                 case PROP_DEFAULT_CALENDAR:
833                         e_source_registry_set_default_calendar (
834                                 E_SOURCE_REGISTRY (object),
835                                 g_value_get_object (value));
836                         return;
837
838                 case PROP_DEFAULT_MAIL_ACCOUNT:
839                         e_source_registry_set_default_mail_account (
840                                 E_SOURCE_REGISTRY (object),
841                                 g_value_get_object (value));
842                         return;
843
844                 case PROP_DEFAULT_MAIL_IDENTITY:
845                         e_source_registry_set_default_mail_identity (
846                                 E_SOURCE_REGISTRY (object),
847                                 g_value_get_object (value));
848                         return;
849
850                 case PROP_DEFAULT_MEMO_LIST:
851                         e_source_registry_set_default_memo_list (
852                                 E_SOURCE_REGISTRY (object),
853                                 g_value_get_object (value));
854                         return;
855
856                 case PROP_DEFAULT_TASK_LIST:
857                         e_source_registry_set_default_task_list (
858                                 E_SOURCE_REGISTRY (object),
859                                 g_value_get_object (value));
860                         return;
861         }
862
863         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
864 }
865
866 static void
867 source_registry_get_property (GObject *object,
868                               guint property_id,
869                               GValue *value,
870                               GParamSpec *pspec)
871 {
872         switch (property_id) {
873                 case PROP_DEFAULT_ADDRESS_BOOK:
874                         g_value_take_object (
875                                 value,
876                                 e_source_registry_ref_default_address_book (
877                                 E_SOURCE_REGISTRY (object)));
878                         return;
879
880                 case PROP_DEFAULT_CALENDAR:
881                         g_value_take_object (
882                                 value,
883                                 e_source_registry_ref_default_calendar (
884                                 E_SOURCE_REGISTRY (object)));
885                         return;
886
887                 case PROP_DEFAULT_MAIL_ACCOUNT:
888                         g_value_take_object (
889                                 value,
890                                 e_source_registry_ref_default_mail_account (
891                                 E_SOURCE_REGISTRY (object)));
892                         return;
893
894                 case PROP_DEFAULT_MAIL_IDENTITY:
895                         g_value_take_object (
896                                 value,
897                                 e_source_registry_ref_default_mail_identity (
898                                 E_SOURCE_REGISTRY (object)));
899                         return;
900
901                 case PROP_DEFAULT_MEMO_LIST:
902                         g_value_take_object (
903                                 value,
904                                 e_source_registry_ref_default_memo_list (
905                                 E_SOURCE_REGISTRY (object)));
906                         return;
907
908                 case PROP_DEFAULT_TASK_LIST:
909                         g_value_take_object (
910                                 value,
911                                 e_source_registry_ref_default_task_list (
912                                 E_SOURCE_REGISTRY (object)));
913                         return;
914         }
915
916         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
917 }
918
919 static void
920 source_registry_dispose (GObject *object)
921 {
922         ESourceRegistryPrivate *priv;
923
924         priv = E_SOURCE_REGISTRY_GET_PRIVATE (object);
925
926         /* Terminate the manager thread first. */
927         if (priv->manager_thread != NULL) {
928                 g_main_loop_quit (priv->thread_closure->main_loop);
929                 g_thread_join (priv->manager_thread);
930                 thread_closure_free (priv->thread_closure);
931                 priv->manager_thread = NULL;
932                 priv->thread_closure = NULL;
933         }
934
935         if (priv->main_context != NULL) {
936                 g_main_context_unref (priv->main_context);
937                 priv->main_context = NULL;
938         }
939
940         if (priv->dbus_object_manager != NULL) {
941                 g_object_unref (priv->dbus_object_manager);
942                 priv->dbus_object_manager = NULL;
943         }
944
945         if (priv->dbus_source_manager != NULL) {
946                 g_object_unref (priv->dbus_source_manager);
947                 priv->dbus_source_manager = NULL;
948         }
949
950         g_hash_table_remove_all (priv->object_path_table);
951
952         g_hash_table_remove_all (priv->sources);
953
954         if (priv->settings != NULL) {
955                 g_object_unref (priv->settings);
956                 priv->settings = NULL;
957         }
958
959         /* Chain up to parent's finalize() method. */
960         G_OBJECT_CLASS (e_source_registry_parent_class)->dispose (object);
961 }
962
963 static void
964 source_registry_finalize (GObject *object)
965 {
966         ESourceRegistryPrivate *priv;
967
968         priv = E_SOURCE_REGISTRY_GET_PRIVATE (object);
969
970         g_hash_table_destroy (priv->object_path_table);
971         g_mutex_free (priv->object_path_table_lock);
972
973         g_hash_table_destroy (priv->sources);
974         g_mutex_free (priv->sources_lock);
975
976         /* Chain up to parent's finalize() method. */
977         G_OBJECT_CLASS (e_source_registry_parent_class)->finalize (object);
978 }
979
980 static gboolean
981 source_registry_initable_init (GInitable *initable,
982                                GCancellable *cancellable,
983                                GError **error)
984 {
985         ESourceRegistry *registry;
986         ThreadClosure *closure;
987
988         registry = E_SOURCE_REGISTRY (initable);
989
990         closure = g_slice_new0 (ThreadClosure);
991         closure->registry = registry;  /* do not reference */
992         closure->main_context = g_main_context_new ();
993         /* It's important to pass 'is_running=FALSE' here because
994          * we wait for the main loop to start running as a way of
995          * synchronizing with the manager thread. */
996         closure->main_loop = g_main_loop_new (closure->main_context, FALSE);
997         closure->main_loop_cond = g_cond_new ();
998         closure->main_loop_mutex = g_mutex_new ();
999
1000         registry->priv->thread_closure = closure;
1001
1002         registry->priv->manager_thread = g_thread_create (
1003                 source_registry_object_manager_thread,
1004                 closure, TRUE /* joinable */, error);
1005
1006         if (registry->priv->manager_thread == NULL)
1007                 return FALSE;
1008
1009         /* Wait for notification that the manager
1010          * thread's main loop has been started. */
1011         g_mutex_lock (closure->main_loop_mutex);
1012         while (!g_main_loop_is_running (closure->main_loop))
1013                 g_cond_wait (
1014                         closure->main_loop_cond,
1015                         closure->main_loop_mutex);
1016         g_mutex_unlock (closure->main_loop_mutex);
1017
1018         /* Check for error in the manager thread. */
1019         if (closure->error != NULL) {
1020                 g_propagate_error (error, closure->error);
1021                 closure->error = NULL;
1022                 return FALSE;
1023         }
1024
1025         /* The registry should now be populated with sources. */
1026         g_warn_if_fail (g_hash_table_size (registry->priv->sources) > 0);
1027
1028         /* The EDBusSourceManagerProxy is just another D-Bus interface
1029          * that resides at the same object path.  It's unrelated to the
1030          * GDBusObjectManagerClient and doesn't need its own thread. */
1031         registry->priv->dbus_source_manager =
1032                 e_dbus_source_manager_proxy_new_for_bus_sync (
1033                         G_BUS_TYPE_SESSION,
1034                         G_DBUS_PROXY_FLAGS_NONE,
1035                         SOURCES_DBUS_SERVICE_NAME,
1036                         DBUS_OBJECT_PATH,
1037                         cancellable, error);
1038
1039         if (registry->priv->dbus_source_manager == NULL)
1040                 return FALSE;
1041
1042         return TRUE;
1043 }
1044
1045 static void
1046 e_source_registry_class_init (ESourceRegistryClass *class)
1047 {
1048         GObjectClass *object_class;
1049
1050         g_type_class_add_private (class, sizeof (ESourceRegistryPrivate));
1051
1052         object_class = G_OBJECT_CLASS (class);
1053         object_class->set_property = source_registry_set_property;
1054         object_class->get_property = source_registry_get_property;
1055         object_class->dispose = source_registry_dispose;
1056         object_class->finalize = source_registry_finalize;
1057
1058         /* The property names correspond to the key names in the
1059          * "org.gnome.Evolution.DefaultSources" GSettings schema. */
1060
1061         /**
1062          * ESourceRegistry:default-address-book:
1063          *
1064          * The default address book #ESource.
1065          **/
1066         g_object_class_install_property (
1067                 object_class,
1068                 PROP_DEFAULT_ADDRESS_BOOK,
1069                 g_param_spec_object (
1070                         "default-address-book",
1071                         "Default Address Book",
1072                         "The default address book ESource",
1073                         E_TYPE_SOURCE,
1074                         G_PARAM_READWRITE |
1075                         G_PARAM_STATIC_STRINGS));
1076
1077         /**
1078          * ESourceRegistry:default-calendar:
1079          *
1080          * The default calendar #ESource.
1081          **/
1082         g_object_class_install_property (
1083                 object_class,
1084                 PROP_DEFAULT_CALENDAR,
1085                 g_param_spec_object (
1086                         "default-calendar",
1087                         "Default Calendar",
1088                         "The default calendar ESource",
1089                         E_TYPE_SOURCE,
1090                         G_PARAM_READWRITE |
1091                         G_PARAM_STATIC_STRINGS));
1092
1093         /**
1094          * ESourceRegistry:default-mail-account:
1095          *
1096          * The default mail account #ESource.
1097          **/
1098         g_object_class_install_property (
1099                 object_class,
1100                 PROP_DEFAULT_MAIL_ACCOUNT,
1101                 g_param_spec_object (
1102                         "default-mail-account",
1103                         "Default Mail Account",
1104                         "The default mail account ESource",
1105                         E_TYPE_SOURCE,
1106                         G_PARAM_READWRITE |
1107                         G_PARAM_STATIC_STRINGS));
1108
1109         /**
1110          * ESourceRegistry:default-mail-identity:
1111          *
1112          * The default mail identity #ESource.
1113          **/
1114         g_object_class_install_property (
1115                 object_class,
1116                 PROP_DEFAULT_MAIL_IDENTITY,
1117                 g_param_spec_object (
1118                         "default-mail-identity",
1119                         "Default Mail Identity",
1120                         "The default mail identity ESource",
1121                         E_TYPE_SOURCE,
1122                         G_PARAM_READWRITE |
1123                         G_PARAM_STATIC_STRINGS));
1124
1125         /**
1126          * ESourceRegistry:default-memo-list:
1127          *
1128          * The default memo list #ESource.
1129          **/
1130         g_object_class_install_property (
1131                 object_class,
1132                 PROP_DEFAULT_MEMO_LIST,
1133                 g_param_spec_object (
1134                         "default-memo-list",
1135                         "Default Memo List",
1136                         "The default memo list ESource",
1137                         E_TYPE_SOURCE,
1138                         G_PARAM_READWRITE |
1139                         G_PARAM_STATIC_STRINGS));
1140
1141         /**
1142          * ESourceRegistry:default-task-list:
1143          *
1144          * The default task list #ESource.
1145          **/
1146         g_object_class_install_property (
1147                 object_class,
1148                 PROP_DEFAULT_TASK_LIST,
1149                 g_param_spec_object (
1150                         "default-task-list",
1151                         "Default Task List",
1152                         "The default task list ESource",
1153                         E_TYPE_SOURCE,
1154                         G_PARAM_READWRITE |
1155                         G_PARAM_STATIC_STRINGS));
1156
1157         /**
1158          * ESourceRegistry::source-added:
1159          * @registry: the #ESourceRegistry which emitted the signal
1160          * @source: the newly-added #ESource
1161          *
1162          * Emitted when an #ESource is added to @registry.
1163          **/
1164         signals[SOURCE_ADDED] = g_signal_new (
1165                 "source-added",
1166                 G_OBJECT_CLASS_TYPE (object_class),
1167                 G_SIGNAL_RUN_LAST,
1168                 G_STRUCT_OFFSET (ESourceRegistryClass, source_added),
1169                 NULL, NULL,
1170                 g_cclosure_marshal_VOID__OBJECT,
1171                 G_TYPE_NONE, 1,
1172                 E_TYPE_SOURCE);
1173
1174         /**
1175          * ESourceRegistry::source-changed:
1176          * @registry: the #ESourceRegistry which emitted the signal
1177          * @source: the #ESource that changed
1178          *
1179          * Emitted when an #ESource registered with @registry emits
1180          * its #ESource::changed signal.
1181          **/
1182         signals[SOURCE_CHANGED] = g_signal_new (
1183                 "source-changed",
1184                 G_OBJECT_CLASS_TYPE (object_class),
1185                 G_SIGNAL_RUN_LAST,
1186                 G_STRUCT_OFFSET (ESourceRegistryClass, source_changed),
1187                 NULL, NULL,
1188                 g_cclosure_marshal_VOID__OBJECT,
1189                 G_TYPE_NONE, 1,
1190                 E_TYPE_SOURCE);
1191
1192         /**
1193          * ESourceRegistry::source-removed:
1194          * @registry: the #ESourceRegistry which emitted the signal
1195          * @source: the #ESource that got removed
1196          *
1197          * Emitted when an #ESource is removed from @registry.
1198          **/
1199         signals[SOURCE_REMOVED] = g_signal_new (
1200                 "source-removed",
1201                 G_OBJECT_CLASS_TYPE (object_class),
1202                 G_SIGNAL_RUN_LAST,
1203                 G_STRUCT_OFFSET (ESourceRegistryClass, source_removed),
1204                 NULL, NULL,
1205                 g_cclosure_marshal_VOID__OBJECT,
1206                 G_TYPE_NONE, 1,
1207                 E_TYPE_SOURCE);
1208
1209         /**
1210          * ESourceRegistry::source-enabled:
1211          * @registry: the #ESourceRegistry which emitted the signal
1212          * @source: the #ESource that got enabled
1213          *
1214          * Emitted when an #ESource #ESource:enabled property becomes %TRUE.
1215          **/
1216         signals[SOURCE_ENABLED] = g_signal_new (
1217                 "source-enabled",
1218                 G_OBJECT_CLASS_TYPE (object_class),
1219                 G_SIGNAL_RUN_LAST,
1220                 G_STRUCT_OFFSET (ESourceRegistryClass, source_enabled),
1221                 NULL, NULL,
1222                 g_cclosure_marshal_VOID__OBJECT,
1223                 G_TYPE_NONE, 1,
1224                 E_TYPE_SOURCE);
1225
1226         /**
1227          * ESourceRegistry::source-disabled:
1228          * @registry: the #ESourceRegistry which emitted the signal
1229          * @source: the #ESource that got disabled
1230          *
1231          * Emitted when an #ESource #ESource:enabled property becomes %FALSE.
1232          **/
1233         signals[SOURCE_DISABLED] = g_signal_new (
1234                 "source-disabled",
1235                 G_OBJECT_CLASS_TYPE (object_class),
1236                 G_SIGNAL_RUN_LAST,
1237                 G_STRUCT_OFFSET (ESourceRegistryClass, source_disabled),
1238                 NULL, NULL,
1239                 g_cclosure_marshal_VOID__OBJECT,
1240                 G_TYPE_NONE, 1,
1241                 E_TYPE_SOURCE);
1242 }
1243
1244 static void
1245 e_source_registry_initable_init (GInitableIface *interface)
1246 {
1247         interface->init = source_registry_initable_init;
1248 }
1249
1250 static void
1251 e_source_registry_init (ESourceRegistry *registry)
1252 {
1253         registry->priv = E_SOURCE_REGISTRY_GET_PRIVATE (registry);
1254
1255         /* This is so the object manager thread can schedule signal
1256          * emissions on the thread-default context for this thread. */
1257         registry->priv->main_context = g_main_context_ref_thread_default ();
1258
1259         /* D-Bus object path -> ESource */
1260         registry->priv->object_path_table =
1261                 g_hash_table_new_full (
1262                         (GHashFunc) g_str_hash,
1263                         (GEqualFunc) g_str_equal,
1264                         (GDestroyNotify) g_free,
1265                         (GDestroyNotify) g_object_unref);
1266
1267         registry->priv->object_path_table_lock = g_mutex_new ();
1268
1269         /* UID string -> ESource */
1270         registry->priv->sources = g_hash_table_new_full (
1271                 (GHashFunc) g_str_hash,
1272                 (GEqualFunc) g_str_equal,
1273                 (GDestroyNotify) g_free,
1274                 (GDestroyNotify) source_registry_unref_source);
1275
1276         registry->priv->sources_lock = g_mutex_new ();
1277
1278         registry->priv->settings = g_settings_new (GSETTINGS_SCHEMA);
1279
1280         g_signal_connect (
1281                 registry->priv->settings, "changed",
1282                 G_CALLBACK (source_registry_settings_changed_cb), registry);
1283 }
1284
1285 /**
1286  * e_source_registry_new_sync:
1287  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1288  * @error: return location for a #GError, or %NULL
1289  *
1290  * Creates a new #ESourceRegistry front-end for the registry D-Bus service.
1291  * If an error occurs in connecting to the D-Bus service, the function sets
1292  * @error and returns %NULL.
1293  *
1294  * Returns: a new #ESourceRegistry, or %NULL
1295  *
1296  * Since: 3.6
1297  **/
1298 ESourceRegistry *
1299 e_source_registry_new_sync (GCancellable *cancellable,
1300                             GError **error)
1301 {
1302         /* XXX Work around http://bugzilla.gnome.org/show_bug.cgi?id=683519
1303          *     until GObject's type initialization deadlock issue is fixed.
1304          *     Apparently only the synchronous instantiation is affected. */
1305         REGISTER_TYPE (G_TYPE_DBUS_CONNECTION);
1306
1307         return g_initable_new (
1308                 E_TYPE_SOURCE_REGISTRY,
1309                 cancellable, error, NULL);
1310 }
1311
1312 /**
1313  * e_source_registry_new:
1314  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1315  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1316  *            is satisfied
1317  * @user_data: (closure): data to pass to the callback function
1318  *
1319  * Asynchronously creates a new #ESourceRegistry front-end for the registry
1320  * D-Bus service.
1321  *
1322  * When the operation is finished, @callback will be called.  You can then
1323  * call e_source_registry_new_finish() to get the result of the operation.
1324  *
1325  * Since: 3.6
1326  **/
1327 void
1328 e_source_registry_new (GCancellable *cancellable,
1329                        GAsyncReadyCallback callback,
1330                        gpointer user_data)
1331 {
1332         g_async_initable_new_async (
1333                 E_TYPE_SOURCE_REGISTRY,
1334                 G_PRIORITY_DEFAULT, cancellable,
1335                 callback, user_data, NULL);
1336 }
1337
1338 /**
1339  * e_source_registry_new_finish:
1340  * @result: a #GAsyncResult
1341  * @error: return location for a #GError, or %NULL
1342  *
1343  * Finishes the operation started with e_source_registry_new_finish().
1344  * If an error occurs in connecting to the D-Bus service, the function
1345  * sets @error and returns %NULL.
1346  *
1347  * Returns: a new #ESourceRegistry, or %NULL
1348  *
1349  * Since: 3.6
1350  **/
1351 ESourceRegistry *
1352 e_source_registry_new_finish (GAsyncResult *result,
1353                               GError **error)
1354 {
1355         GObject *source_object;
1356         GObject *object;
1357
1358         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1359
1360         source_object = g_async_result_get_source_object (result);
1361         g_return_val_if_fail (source_object != NULL, NULL);
1362
1363         object = g_async_initable_new_finish (
1364                 G_ASYNC_INITABLE (source_object), result, error);
1365
1366         g_object_unref (source_object);
1367
1368         return (object != NULL) ? E_SOURCE_REGISTRY (object) : NULL;
1369 }
1370
1371 /* Helper for e_source_registry_authenticate() */
1372 static void
1373 source_registry_authenticate_thread (GSimpleAsyncResult *simple,
1374                                      GObject *object,
1375                                      GCancellable *cancellable)
1376 {
1377         AsyncContext *async_context;
1378         GError *error = NULL;
1379
1380         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1381
1382         e_source_registry_authenticate_sync (
1383                 E_SOURCE_REGISTRY (object),
1384                 async_context->source,
1385                 async_context->auth,
1386                 cancellable, &error);
1387
1388         if (error != NULL)
1389                 g_simple_async_result_take_error (simple, error);
1390 }
1391
1392 /* Helper for e_source_registry_authenticate_sync() */
1393 static gboolean
1394 source_registry_authenticate_respond_cb (AuthContext *auth_context)
1395 {
1396         ESourceAuthenticationResult auth_result;
1397         GError *non_fatal_error = NULL;
1398
1399         g_return_val_if_fail (auth_context->authenticating, FALSE);
1400
1401         auth_result = auth_context->auth_result;
1402
1403         /* Allow the next authentication attempt to proceed. */
1404         auth_context->authenticating = FALSE;
1405
1406         /* Send the server a status update based on the authentication
1407          * result.  Note, we don't really care if the D-Bus message gets
1408          * through to the server at this point.  If it doesn't, the auth
1409          * session will either time out on its own or the authentication
1410          * dialog will eventually be dismissed by the user. */
1411
1412         /* If we were cancelled from our side, we have a bit of a dilemma.
1413          * We need to tell the server to cancel the authentication session,
1414          * but that involves making a synchronous D-Bus call, which we are
1415          * not supposed to do if we know we've been cancelled.  But if we
1416          * don't tell the server, the authentication session will be left
1417          * to timeout on its own (which may take minutes), and meanwhile
1418          * all other authentication requests are blocked.  So choose the
1419          * lesser evil and make the synchronous call but without passing
1420          * the already-cancelled GCancellable. */
1421         if (g_cancellable_is_cancelled (auth_context->cancellable)) {
1422                 e_dbus_authenticator_call_cancel_sync (
1423                         auth_context->dbus_auth,
1424                         NULL, &non_fatal_error);
1425                 g_main_loop_quit (auth_context->main_loop);
1426                 auth_context->success = FALSE;
1427
1428         /* If an error occurred while attempting to authenticate,
1429          * tell the server to cancel the authentication session. */
1430         } else if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
1431                 e_dbus_authenticator_call_cancel_sync (
1432                         auth_context->dbus_auth,
1433                         auth_context->cancellable,
1434                         &non_fatal_error);
1435                 g_main_loop_quit (auth_context->main_loop);
1436                 auth_context->success = FALSE;
1437
1438         /* If the password was accepted, let the server know so it
1439          * can close any authentication dialogs and save the user
1440          * provided password to the keyring. */
1441         } else if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
1442                 e_dbus_authenticator_call_accepted_sync (
1443                         auth_context->dbus_auth,
1444                         auth_context->cancellable,
1445                         &non_fatal_error);
1446                 g_main_loop_quit (auth_context->main_loop);
1447                 auth_context->success = TRUE;
1448
1449         /* If the password was rejected, let the server know so it can
1450          * indicate failure and request a different password, and then
1451          * wait for the next "response" signal. */
1452         } else {
1453                 e_dbus_authenticator_call_rejected_sync (
1454                         auth_context->dbus_auth,
1455                         auth_context->cancellable,
1456                         &non_fatal_error);
1457         }
1458
1459         /* Leave breadcrumbs if something went wrong,
1460          * but don't fail the whole operation over it. */
1461         if (non_fatal_error != NULL) {
1462                 g_warning ("%s: %s", G_STRFUNC, non_fatal_error->message);
1463                 g_error_free (non_fatal_error);
1464         }
1465
1466         return FALSE;
1467 }
1468
1469 /* Helper for e_source_registry_authenticate_sync() */
1470 static void
1471 source_registry_authenticate_authenticate_cb (EDBusAuthenticator *dbus_auth,
1472                                               const gchar *encrypted_secret,
1473                                               AuthContext *auth_context)
1474 {
1475         GSource *idle_source;
1476         GMainContext *main_context;
1477         GString *password;
1478         gboolean valid_secret;
1479
1480         /* We should only get one secret at a time. */
1481         g_return_if_fail (!auth_context->authenticating);
1482
1483         valid_secret = gcr_secret_exchange_receive (
1484                 auth_context->secret_exchange, encrypted_secret);
1485         g_return_if_fail (valid_secret);
1486
1487         auth_context->authenticating = TRUE;
1488
1489         /* This avoids revealing the password in a stack trace. */
1490         password = g_string_new (
1491                 gcr_secret_exchange_get_secret (
1492                 auth_context->secret_exchange, NULL));
1493
1494         /* Try authenticating with the given password.  We have to
1495          * call this synchronously because some authenticators use
1496          * mutexes to serialize I/O operations and are not prepared
1497          * to make authentication attempts from a different thread.
1498          *
1499          * Unfortunately this means we won't notice server-side
1500          * dismissals while the main loop is blocked.  We respond
1501          * to the server from a low-priority idle callback so that
1502          * any pending "dismissed" signals get handled first. */
1503
1504         auth_context->auth_result =
1505                 e_source_authenticator_try_password_sync (
1506                         auth_context->auth, password,
1507                         auth_context->cancellable,
1508                         auth_context->error);
1509
1510         idle_source = g_idle_source_new ();
1511         main_context = g_main_context_get_thread_default ();
1512         g_source_set_callback (
1513                 idle_source, (GSourceFunc)
1514                 source_registry_authenticate_respond_cb,
1515                 auth_context, NULL);
1516         g_source_attach (idle_source, main_context);
1517         g_source_unref (idle_source);
1518
1519         g_string_free (password, TRUE);
1520 }
1521
1522 /* Helper for e_source_registry_authenticate_sync() */
1523 static void
1524 source_registry_authenticate_dismissed_cb (EDBusAuthenticator *dbus_auth,
1525                                            AuthContext *auth_context)
1526 {
1527         /* Be careful not to overwrite an existing error in case this
1528          * is called after e_source_authenticator_try_password_sync()
1529          * but prior to the idle callback. */
1530         if (auth_context->auth_result != E_SOURCE_AUTHENTICATION_ERROR) {
1531                 /* XXX Use a separate error code for dismissals? */
1532                 g_set_error_literal (
1533                         auth_context->error,
1534                         G_IO_ERROR, G_IO_ERROR_CANCELLED,
1535                         _("The user declined to authenticate"));
1536                 auth_context->auth_result = E_SOURCE_AUTHENTICATION_ERROR;
1537         }
1538
1539         g_main_loop_quit (auth_context->main_loop);
1540         auth_context->success = FALSE;
1541 }
1542
1543 /* Helper for e_source_registry_authenticate_sync() */
1544 static gboolean
1545 source_registry_call_authenticate_for_source (ESourceRegistry *registry,
1546                                               ESourceAuthenticator *auth,
1547                                               ESource *source,
1548                                               gchar **out_object_path,
1549                                               GCancellable *cancellable,
1550                                               GError **error)
1551 {
1552         ESource *collection;
1553         const gchar *uid;
1554         gchar *prompt_title = NULL;
1555         gchar *prompt_message = NULL;
1556         gchar *prompt_description = NULL;
1557         gboolean success;
1558
1559         /* If the source is a member of a collection, we want to store
1560          * the password under the UID of the "collection" source so it
1561          * will apply to the entire collection.
1562          *
1563          * XXX This assumes all sources in a collection share a single
1564          *     password.  If that turns out not to be true in all cases
1565          *     we could maybe add a "SharedPassword: true/false" key to
1566          *     [Collection] and apply it here.
1567          */
1568         collection = e_source_registry_find_extension (
1569                 registry, source, E_SOURCE_EXTENSION_COLLECTION);
1570         if (collection != NULL)
1571                 source = collection;
1572         else
1573                 g_object_ref (source);
1574
1575         uid = e_source_get_uid (source);
1576
1577         e_source_authenticator_get_prompt_strings (
1578                 auth, source,
1579                 &prompt_title,
1580                 &prompt_message,
1581                 &prompt_description);
1582
1583         success = e_dbus_source_manager_call_authenticate_sync (
1584                 registry->priv->dbus_source_manager, uid,
1585                 prompt_title, prompt_message, prompt_description,
1586                 out_object_path, cancellable, error);
1587
1588         g_free (prompt_title);
1589         g_free (prompt_message);
1590         g_free (prompt_description);
1591
1592         g_object_unref (source);
1593
1594         return success;
1595 }
1596
1597 /**
1598  * e_source_registry_authenticate_sync:
1599  * @registry: an #ESourceRegistry
1600  * @source: an #ESource
1601  * @auth: an #ESourceAuthenticator
1602  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1603  * @error: return location for a #GError, or %NULL
1604  *
1605  * Authenticates @source, using @auth to handle the authentication
1606  * attempts.  The operation loops until authentication is successful or
1607  * the user aborts further authentication attempts.  If an error occurs,
1608  * the function will set @error and return %FALSE.
1609  *
1610  * Note that @source need not have a #GDBusObject, which means this
1611  * function can test authentication on a scratch #ESource.
1612  *
1613  * Only backend implementations and data source editors should call this
1614  * function.  The intent is for basic client applications to not have to
1615  * deal with authentication at all.
1616  *
1617  * Returns: %TRUE on success, %FALSE on failure
1618  *
1619  * Since: 3.6
1620  **/
1621 gboolean
1622 e_source_registry_authenticate_sync (ESourceRegistry *registry,
1623                                      ESource *source,
1624                                      ESourceAuthenticator *auth,
1625                                      GCancellable *cancellable,
1626                                      GError **error)
1627 {
1628         AuthContext *auth_context;
1629         GMainContext *main_context;
1630         EDBusAuthenticator *dbus_auth;
1631         gchar *encryption_key;
1632         gchar *object_path = NULL;
1633         gboolean success;
1634
1635         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1636         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1637         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth), FALSE);
1638
1639         /* This extracts authentication prompt details for the ESource
1640          * before initiating an authentication session with the server,
1641          * so split it out of the main algorithm for clarity's sake. */
1642         success = source_registry_call_authenticate_for_source (
1643                 registry, auth, source, &object_path, cancellable, error);
1644
1645         if (!success) {
1646                 g_warn_if_fail (object_path == NULL);
1647                 return FALSE;
1648         }
1649
1650         g_return_val_if_fail (object_path != NULL, FALSE);
1651
1652         main_context = g_main_context_new ();
1653         g_main_context_push_thread_default (main_context);
1654
1655         dbus_auth = e_dbus_authenticator_proxy_new_for_bus_sync (
1656                 G_BUS_TYPE_SESSION,
1657                 G_DBUS_PROXY_FLAGS_NONE,
1658                 SOURCES_DBUS_SERVICE_NAME,
1659                 object_path, cancellable, error);
1660
1661         g_free (object_path);
1662
1663         if (dbus_auth == NULL) {
1664                 success = FALSE;
1665                 goto exit;
1666         }
1667
1668         auth_context = g_slice_new0 (AuthContext);
1669         auth_context->auth = g_object_ref (auth);
1670         auth_context->dbus_auth = dbus_auth;  /* takes ownership */
1671         auth_context->main_loop = g_main_loop_new (main_context, FALSE);
1672         auth_context->error = error;
1673
1674         /* This just needs to be something other than
1675          * E_SOURCE_AUTHENTICATION_ERROR so we don't trip
1676          * up source_registry_authenticate_dismissed_cb(). */
1677         auth_context->auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
1678
1679         if (G_IS_CANCELLABLE (cancellable))
1680                 auth_context->cancellable = g_object_ref (cancellable);
1681
1682         auth_context->secret_exchange =
1683                 gcr_secret_exchange_new (GCR_SECRET_EXCHANGE_PROTOCOL_1);
1684
1685         g_signal_connect (
1686                 dbus_auth, "authenticate",
1687                 G_CALLBACK (source_registry_authenticate_authenticate_cb),
1688                 auth_context);
1689
1690         g_signal_connect (
1691                 dbus_auth, "dismissed",
1692                 G_CALLBACK (source_registry_authenticate_dismissed_cb),
1693                 auth_context);
1694
1695         encryption_key = gcr_secret_exchange_begin (
1696                 auth_context->secret_exchange);
1697
1698         /* Signal the D-Bus server that we're ready to begin the
1699          * authentication session.  This must happen AFTER we've
1700          * connected to the response signal since the server may
1701          * already have a response ready and waiting for us. */
1702         success = e_dbus_authenticator_call_ready_sync (
1703                 dbus_auth, encryption_key, cancellable, error);
1704
1705         g_free (encryption_key);
1706
1707         if (success) {
1708                 g_main_loop_run (auth_context->main_loop);
1709                 success = auth_context->success;
1710         }
1711
1712         auth_context_free (auth_context);
1713
1714 exit:
1715         g_main_context_pop_thread_default (main_context);
1716         g_main_context_unref (main_context);
1717
1718         return success;
1719 }
1720
1721 /**
1722  * e_source_registry_authenticate:
1723  * @registry: an #ESourceRegistry
1724  * @source: an #ESource
1725  * @auth: an #ESourceAuthenticator
1726  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1727  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1728  *            is satisfied
1729  * @user_data: (closure): data to pass to the callback function
1730  *
1731  * Asynchronously authenticates @source, using @auth to handle the
1732  * authentication attempts.  The operation loops until authentication
1733  * is successful or the user aborts further authentication attempts.
1734  *
1735  * Note that @source need not have a #GDBusObject, which means this
1736  * function can test authentication on a scratch #ESource.
1737  *
1738  * When the operation is finished, @callback will be called.  You can then
1739  * call e_source_registry_authenticate_finish() to get the result of the
1740  * operation.
1741  *
1742  * Only backend implementations and data source editors should call this
1743  * function.  The intent is for basic client applications to not have to
1744  * deal with authentication at all.
1745  *
1746  * Since: 3.6
1747  **/
1748 void
1749 e_source_registry_authenticate (ESourceRegistry *registry,
1750                                 ESource *source,
1751                                 ESourceAuthenticator *auth,
1752                                 GCancellable *cancellable,
1753                                 GAsyncReadyCallback callback,
1754                                 gpointer user_data)
1755 {
1756         GSimpleAsyncResult *simple;
1757         AsyncContext *async_context;
1758
1759         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
1760         g_return_if_fail (E_IS_SOURCE (source));
1761         g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
1762
1763         async_context = g_slice_new0 (AsyncContext);
1764         async_context->source = g_object_ref (source);
1765         async_context->auth = g_object_ref (auth);
1766
1767         simple = g_simple_async_result_new (
1768                 G_OBJECT (registry), callback, user_data,
1769                 e_source_registry_authenticate);
1770
1771         g_simple_async_result_set_check_cancellable (simple, cancellable);
1772
1773         g_simple_async_result_set_op_res_gpointer (
1774                 simple, async_context, (GDestroyNotify) async_context_free);
1775
1776         g_simple_async_result_run_in_thread (
1777                 simple, source_registry_authenticate_thread,
1778                 G_PRIORITY_DEFAULT, cancellable);
1779
1780         g_object_unref (simple);
1781 }
1782
1783 /**
1784  * e_source_registry_authenticate_finish:
1785  * @registry: an #ESourceRegistry
1786  * @result: a #GAsyncResult
1787  * @error: return location for a #GError, or %NULL
1788  *
1789  * Finishes the operation started with e_source_registry_authenticate().
1790  * If an error occurred, the function will set @error and return %FALSE.
1791  *
1792  * Returns: %TRUE on success, %FALSE on failure
1793  *
1794  * Since: 3.6
1795  **/
1796 gboolean
1797 e_source_registry_authenticate_finish (ESourceRegistry *registry,
1798                                        GAsyncResult *result,
1799                                        GError **error)
1800 {
1801         GSimpleAsyncResult *simple;
1802
1803         g_return_val_if_fail (
1804                 g_simple_async_result_is_valid (
1805                 result, G_OBJECT (registry),
1806                 e_source_registry_authenticate), FALSE);
1807
1808         simple = G_SIMPLE_ASYNC_RESULT (result);
1809
1810         /* Assume success unless a GError is set. */
1811         return !g_simple_async_result_propagate_error (simple, error);
1812 }
1813
1814 /* Helper for e_source_registry_commit_source() */
1815 static void
1816 source_registry_commit_source_thread (GSimpleAsyncResult *simple,
1817                                       GObject *object,
1818                                       GCancellable *cancellable)
1819 {
1820         AsyncContext *async_context;
1821         GError *error = NULL;
1822
1823         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1824
1825         e_source_registry_commit_source_sync (
1826                 E_SOURCE_REGISTRY (object),
1827                 async_context->source,
1828                 cancellable, &error);
1829
1830         if (error != NULL)
1831                 g_simple_async_result_take_error (simple, error);
1832 }
1833
1834 /**
1835  * e_source_registry_commit_source_sync:
1836  * @registry: an #ESourceRegistry
1837  * @source: an #ESource with changes to commit
1838  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1839  * @error: return location for #GError, or %NULL
1840  *
1841  * This is a convenience function intended for use with graphical
1842  * #ESource editors.  Call this function when the user is finished
1843  * making changes to @source.
1844  *
1845  * If @source has a #GDBusObject, its contents are submitted to the D-Bus
1846  * service through e_source_write_sync().
1847  *
1848  * If @source does NOT have a #GDBusObject (implying it's a scratch
1849  * #ESource), its contents are submitted to the D-Bus service through
1850  * either e_source_remote_create_sync() if @source is to be a collection
1851  * member, or e_source_registry_create_sources_sync() if @source to be an
1852  * independent data source.
1853  *
1854  * If an error occurs, the function will set @error and return %FALSE.
1855  *
1856  * Returns: %TRUE on success, %FALSE on failure
1857  *
1858  * Since: 3.6
1859  **/
1860 gboolean
1861 e_source_registry_commit_source_sync (ESourceRegistry *registry,
1862                                       ESource *source,
1863                                       GCancellable *cancellable,
1864                                       GError **error)
1865 {
1866         GDBusObject *dbus_object;
1867         ESource *collection_source;
1868         gboolean collection_member;
1869         gboolean success;
1870
1871         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1872         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1873
1874         dbus_object = e_source_ref_dbus_object (source);
1875
1876         collection_source = e_source_registry_find_extension (
1877                 registry, source, E_SOURCE_EXTENSION_COLLECTION);
1878
1879         collection_member =
1880                 (collection_source != NULL) &&
1881                 (collection_source != source);
1882
1883         if (dbus_object != NULL) {
1884                 success = e_source_write_sync (source, cancellable, error);
1885                 g_object_unref (dbus_object);
1886
1887         } else if (collection_member) {
1888                 success = e_source_remote_create_sync (
1889                         collection_source, source, cancellable, error);
1890
1891         } else {
1892                 GList *list = g_list_prepend (NULL, source);
1893                 success = e_source_registry_create_sources_sync (
1894                         registry, list, cancellable, error);
1895                 g_list_free (list);
1896         }
1897
1898         if (collection_source != NULL)
1899                 g_object_unref (collection_source);
1900
1901         return success;
1902 }
1903
1904 /**
1905  * e_source_registry_commit_source:
1906  * @registry: an #ESourceRegistry
1907  * @source: an #ESource with changes to commit
1908  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1909  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1910  *            is satisfied
1911  * @user_data: (closure): data to pass to the callback function
1912  *
1913  * See e_source_registry_commit_source_sync() for details.
1914  *
1915  * When the operation is finished, @callback will be called.  You can then
1916  * call e_source_registry_commit_source_finish() to get the result of the
1917  * operation.
1918  *
1919  * Since: 3.6
1920  **/
1921 void
1922 e_source_registry_commit_source (ESourceRegistry *registry,
1923                                  ESource *source,
1924                                  GCancellable *cancellable,
1925                                  GAsyncReadyCallback callback,
1926                                  gpointer user_data)
1927 {
1928         GSimpleAsyncResult *simple;
1929         AsyncContext *async_context;
1930
1931         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
1932         g_return_if_fail (E_IS_SOURCE (source));
1933
1934         async_context = g_slice_new0 (AsyncContext);
1935         async_context->source = g_object_ref (source);
1936
1937         simple = g_simple_async_result_new (
1938                 G_OBJECT (registry), callback, user_data,
1939                 e_source_registry_commit_source);
1940
1941         g_simple_async_result_set_check_cancellable (simple, cancellable);
1942
1943         g_simple_async_result_set_op_res_gpointer (
1944                 simple, async_context, (GDestroyNotify) async_context_free);
1945
1946         g_simple_async_result_run_in_thread (
1947                 simple, source_registry_commit_source_thread,
1948                 G_PRIORITY_DEFAULT, cancellable);
1949
1950         g_object_unref (simple);
1951 }
1952
1953 /**
1954  * e_source_registry_commit_source_finish:
1955  * @registry: an #ESourceRegistry
1956  * @result: a #GAsyncResult
1957  * @error: return location for a #GError, or %NULL
1958  *
1959  * Finishes the operation started with e_source_registry_commit_source().
1960  *
1961  * If an error occurred, the function will set @error and return %FALSE.
1962  *
1963  * Returns: %TRUE on success, %FALSE on failure
1964  *
1965  * Since: 3.6
1966  **/
1967 gboolean
1968 e_source_registry_commit_source_finish (ESourceRegistry *registry,
1969                                         GAsyncResult *result,
1970                                         GError **error)
1971 {
1972         GSimpleAsyncResult *simple;
1973
1974         g_return_val_if_fail (
1975                 g_simple_async_result_is_valid (
1976                 result, G_OBJECT (registry),
1977                 e_source_registry_commit_source), FALSE);
1978
1979         simple = G_SIMPLE_ASYNC_RESULT (result);
1980
1981         /* Assume success unless a GError is set. */
1982         return !g_simple_async_result_propagate_error (simple, error);
1983 }
1984
1985 /* Helper for e_source_registry_create_sources() */
1986 static void
1987 source_registry_create_sources_thread (GSimpleAsyncResult *simple,
1988                                        GObject *object,
1989                                        GCancellable *cancellable)
1990 {
1991         AsyncContext *async_context;
1992         GError *error = NULL;
1993
1994         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1995
1996         e_source_registry_create_sources_sync (
1997                 E_SOURCE_REGISTRY (object),
1998                 async_context->list_of_sources,
1999                 cancellable, &error);
2000
2001         if (error != NULL)
2002                 g_simple_async_result_take_error (simple, error);
2003 }
2004
2005 /**
2006  * e_source_registry_create_sources_sync:
2007  * @registry: an #ESourceRegistry
2008  * @list_of_sources: (element-type ESource): a list of #ESource instances with
2009  * no #GDBusObject
2010  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2011  * @error: return location for a #GError, or %NULL
2012  *
2013  * Requests the D-Bus service create new key files for each #ESource in
2014  * @list_of_sources.  Each list element must be a scratch #ESource with
2015  * no #GDBusObject.
2016  *
2017  * If an error occurs, the function will set @error and return %FALSE.
2018  *
2019  * Returns: %TRUE on success, %FALSE on failure
2020  *
2021  * Since: 3.6
2022  **/
2023 gboolean
2024 e_source_registry_create_sources_sync (ESourceRegistry *registry,
2025                                        GList *list_of_sources,
2026                                        GCancellable *cancellable,
2027                                        GError **error)
2028 {
2029         GVariantBuilder builder;
2030         GVariant *variant;
2031         GList *link;
2032         gboolean success;
2033
2034         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
2035
2036         /* Verify the list elements are all ESources. */
2037         for (link = list_of_sources; link != NULL; link = g_list_next (link))
2038                 g_return_val_if_fail (E_IS_SOURCE (link->data), FALSE);
2039
2040         g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2041
2042         for (link = list_of_sources; link != NULL; link = g_list_next (link)) {
2043                 ESource *source;
2044                 const gchar *uid;
2045                 gchar *source_data;
2046
2047                 source = E_SOURCE (link->data);
2048                 uid = e_source_get_uid (source);
2049
2050                 source_data = e_source_to_string (source, NULL);
2051                 g_variant_builder_add (&builder, "{ss}", uid, source_data);
2052                 g_free (source_data);
2053         }
2054
2055         variant = g_variant_builder_end (&builder);
2056
2057         /* This function sinks the floating GVariant reference. */
2058         success = e_dbus_source_manager_call_create_sources_sync (
2059                 registry->priv->dbus_source_manager,
2060                 variant, cancellable, error);
2061
2062         g_variant_builder_clear (&builder);
2063
2064         return success;
2065 }
2066
2067 /**
2068  * e_source_registry_create_sources:
2069  * @registry: an #ESourceRegistry
2070  * @list_of_sources: (element-type ESource): a list of #ESource instances with
2071  * no #GDBusObject
2072  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2073  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2074  *            is satisfied
2075  * @user_data: (closure): data to pass to the callback function
2076  *
2077  * Asynchronously requests the D-Bus service create new key files for each
2078  * #ESource in @list_of_sources.  Each list element must be a scratch
2079  * #ESource with no #GDBusObject.
2080  *
2081  * When the operation is finished, @callback will be called.  You can then
2082  * call e_source_registry_create_sources_finish() to get the result of the
2083  * operation.
2084  *
2085  * Since: 3.6
2086  **/
2087 void
2088 e_source_registry_create_sources (ESourceRegistry *registry,
2089                                   GList *list_of_sources,
2090                                   GCancellable *cancellable,
2091                                   GAsyncReadyCallback callback,
2092                                   gpointer user_data)
2093 {
2094         GSimpleAsyncResult *simple;
2095         AsyncContext *async_context;
2096         GList *link;
2097
2098         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2099
2100         /* Verify the list elements are all ESources. */
2101         for (link = list_of_sources; link != NULL; link = g_list_next (link))
2102                 g_return_if_fail (E_IS_SOURCE (link->data));
2103
2104         async_context = g_slice_new0 (AsyncContext);
2105         async_context->list_of_sources = g_list_copy (list_of_sources);
2106
2107         g_list_foreach (
2108                 async_context->list_of_sources,
2109                 (GFunc) g_object_ref, NULL);
2110
2111         simple = g_simple_async_result_new (
2112                 G_OBJECT (registry), callback, user_data,
2113                 e_source_registry_create_sources);
2114
2115         g_simple_async_result_set_check_cancellable (simple, cancellable);
2116
2117         g_simple_async_result_set_op_res_gpointer (
2118                 simple, async_context, (GDestroyNotify) async_context_free);
2119
2120         g_simple_async_result_run_in_thread (
2121                 simple, source_registry_create_sources_thread,
2122                 G_PRIORITY_DEFAULT, cancellable);
2123
2124         g_object_unref (simple);
2125 }
2126
2127 /**
2128  * e_source_registry_create_sources_finish:
2129  * @registry: an #ESourceRegistry
2130  * @result: a #GAsyncResult
2131  * @error: return location for a #GError, or %NULL
2132  *
2133  * Finishes the operation started with e_source_registry_create_sources().
2134  *
2135  * If an error occurred, the function will set @error and return %FALSE.
2136  *
2137  * Returns: %TRUE on success, %FALSE on failure
2138  *
2139  * Since: 3.6
2140  **/
2141 gboolean
2142 e_source_registry_create_sources_finish (ESourceRegistry *registry,
2143                                          GAsyncResult *result,
2144                                          GError **error)
2145 {
2146         GSimpleAsyncResult *simple;
2147
2148         g_return_val_if_fail (
2149                 g_simple_async_result_is_valid (
2150                 result, G_OBJECT (registry),
2151                 e_source_registry_create_sources), FALSE);
2152
2153         simple = G_SIMPLE_ASYNC_RESULT (result);
2154
2155         /* Assume success unless a GError is set. */
2156         return !g_simple_async_result_propagate_error (simple, error);
2157 }
2158
2159 /**
2160  * e_source_registry_ref_source:
2161  * @registry: an #ESourceRegistry
2162  * @uid: a unique identifier string
2163  *
2164  * Looks up an #ESource in @registry by its unique identifier string.
2165  *
2166  * The returned #ESource is referenced for thread-safety and must be
2167  * unreferenced with g_object_unref() when finished with it.
2168  *
2169  * Returns: (transfer full): an #ESource, or %NULL if no match was found
2170  *
2171  * Since: 3.6
2172  **/
2173 ESource *
2174 e_source_registry_ref_source (ESourceRegistry *registry,
2175                               const gchar *uid)
2176 {
2177         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2178         g_return_val_if_fail (uid != NULL, NULL);
2179
2180         return source_registry_sources_lookup (registry, uid);
2181 }
2182
2183 /**
2184  * e_source_registry_list_sources:
2185  * @registry: an #ESourceRegistry
2186  * @extension_name: (allow-none): an extension name, or %NULL
2187  *
2188  * Returns a list of registered sources, sorted by display name.  If
2189  * @extension_name is given, restrict the list to sources having that
2190  * extension name.
2191  *
2192  * The sources returned in the list are referenced for thread-safety.
2193  * They must each be unreferenced with g_object_unref() when finished
2194  * when them.  Free the returned list itself with g_list_free().
2195  *
2196  * An easy way to free the list properly in one step is as follows:
2197  *
2198  * |[
2199  *   g_list_free_full (list, g_object_unref);
2200  * ]|
2201  *
2202  * Returns: (element-type ESource) (transfer full): a sorted list of sources
2203  *
2204  * Since: 3.6
2205  **/
2206 GList *
2207 e_source_registry_list_sources (ESourceRegistry *registry,
2208                                 const gchar *extension_name)
2209 {
2210         GList *list, *link;
2211         GQueue trash = G_QUEUE_INIT;
2212
2213         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2214
2215         list = g_list_sort (
2216                 source_registry_sources_get_values (registry),
2217                 (GCompareFunc) e_source_compare_by_display_name);
2218
2219         if (extension_name == NULL)
2220                 return list;
2221
2222         for (link = list; link != NULL; link = g_list_next (link)) {
2223                 ESource *source = E_SOURCE (link->data);
2224
2225                 if (!e_source_has_extension (source, extension_name)) {
2226                         g_queue_push_tail (&trash, link);
2227                         g_object_unref (source);
2228                 }
2229         }
2230
2231         /* We do want pop_head() here, not pop_head_link(). */
2232         while ((link = g_queue_pop_head (&trash)) != NULL)
2233                 list = g_list_delete_link (list, link);
2234
2235         return list;
2236 }
2237
2238 /**
2239  * e_source_registry_check_enabled:
2240  * @registry: an #ESourceRegistry
2241  * @source: an #ESource
2242  *
2243  * Determines whether @source is "effectively" enabled by examining its
2244  * own #ESource:enabled property as well as those of its ancestors in the
2245  * #ESource hierarchy.  If all examined #ESource:enabled properties are
2246  * %TRUE, then the function returns %TRUE.  If any are %FALSE, then the
2247  * function returns %FALSE.
2248  *
2249  * Use this function instead of e_source_get_enabled() to determine
2250  * things like whether to display an #ESource in a user interface or
2251  * whether to act on the data set described by the #ESource.
2252  *
2253  * Returns: whether @source is "effectively" enabled
2254  *
2255  * Since: 3.8
2256  **/
2257 gboolean
2258 e_source_registry_check_enabled (ESourceRegistry *registry,
2259                                  ESource *source)
2260 {
2261         gboolean enabled;
2262         gchar *parent_uid;
2263
2264         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
2265         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2266
2267         enabled = e_source_get_enabled (source);
2268         parent_uid = e_source_dup_parent (source);
2269
2270         while (enabled && parent_uid != NULL) {
2271                 ESource *parent;
2272
2273                 parent = e_source_registry_ref_source (registry, parent_uid);
2274
2275                 g_free (parent_uid);
2276                 parent_uid = NULL;
2277
2278                 if (parent != NULL) {
2279                         enabled = e_source_get_enabled (parent);
2280                         parent_uid = e_source_dup_parent (parent);
2281                         g_object_unref (parent);
2282                 }
2283         }
2284
2285         g_free (parent_uid);
2286
2287         return enabled;
2288 }
2289
2290 /**
2291  * e_source_registry_find_extension:
2292  * @registry: an #ESourceRegistry
2293  * @source: an #ESource
2294  * @extension_name: the extension name to find
2295  *
2296  * Examines @source and its ancestors and returns the "deepest" #ESource
2297  * having an #ESourceExtension with the given @extension_name.  If neither
2298  * @source nor any of its ancestors have such an extension, the function
2299  * returns %NULL.
2300  *
2301  * This function is useful in cases when an #ESourceExtension is meant to
2302  * apply to both the #ESource it belongs to and the #ESource's descendants.
2303  *
2304  * A common example is the #ESourceCollection extension, where descendants
2305  * of an #ESource having an #ESourceCollection extension are implied to be
2306  * members of that collection.  In that example, this function can be used
2307  * to test whether @source is a member of a collection.
2308  *
2309  * The returned #ESource is referenced for thread-safety and must be
2310  * unreferenced with g_object_unref() when finished with it.
2311  *
2312  * Note the function returns the #ESource containing the #ESourceExtension
2313  * instead of the #ESourceExtension itself because extension instances are
2314  * not to be referenced directly (see e_source_get_extension()).
2315  *
2316  * Returns: (transfer full): an #ESource, or %NULL if no match was found
2317  *
2318  * Since: 3.6
2319  **/
2320 ESource *
2321 e_source_registry_find_extension (ESourceRegistry *registry,
2322                                   ESource *source,
2323                                   const gchar *extension_name)
2324 {
2325         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2326         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2327         g_return_val_if_fail (extension_name != NULL, NULL);
2328
2329         g_object_ref (source);
2330
2331         while (!e_source_has_extension (source, extension_name)) {
2332                 gchar *uid;
2333
2334                 uid = e_source_dup_parent (source);
2335
2336                 g_object_unref (source);
2337                 source = NULL;
2338
2339                 if (uid != NULL) {
2340                         source = e_source_registry_ref_source (registry, uid);
2341                         g_free (uid);
2342                 }
2343
2344                 if (source == NULL)
2345                         break;
2346         }
2347
2348         return source;
2349 }
2350
2351 /* Helper for e_source_registry_build_display_tree() */
2352 static gint
2353 source_registry_compare_nodes (GNode *node_a,
2354                                GNode *node_b)
2355 {
2356         ESource *source_a = E_SOURCE (node_a->data);
2357         ESource *source_b = E_SOURCE (node_b->data);
2358         const gchar *uid_a, *uid_b;
2359
2360         uid_a = e_source_get_uid (source_a);
2361         uid_b = e_source_get_uid (source_b);
2362
2363         /* Sanity check, with runtime warnings. */
2364         if (uid_a == NULL) {
2365                 g_warn_if_reached ();
2366                 uid_a = "";
2367         }
2368         if (uid_b == NULL) {
2369                 g_warn_if_reached ();
2370                 uid_b = "";
2371         }
2372
2373         /* The built-in "local-stub" source comes first at depth 1. */
2374
2375         if (g_strcmp0 (uid_a, "local-stub") == 0)
2376                 return -1;
2377
2378         if (g_strcmp0 (uid_b, "local-stub") == 0)
2379                 return 1;
2380
2381         /* The built-in "system-*" sources come first at depth 2. */
2382
2383         if (g_str_has_prefix (uid_a, "system-"))
2384                 return -1;
2385
2386         if (g_str_has_prefix (uid_b, "system-"))
2387                 return 1;
2388
2389         return e_source_compare_by_display_name (source_a, source_b);
2390 }
2391
2392 /* Helper for e_source_registry_build_display_tree() */
2393 static gboolean
2394 source_registry_prune_nodes (GNode *node,
2395                              const gchar *extension_name)
2396 {
2397         GQueue queue = G_QUEUE_INIT;
2398         GNode *child_node;
2399
2400         /* Unlink all the child nodes and place them in a queue. */
2401         while ((child_node = g_node_first_child (node)) != NULL) {
2402                 g_node_unlink (child_node);
2403                 g_queue_push_tail (&queue, child_node);
2404         }
2405
2406         /* Sort the queue by source name. */
2407         g_queue_sort (
2408                 &queue, (GCompareDataFunc)
2409                 source_registry_compare_nodes, NULL);
2410
2411         /* Pop nodes off the head of the queue until the queue is empty.
2412          * If the node has either its own children or the given extension
2413          * name, put it back under the parent node (preserving the sorted
2414          * order).  Otherwise delete the node and its descendants. */
2415         while ((child_node = g_queue_pop_head (&queue)) != NULL) {
2416                 ESource *child = E_SOURCE (child_node->data);
2417                 gboolean append_child_node = FALSE;
2418
2419                 if (extension_name == NULL)
2420                         append_child_node = e_source_get_enabled (child);
2421
2422                 else if (e_source_has_extension (child, extension_name))
2423                         append_child_node = e_source_get_enabled (child);
2424
2425                 else if (g_node_first_child (child_node) != NULL)
2426                         append_child_node = e_source_get_enabled (child);
2427
2428                 if (append_child_node)
2429                         g_node_append (node, child_node);
2430                 else
2431                         e_source_registry_free_display_tree (child_node);
2432         }
2433
2434         return FALSE;
2435 }
2436
2437 /**
2438  * e_source_registry_build_display_tree:
2439  * @registry: an #ESourceRegistry
2440  * @extension_name: (allow-none): an extension name, or %NULL
2441  *
2442  * Returns a single #GNode tree of registered sources that can be used to
2443  * populate a #GtkTreeModel.  (The root #GNode is just an empty placeholder.)
2444  *
2445  * Similar to e_source_registry_list_sources(), an @extension_name can be
2446  * given to restrict the tree to sources having that extension name.  Parents
2447  * of matched sources are included in the tree regardless of whether they have
2448  * an extension named @extension_name.
2449  *
2450  * Disabled leaf nodes are automatically excluded from the #GNode tree.
2451  *
2452  * The sources returned in the tree are referenced for thread-safety.
2453  * They must each be unreferenced with g_object_unref() when finished
2454  * with them.  Free the returned tree itself with g_node_destroy().
2455  * For convenience, e_source_registry_free_display_tree() does all
2456  * that in one step.
2457  *
2458  * Returns: (element-type ESource) (transfer full): a tree of sources,
2459  *          arranged for display
2460  *
2461  * Since: 3.6
2462  **/
2463 GNode *
2464 e_source_registry_build_display_tree (ESourceRegistry *registry,
2465                                       const gchar *extension_name)
2466 {
2467         GNode *root;
2468
2469         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2470
2471         /* Assemble all data sources into a tree. */
2472         root = source_registry_sources_build_tree (registry);
2473
2474         /* Prune unwanted nodes from the copied source trees.
2475          * This must be done in "post" order (children first)
2476          * since it reorders and deletes child nodes. */
2477         g_node_traverse (
2478                 root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2479                 (GNodeTraverseFunc) source_registry_prune_nodes,
2480                 (gpointer) extension_name);
2481
2482         return root;
2483 }
2484
2485 /* Helper for e_source_registry_free_display_tree() */
2486 static void
2487 source_registry_unref_nodes (GNode *node)
2488 {
2489         while (node != NULL) {
2490                 if (node->children != NULL)
2491                         source_registry_unref_nodes (node->children);
2492                 if (node->data != NULL)
2493                         g_object_unref (node->data);
2494                 node = node->next;
2495         }
2496 }
2497
2498 /**
2499  * e_source_registry_free_display_tree:
2500  * @display_tree: a tree of sources, arranged for display
2501  *
2502  * Convenience function to free a #GNode tree of registered
2503  * sources created by e_source_registry_build_display_tree().
2504  *
2505  * Since: 3.6
2506  **/
2507 void
2508 e_source_registry_free_display_tree (GNode *display_tree)
2509 {
2510         g_return_if_fail (display_tree != NULL);
2511
2512         /* XXX This would be easier if GLib had something like
2513          *     g_node_destroy_full() which took a GDestroyNotify.
2514          *     Then the tree would not have to be traversed twice. */
2515
2516         source_registry_unref_nodes (display_tree);
2517         g_node_destroy (display_tree);
2518 }
2519
2520 /* Helper for e_source_registry_debug_dump() */
2521 static gboolean
2522 source_registry_debug_dump_cb (GNode *node)
2523 {
2524         guint ii, depth;
2525
2526         /* Root node is an empty placeholder. */
2527         if (G_NODE_IS_ROOT (node))
2528                 return FALSE;
2529
2530         depth = g_node_depth (node);
2531         for (ii = 2; ii < depth; ii++)
2532                 g_print ("    ");
2533
2534         if (E_IS_SOURCE (node->data)) {
2535                 ESource *source = E_SOURCE (node->data);
2536                 g_print ("\"%s\" ", e_source_get_display_name (source));
2537                 g_print ("(%s)", e_source_get_uid (source));
2538         }
2539
2540         g_print ("\n");
2541
2542         return FALSE;
2543 }
2544
2545 /**
2546  * e_source_registry_debug_dump:
2547  * @registry: an #ESourceRegistry
2548  * @extension_name: (allow-none): an extension name, or %NULL
2549  *
2550  * Handy debugging function that uses e_source_registry_build_display_tree()
2551  * to print a tree of registered sources to standard output.
2552  *
2553  * Since: 3.6
2554  **/
2555 void
2556 e_source_registry_debug_dump (ESourceRegistry *registry,
2557                               const gchar *extension_name)
2558 {
2559         GNode *root;
2560
2561         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2562
2563         root = e_source_registry_build_display_tree (registry, extension_name);
2564
2565         g_node_traverse (
2566                 root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2567                 (GNodeTraverseFunc) source_registry_debug_dump_cb, NULL);
2568
2569         e_source_registry_free_display_tree (root);
2570 }
2571
2572 /**
2573  * e_source_registry_ref_builtin_address_book:
2574  * @registry: an #ESourceRegistry
2575  *
2576  * Returns the built-in address book #ESource.
2577  *
2578  * This #ESource is always present and makes for a safe fallback.
2579  *
2580  * The returned #ESource is referenced for thread-safety and must be
2581  * unreferenced with g_object_unref() when finished with it.
2582  *
2583  * Returns: (transfer full): the built-in address book #ESource
2584  *
2585  * Since: 3.6
2586  **/
2587 ESource *
2588 e_source_registry_ref_builtin_address_book (ESourceRegistry *registry)
2589 {
2590         ESource *source;
2591         const gchar *uid;
2592
2593         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2594
2595         uid = E_SOURCE_BUILTIN_ADDRESS_BOOK_UID;
2596         source = e_source_registry_ref_source (registry, uid);
2597         g_return_val_if_fail (source != NULL, NULL);
2598
2599         return source;
2600 }
2601
2602 /**
2603  * e_source_registry_ref_default_address_book:
2604  * @registry: an #ESourceRegistry
2605  *
2606  * Returns the #ESource most recently passed to
2607  * e_source_registry_set_default_address_book() either in this session
2608  * or a previous session, or else falls back to the built-in address book.
2609  *
2610  * The returned #ESource is referenced for thread-safety and must be
2611  * unreferenced with g_object_unref() when finished with it.
2612  *
2613  * Returns: (transfer full): the default address book #ESource
2614  *
2615  * Since: 3.6
2616  **/
2617 ESource *
2618 e_source_registry_ref_default_address_book (ESourceRegistry *registry)
2619 {
2620         const gchar *key;
2621         ESource *source;
2622         gchar *uid;
2623
2624         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2625
2626         key = E_SETTINGS_DEFAULT_ADDRESS_BOOK_KEY;
2627         uid = g_settings_get_string (registry->priv->settings, key);
2628         source = e_source_registry_ref_source (registry, uid);
2629         g_free (uid);
2630
2631         /* The built-in source is always present. */
2632         if (source == NULL)
2633                 source = e_source_registry_ref_builtin_address_book (registry);
2634
2635         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2636
2637         return source;
2638 }
2639
2640 /**
2641  * e_source_registry_set_default_address_book:
2642  * @registry: an #ESourceRegistry
2643  * @default_source: (allow-none): an address book #ESource, or %NULL
2644  *
2645  * Sets @default_source as the default address book.  If @default_source
2646  * is %NULL, the default address book is reset to the built-in address book.
2647  * This setting will persist across sessions until changed.
2648  *
2649  * Since: 3.6
2650  **/
2651 void
2652 e_source_registry_set_default_address_book (ESourceRegistry *registry,
2653                                             ESource *default_source)
2654 {
2655         const gchar *key;
2656         const gchar *uid;
2657
2658         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2659
2660         if (default_source != NULL) {
2661                 g_return_if_fail (E_IS_SOURCE (default_source));
2662                 uid = e_source_get_uid (default_source);
2663         } else {
2664                 uid = E_SOURCE_BUILTIN_ADDRESS_BOOK_UID;
2665         }
2666
2667         key = E_SETTINGS_DEFAULT_ADDRESS_BOOK_KEY;
2668         g_settings_set_string (registry->priv->settings, key, uid);
2669
2670         /* The GSettings::changed signal will trigger a "notify" signal
2671          * from the registry, so no need to call g_object_notify() here. */
2672 }
2673
2674 /**
2675  * e_source_registry_ref_builtin_calendar:
2676  * @registry: an #ESourceRegistry
2677  *
2678  * Returns the built-in calendar #ESource.
2679  *
2680  * This #ESource is always present and makes for a safe fallback.
2681  *
2682  * The returned #ESource is referenced for thread-safety and must be
2683  * unreferenced with g_object_unref() when finished with it.
2684  *
2685  * Returns: (transfer full): the built-in calendar #ESource
2686  *
2687  * Since: 3.6
2688  **/
2689 ESource *
2690 e_source_registry_ref_builtin_calendar (ESourceRegistry *registry)
2691 {
2692         ESource *source;
2693         const gchar *uid;
2694
2695         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2696
2697         uid = E_SOURCE_BUILTIN_CALENDAR_UID;
2698         source = e_source_registry_ref_source (registry, uid);
2699         g_return_val_if_fail (source != NULL, NULL);
2700
2701         return source;
2702 }
2703
2704 /**
2705  * e_source_registry_ref_default_calendar:
2706  * @registry: an #ESourceRegistry
2707  *
2708  * Returns the #ESource most recently passed to
2709  * e_source_registry_set_default_calendar() either in this session
2710  * or a previous session, or else falls back to the built-in calendar.
2711  *
2712  * The returned #ESource is referenced for thread-safety and must be
2713  * unreferenced with g_object_unref() when finished with it.
2714  *
2715  * Returns: (transfer full): the default calendar #ESource
2716  *
2717  * Since: 3.6
2718  **/
2719 ESource *
2720 e_source_registry_ref_default_calendar (ESourceRegistry *registry)
2721 {
2722         const gchar *key;
2723         ESource *source;
2724         gchar *uid;
2725
2726         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2727
2728         key = E_SETTINGS_DEFAULT_CALENDAR_KEY;
2729         uid = g_settings_get_string (registry->priv->settings, key);
2730         source = e_source_registry_ref_source (registry, uid);
2731         g_free (uid);
2732
2733         /* The built-in source is always present. */
2734         if (source == NULL)
2735                 source = e_source_registry_ref_builtin_calendar (registry);
2736
2737         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2738
2739         return source;
2740 }
2741
2742 /**
2743  * e_source_registry_set_default_calendar:
2744  * @registry: an #ESourceRegistry
2745  * @default_source: (allow-none): a calendar #ESource, or %NULL
2746  *
2747  * Sets @default_source as the default calendar.  If @default_source
2748  * is %NULL, the default calendar is reset to the built-in calendar.
2749  * This setting will persist across sessions until changed.
2750  *
2751  * Since: 3.6
2752  **/
2753 void
2754 e_source_registry_set_default_calendar (ESourceRegistry *registry,
2755                                         ESource *default_source)
2756 {
2757         const gchar *key;
2758         const gchar *uid;
2759
2760         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2761
2762         if (default_source != NULL) {
2763                 g_return_if_fail (E_IS_SOURCE (default_source));
2764                 uid = e_source_get_uid (default_source);
2765         } else {
2766                 uid = E_SOURCE_BUILTIN_CALENDAR_UID;
2767         }
2768
2769         key = E_SETTINGS_DEFAULT_CALENDAR_KEY;
2770         g_settings_set_string (registry->priv->settings, key, uid);
2771
2772         /* The GSettings::changed signal will trigger a "notify" signal
2773          * from the registry, so no need to call g_object_notify() here. */
2774 }
2775
2776 /**
2777  * e_source_registry_ref_builtin_mail_account:
2778  * @registry: an #ESourceRegistry
2779  *
2780  * Returns the built-in mail account #ESource.
2781  *
2782  * This #ESource is always present and makes for a safe fallback.
2783  *
2784  * The returned #ESource is referenced for thread-safety and must be
2785  * unreferenced with g_object_unref() when finished with it.
2786  *
2787  * Returns: (transfer full): the built-in mail account #ESource
2788  *
2789  * Since: 3.6
2790  **/
2791 ESource *
2792 e_source_registry_ref_builtin_mail_account (ESourceRegistry *registry)
2793 {
2794         ESource *source;
2795         const gchar *uid;
2796
2797         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2798
2799         uid = E_SOURCE_BUILTIN_MAIL_ACCOUNT_UID;
2800         source = e_source_registry_ref_source (registry, uid);
2801         g_return_val_if_fail (source != NULL, NULL);
2802
2803         return source;
2804 }
2805
2806 /**
2807  * e_source_registry_ref_default_mail_account:
2808  * @registry: an #ESourceRegistry
2809  *
2810  * Returns the #ESource most recently passed to
2811  * e_source_registry_set_default_mail_account() either in this session
2812  * or a previous session, or else falls back to the built-in mail account.
2813  *
2814  * The returned #ESource is referenced for thread-safety and must be
2815  * unreferenced with g_object_unref() when finished with it.
2816  *
2817  * Returns: (transfer full): the default mail account #ESource
2818  *
2819  * Since: 3.6
2820  **/
2821 ESource *
2822 e_source_registry_ref_default_mail_account (ESourceRegistry *registry)
2823 {
2824         const gchar *key;
2825         ESource *source;
2826         gchar *uid;
2827
2828         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2829
2830         key = E_SETTINGS_DEFAULT_MAIL_ACCOUNT_KEY;
2831         uid = g_settings_get_string (registry->priv->settings, key);
2832         source = e_source_registry_ref_source (registry, uid);
2833         g_free (uid);
2834
2835         /* The built-in source is always present. */
2836         if (source == NULL)
2837                 source = e_source_registry_ref_builtin_mail_account (registry);
2838
2839         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2840
2841         return source;
2842 }
2843
2844 /**
2845  * e_source_registry_set_default_mail_account:
2846  * @registry: an #ESourceRegistry
2847  * @default_source: (allow-none): a mail account #ESource, or %NULL
2848  *
2849  * Sets @default_source as the default mail account.  If @default_source
2850  * is %NULL, the default mail account is reset to the built-in mail account.
2851  * This setting will persist across sessions until changed.
2852  *
2853  * Since: 3.6
2854  **/
2855 void
2856 e_source_registry_set_default_mail_account (ESourceRegistry *registry,
2857                                             ESource *default_source)
2858 {
2859         const gchar *key;
2860         const gchar *uid;
2861
2862         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2863
2864         if (default_source != NULL) {
2865                 g_return_if_fail (E_IS_SOURCE (default_source));
2866                 uid = e_source_get_uid (default_source);
2867         } else {
2868                 uid = E_SOURCE_BUILTIN_MAIL_ACCOUNT_UID;
2869         }
2870
2871         key = E_SETTINGS_DEFAULT_MAIL_ACCOUNT_KEY;
2872         g_settings_set_string (registry->priv->settings, key, uid);
2873
2874         /* The GSettings::changed signal will trigger a "notify" signal
2875          * from the registry, so no need to call g_object_notify() here. */
2876 }
2877
2878 /* Helper for e_source_registry_ref_default_mail_identity() */
2879 static ESource *
2880 source_registry_ref_any_mail_identity (ESourceRegistry *registry)
2881 {
2882         ESource *source;
2883         GList *list, *link;
2884         const gchar *extension_name;
2885         gchar *uid = NULL;
2886
2887         /* First fallback: Return the mail identity named
2888          *                 by the default mail account. */
2889
2890         source = e_source_registry_ref_default_mail_account (registry);
2891
2892         /* This should never be NULL, but just to be safe. */
2893         if (source != NULL) {
2894                 ESourceMailAccount *extension;
2895
2896                 extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
2897                 extension = e_source_get_extension (source, extension_name);
2898                 uid = e_source_mail_account_dup_identity_uid (extension);
2899
2900                 g_object_unref (source);
2901                 source = NULL;
2902         }
2903
2904         if (uid != NULL) {
2905                 source = e_source_registry_ref_source (registry, uid);
2906                 g_free (uid);
2907         }
2908
2909         if (source != NULL)
2910                 return source;
2911
2912         /* Second fallback: Pick any available mail identity,
2913          *                  preferring enabled identities. */
2914
2915         extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
2916         list = e_source_registry_list_sources (registry, extension_name);
2917
2918         for (link = list; link != NULL; link = g_list_next (link)) {
2919                 ESource *candidate = E_SOURCE (link->data);
2920
2921                 if (e_source_get_enabled (candidate)) {
2922                         source = g_object_ref (candidate);
2923                         break;
2924                 }
2925         }
2926
2927         if (source == NULL && list != NULL)
2928                 source = g_object_ref (list->data);
2929
2930         g_list_free_full (list, (GDestroyNotify) g_object_unref);
2931
2932         return source;
2933 }
2934
2935 /**
2936  * e_source_registry_ref_default_mail_identity:
2937  * @registry: an #ESourceRegistry
2938  *
2939  * Returns the #ESource most recently passed to
2940  * e_source_registry_set_default_mail_identity() either in this session
2941  * or a previous session, or else falls back to the mail identity named
2942  * by the default mail account.  If even that fails it returns any mail
2943  * identity from @registry, or %NULL if there are none.
2944  *
2945  * The returned #ESource is referenced for thread-safety and must be
2946  * unreferenced with g_object_unref() when finished with it.
2947  *
2948  * Returns: (transfer full): the default mail identity #ESource, or %NULL
2949  *
2950  * Since: 3.6
2951  **/
2952 ESource *
2953 e_source_registry_ref_default_mail_identity (ESourceRegistry *registry)
2954 {
2955         const gchar *key;
2956         ESource *source;
2957         gchar *uid;
2958
2959         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2960
2961         key = E_SETTINGS_DEFAULT_MAIL_IDENTITY_KEY;
2962         uid = g_settings_get_string (registry->priv->settings, key);
2963         source = e_source_registry_ref_source (registry, uid);
2964         g_free (uid);
2965
2966         if (source == NULL)
2967                 source = source_registry_ref_any_mail_identity (registry);
2968
2969         return source;
2970 }
2971
2972 /**
2973  * e_source_registry_set_default_mail_identity:
2974  * @registry: an #ESourceRegistry
2975  * @default_source: (allow-none): a mail identity #ESource, or %NULL
2976  *
2977  * Sets @default_source as the default mail identity.  If @default_source
2978  * is %NULL, the next request for the default mail identity will use the
2979  * fallbacks described in e_source_registry_get_default_mail_identity().
2980  *
2981  * Since: 3.6
2982  **/
2983 void
2984 e_source_registry_set_default_mail_identity (ESourceRegistry *registry,
2985                                              ESource *default_source)
2986 {
2987         const gchar *key;
2988         const gchar *uid;
2989
2990         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2991
2992         if (default_source != NULL) {
2993                 g_return_if_fail (E_IS_SOURCE (default_source));
2994                 uid = e_source_get_uid (default_source);
2995         } else {
2996                 uid = "";  /* no built-in mail identity */
2997         }
2998
2999         key = E_SETTINGS_DEFAULT_MAIL_IDENTITY_KEY;
3000         g_settings_set_string (registry->priv->settings, key, uid);
3001
3002         /* The GSettings::changed signal will trigger a "notify" signal
3003          * from the registry, so no need to call g_object_notify() here. */
3004 }
3005
3006 /**
3007  * e_source_registry_ref_builtin_memo_list:
3008  * @registry: an #ESourceRegistry
3009  *
3010  * Returns the built-in memo list #ESource.
3011  *
3012  * This #ESource is always present and makes for a safe fallback.
3013  *
3014  * The returned #ESource is referenced for thread-safety and must be
3015  * unreferenced with g_object_unref() when finished with it.
3016  *
3017  * Returns: (transfer full): the built-in memo list #ESource
3018  *
3019  * Since: 3.6
3020  **/
3021 ESource *
3022 e_source_registry_ref_builtin_memo_list (ESourceRegistry *registry)
3023 {
3024         ESource *source;
3025         const gchar *uid;
3026
3027         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3028
3029         uid = E_SOURCE_BUILTIN_MEMO_LIST_UID;
3030         source = e_source_registry_ref_source (registry, uid);
3031         g_return_val_if_fail (source != NULL, NULL);
3032
3033         return source;
3034 }
3035
3036 /**
3037  * e_source_registry_ref_default_memo_list:
3038  * @registry: an #ESourceRegistry
3039  *
3040  * Returns the #ESource most recently passed to
3041  * e_source_registry_set_default_memo_list() either in this session
3042  * or a previous session, or else falls back to the built-in memo list.
3043  *
3044  * The returned #ESource is referenced for thread-safety and must be
3045  * unreferenced with g_object_unref() when finished with it.
3046  *
3047  * Returns: (transfer full): the default memo list #ESource
3048  *
3049  * Since: 3.6
3050  **/
3051 ESource *
3052 e_source_registry_ref_default_memo_list (ESourceRegistry *registry)
3053 {
3054         const gchar *key;
3055         ESource *source;
3056         gchar *uid;
3057
3058         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3059
3060         key = E_SETTINGS_DEFAULT_MEMO_LIST_KEY;
3061         uid = g_settings_get_string (registry->priv->settings, key);
3062         source = e_source_registry_ref_source (registry, uid);
3063         g_free (uid);
3064
3065         /* The built-in source is always present. */
3066         if (source == NULL)
3067                 source = e_source_registry_ref_builtin_memo_list (registry);
3068
3069         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3070
3071         return source;
3072 }
3073
3074 /**
3075  * e_source_registry_set_default_memo_list:
3076  * @registry: an #ESourceRegistry
3077  * @default_source: (allow-none): a memo list #ESource, or %NULL
3078  *
3079  * Sets @default_source as the default memo list.  If @default_source
3080  * is %NULL, the default memo list is reset to the built-in memo list.
3081  * This setting will persist across sessions until changed.
3082  *
3083  * Since: 3.6
3084  **/
3085 void
3086 e_source_registry_set_default_memo_list (ESourceRegistry *registry,
3087                                          ESource *default_source)
3088 {
3089         const gchar *key;
3090         const gchar *uid;
3091
3092         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3093
3094         if (default_source != NULL) {
3095                 g_return_if_fail (E_IS_SOURCE (default_source));
3096                 uid = e_source_get_uid (default_source);
3097         } else {
3098                 uid = E_SOURCE_BUILTIN_MEMO_LIST_UID;
3099         }
3100
3101         key = E_SETTINGS_DEFAULT_MEMO_LIST_KEY;
3102         g_settings_set_string (registry->priv->settings, key, uid);
3103
3104         /* The GSettings::changed signal will trigger a "notify" signal
3105          * from the registry, so no need to call g_object_notify() here. */
3106 }
3107
3108 /**
3109  * e_source_registry_ref_builtin_task_list:
3110  * @registry: an #ESourceRegistry
3111  *
3112  * Returns the built-in task list #ESource.
3113  *
3114  * This #ESource is always present and makes for a safe fallback.
3115  *
3116  * The returned #ESource is referenced for thread-safety and must be
3117  * unreferenced with g_object_unref() when finished with it.
3118  *
3119  * Returns: (transfer full): the built-in task list #ESource
3120  *
3121  * Since: 3.6
3122  **/
3123 ESource *
3124 e_source_registry_ref_builtin_task_list (ESourceRegistry *registry)
3125 {
3126         ESource *source;
3127         const gchar *uid;
3128
3129         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3130
3131         uid = E_SOURCE_BUILTIN_TASK_LIST_UID;
3132         source = e_source_registry_ref_source (registry, uid);
3133         g_return_val_if_fail (source != NULL, NULL);
3134
3135         return source;
3136 }
3137
3138 /**
3139  * e_source_registry_ref_default_task_list:
3140  * @registry: an #ESourceRegistry
3141  *
3142  * Returns the #ESource most recently passed to
3143  * e_source_registry_set_default_task_list() either in this session
3144  * or a previous session, or else falls back to the built-in task list.
3145  *
3146  * The returned #ESource is referenced for thread-safety and must be
3147  * unreferenced with g_object_unref() when finished with it.
3148  *
3149  * Returns: (transfer full): the default task list #ESource
3150  *
3151  * Since: 3.6
3152  **/
3153 ESource *
3154 e_source_registry_ref_default_task_list (ESourceRegistry *registry)
3155 {
3156         const gchar *key;
3157         ESource *source;
3158         gchar *uid;
3159
3160         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3161
3162         key = E_SETTINGS_DEFAULT_TASK_LIST_KEY;
3163         uid = g_settings_get_string (registry->priv->settings, key);
3164         source = e_source_registry_ref_source (registry, uid);
3165         g_free (uid);
3166
3167         /* The built-in source is always present. */
3168         if (source == NULL)
3169                 source = e_source_registry_ref_builtin_task_list (registry);
3170
3171         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3172
3173         return source;
3174 }
3175
3176 /**
3177  * e_source_registry_set_default_task_list:
3178  * @registry: an #ESourceRegistry
3179  * @default_source: (allow-none): a task list #ESource, or %NULL
3180  *
3181  * Sets @default_source as the default task list.  If @default_source
3182  * is %NULL, the default task list is reset to the built-in task list.
3183  * This setting will persist across sessions until changed.
3184  *
3185  * Since: 3.6
3186  **/
3187 void
3188 e_source_registry_set_default_task_list (ESourceRegistry *registry,
3189                                          ESource *default_source)
3190 {
3191         const gchar *key;
3192         const gchar *uid;
3193
3194         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3195
3196         if (default_source != NULL) {
3197                 g_return_if_fail (E_IS_SOURCE (default_source));
3198                 uid = e_source_get_uid (default_source);
3199         } else {
3200                 uid = E_SOURCE_BUILTIN_TASK_LIST_UID;
3201         }
3202
3203         key = E_SETTINGS_DEFAULT_TASK_LIST_KEY;
3204         g_settings_set_string (registry->priv->settings, key, uid);
3205
3206         /* The GSettings::changed signal will trigger a "notify" signal
3207          * from the registry, so no need to call g_object_notify() here. */
3208 }
3209
3210 /**
3211  * e_source_registry_ref_default_for_extension_name:
3212  * @registry: an #ESourceRegistry
3213  * @extension_name: an extension_name
3214  *
3215  * This is a convenience function to return a default #ESource based on
3216  * @extension_name.  This only works with a subset of extension names.
3217  *
3218  * If @extension_name is #E_SOURCE_EXTENSION_ADDRESS_BOOK, the function
3219  * returns the current default address book, or else falls back to the
3220  * built-in address book.
3221  *
3222  * If @extension_name is #E_SOURCE_EXTENSION_CALENDAR, the function returns
3223  * the current default calendar, or else falls back to the built-in calendar.
3224  *
3225  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_ACCOUNT, the function
3226  * returns the current default mail account, or else falls back to the
3227  * built-in mail account.
3228  *
3229  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_IDENTITY, the function
3230  * returns the current default mail identity, or else falls back to the
3231  * mail identity named by the current default mail account.
3232  *
3233  * If @extension_name is #E_SOURCE_EXTENSION_MEMO_LIST, the function returns
3234  * the current default memo list, or else falls back to the built-in memo list.
3235  *
3236  * If @extension_name is #E_SOURCE_EXTENSION_TASK_LIST, the function returns
3237  * the current default task list, or else falls back to the built-in task list.
3238  *
3239  * For all other values of @extension_name, the function returns %NULL.
3240  *
3241  * The returned #ESource is referenced for thread-safety and must be
3242  * unreferenced with g_object_unref() when finished with it.
3243  *
3244  * Returns: (transfer full): the default #ESource based on @extension_name
3245  *
3246  * Since: 3.6
3247  **/
3248 ESource *
3249 e_source_registry_ref_default_for_extension_name (ESourceRegistry *registry,
3250                                                   const gchar *extension_name)
3251 {
3252         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3253         g_return_val_if_fail (extension_name != NULL, NULL);
3254
3255         if (strcmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0)
3256                 return e_source_registry_ref_default_address_book (registry);
3257
3258         if (strcmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0)
3259                 return e_source_registry_ref_default_calendar (registry);
3260
3261         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_ACCOUNT) == 0)
3262                 return e_source_registry_ref_default_mail_account (registry);
3263
3264         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_IDENTITY) == 0)
3265                 return e_source_registry_ref_default_mail_identity (registry);
3266
3267         if (strcmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0)
3268                 return e_source_registry_ref_default_memo_list (registry);
3269
3270         if (strcmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0)
3271                 return e_source_registry_ref_default_task_list (registry);
3272
3273         return NULL;
3274 }
3275
3276 /**
3277  * e_source_registry_set_default_for_extension_name:
3278  * @registry: an #ESourceRegistry
3279  * @extension_name: an extension name
3280  * @default_source: (allow-none): an #ESource, or %NULL
3281  *
3282  * This is a convenience function to set a default #ESource based on
3283  * @extension_name.  This only works with a subset of extension names.
3284  *
3285  * If @extension_name is #E_SOURCE_EXTENSION_ADDRESS_BOOK, the function
3286  * sets @default_source as the default address book.  If @default_source
3287  * is %NULL, the default address book is reset to the built-in address book.
3288  *
3289  * If @extension_name is #E_SOURCE_EXTENSION_CALENDAR, the function sets
3290  * @default_source as the default calendar.  If @default_source is %NULL,
3291  * the default calendar is reset to the built-in calendar.
3292  *
3293  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_ACCOUNT, the function
3294  * sets @default_source as the default mail account.  If @default_source
3295  * is %NULL, the default mail account is reset to the built-in mail account.
3296  *
3297  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_IDENTITY, the function
3298  * sets @default_source as the default mail identity.  If @default_source
3299  * is %NULL, the next request for the default mail identity will return
3300  * the mail identity named by the default mail account.
3301  *
3302  * If @extension_name is #E_SOURCE_EXTENSION_MEMO_LIST, the function sets
3303  * @default_source as the default memo list.  If @default_source is %NULL,
3304  * the default memo list is reset to the built-in memo list.
3305  *
3306  * If @extension_name is #E_SOURCE_EXTENSION_TASK_LIST, the function sets
3307  * @default_source as the default task list.  If @default_source is %NULL,
3308  * the default task list is reset to the built-in task list.
3309  *
3310  * For all other values of @extension_name, the function does nothing.
3311  *
3312  * Since: 3.6
3313  **/
3314 void
3315 e_source_registry_set_default_for_extension_name (ESourceRegistry *registry,
3316                                                   const gchar *extension_name,
3317                                                   ESource *default_source)
3318 {
3319         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3320         g_return_if_fail (extension_name != NULL);
3321
3322         if (strcmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0)
3323                 e_source_registry_set_default_address_book (
3324                         registry, default_source);
3325
3326         if (strcmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0)
3327                 e_source_registry_set_default_calendar (
3328                         registry, default_source);
3329
3330         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_ACCOUNT) == 0)
3331                 e_source_registry_set_default_mail_account (
3332                         registry, default_source);
3333
3334         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_IDENTITY) == 0)
3335                 e_source_registry_set_default_mail_identity (
3336                         registry, default_source);
3337
3338         if (strcmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0)
3339                 e_source_registry_set_default_memo_list (
3340                         registry, default_source);
3341
3342         if (strcmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0)
3343                 e_source_registry_set_default_task_list (
3344                         registry, default_source);
3345 }
3346