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