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