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