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