3077f579af6ba6747e4ee4aa794f8208ca6ae5ae
[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         g_warn_if_fail (g_hash_table_size (registry->priv->sources) > 0);
1066
1067         /* The EDBusSourceManagerProxy is just another D-Bus interface
1068          * that resides at the same object path.  It's unrelated to the
1069          * GDBusObjectManagerClient and doesn't need its own thread. */
1070         registry->priv->dbus_source_manager =
1071                 e_dbus_source_manager_proxy_new_for_bus_sync (
1072                         G_BUS_TYPE_SESSION,
1073                         G_DBUS_PROXY_FLAGS_NONE,
1074                         SOURCES_DBUS_SERVICE_NAME,
1075                         DBUS_OBJECT_PATH,
1076                         cancellable, error);
1077
1078         if (registry->priv->dbus_source_manager == NULL)
1079                 return FALSE;
1080
1081         /* Allow authentication prompts for all exported data sources
1082          * when a new EDBusSourceManagerProxy is created.  The thought
1083          * being, if you cancel an authentication prompt you will not
1084          * be bothered again until you start (or restart) a new E-D-S
1085          * client app.  Failure here is non-fatal, ignore errors. */
1086         e_dbus_source_manager_call_allow_auth_prompt_all_sync (
1087                 registry->priv->dbus_source_manager, cancellable, NULL);
1088
1089         return TRUE;
1090 }
1091
1092 static void
1093 e_source_registry_class_init (ESourceRegistryClass *class)
1094 {
1095         GObjectClass *object_class;
1096
1097         g_type_class_add_private (class, sizeof (ESourceRegistryPrivate));
1098
1099         object_class = G_OBJECT_CLASS (class);
1100         object_class->set_property = source_registry_set_property;
1101         object_class->get_property = source_registry_get_property;
1102         object_class->dispose = source_registry_dispose;
1103         object_class->finalize = source_registry_finalize;
1104
1105         /* The property names correspond to the key names in the
1106          * "org.gnome.Evolution.DefaultSources" GSettings schema. */
1107
1108         /**
1109          * ESourceRegistry:default-address-book:
1110          *
1111          * The default address book #ESource.
1112          **/
1113         g_object_class_install_property (
1114                 object_class,
1115                 PROP_DEFAULT_ADDRESS_BOOK,
1116                 g_param_spec_object (
1117                         "default-address-book",
1118                         "Default Address Book",
1119                         "The default address book ESource",
1120                         E_TYPE_SOURCE,
1121                         G_PARAM_READWRITE |
1122                         G_PARAM_STATIC_STRINGS));
1123
1124         /**
1125          * ESourceRegistry:default-calendar:
1126          *
1127          * The default calendar #ESource.
1128          **/
1129         g_object_class_install_property (
1130                 object_class,
1131                 PROP_DEFAULT_CALENDAR,
1132                 g_param_spec_object (
1133                         "default-calendar",
1134                         "Default Calendar",
1135                         "The default calendar ESource",
1136                         E_TYPE_SOURCE,
1137                         G_PARAM_READWRITE |
1138                         G_PARAM_STATIC_STRINGS));
1139
1140         /**
1141          * ESourceRegistry:default-mail-account:
1142          *
1143          * The default mail account #ESource.
1144          **/
1145         g_object_class_install_property (
1146                 object_class,
1147                 PROP_DEFAULT_MAIL_ACCOUNT,
1148                 g_param_spec_object (
1149                         "default-mail-account",
1150                         "Default Mail Account",
1151                         "The default mail account ESource",
1152                         E_TYPE_SOURCE,
1153                         G_PARAM_READWRITE |
1154                         G_PARAM_STATIC_STRINGS));
1155
1156         /**
1157          * ESourceRegistry:default-mail-identity:
1158          *
1159          * The default mail identity #ESource.
1160          **/
1161         g_object_class_install_property (
1162                 object_class,
1163                 PROP_DEFAULT_MAIL_IDENTITY,
1164                 g_param_spec_object (
1165                         "default-mail-identity",
1166                         "Default Mail Identity",
1167                         "The default mail identity ESource",
1168                         E_TYPE_SOURCE,
1169                         G_PARAM_READWRITE |
1170                         G_PARAM_STATIC_STRINGS));
1171
1172         /**
1173          * ESourceRegistry:default-memo-list:
1174          *
1175          * The default memo list #ESource.
1176          **/
1177         g_object_class_install_property (
1178                 object_class,
1179                 PROP_DEFAULT_MEMO_LIST,
1180                 g_param_spec_object (
1181                         "default-memo-list",
1182                         "Default Memo List",
1183                         "The default memo list ESource",
1184                         E_TYPE_SOURCE,
1185                         G_PARAM_READWRITE |
1186                         G_PARAM_STATIC_STRINGS));
1187
1188         /**
1189          * ESourceRegistry:default-task-list:
1190          *
1191          * The default task list #ESource.
1192          **/
1193         g_object_class_install_property (
1194                 object_class,
1195                 PROP_DEFAULT_TASK_LIST,
1196                 g_param_spec_object (
1197                         "default-task-list",
1198                         "Default Task List",
1199                         "The default task list ESource",
1200                         E_TYPE_SOURCE,
1201                         G_PARAM_READWRITE |
1202                         G_PARAM_STATIC_STRINGS));
1203
1204         /**
1205          * ESourceRegistry::source-added:
1206          * @registry: the #ESourceRegistry which emitted the signal
1207          * @source: the newly-added #ESource
1208          *
1209          * Emitted when an #ESource is added to @registry.
1210          **/
1211         signals[SOURCE_ADDED] = g_signal_new (
1212                 "source-added",
1213                 G_OBJECT_CLASS_TYPE (object_class),
1214                 G_SIGNAL_RUN_LAST,
1215                 G_STRUCT_OFFSET (ESourceRegistryClass, source_added),
1216                 NULL, NULL,
1217                 g_cclosure_marshal_VOID__OBJECT,
1218                 G_TYPE_NONE, 1,
1219                 E_TYPE_SOURCE);
1220
1221         /**
1222          * ESourceRegistry::source-changed:
1223          * @registry: the #ESourceRegistry which emitted the signal
1224          * @source: the #ESource that changed
1225          *
1226          * Emitted when an #ESource registered with @registry emits
1227          * its #ESource::changed signal.
1228          **/
1229         signals[SOURCE_CHANGED] = g_signal_new (
1230                 "source-changed",
1231                 G_OBJECT_CLASS_TYPE (object_class),
1232                 G_SIGNAL_RUN_LAST,
1233                 G_STRUCT_OFFSET (ESourceRegistryClass, source_changed),
1234                 NULL, NULL,
1235                 g_cclosure_marshal_VOID__OBJECT,
1236                 G_TYPE_NONE, 1,
1237                 E_TYPE_SOURCE);
1238
1239         /**
1240          * ESourceRegistry::source-removed:
1241          * @registry: the #ESourceRegistry which emitted the signal
1242          * @source: the #ESource that got removed
1243          *
1244          * Emitted when an #ESource is removed from @registry.
1245          **/
1246         signals[SOURCE_REMOVED] = g_signal_new (
1247                 "source-removed",
1248                 G_OBJECT_CLASS_TYPE (object_class),
1249                 G_SIGNAL_RUN_LAST,
1250                 G_STRUCT_OFFSET (ESourceRegistryClass, source_removed),
1251                 NULL, NULL,
1252                 g_cclosure_marshal_VOID__OBJECT,
1253                 G_TYPE_NONE, 1,
1254                 E_TYPE_SOURCE);
1255
1256         /**
1257          * ESourceRegistry::source-enabled:
1258          * @registry: the #ESourceRegistry which emitted the signal
1259          * @source: the #ESource that got enabled
1260          *
1261          * Emitted when an #ESource #ESource:enabled property becomes %TRUE.
1262          **/
1263         signals[SOURCE_ENABLED] = g_signal_new (
1264                 "source-enabled",
1265                 G_OBJECT_CLASS_TYPE (object_class),
1266                 G_SIGNAL_RUN_LAST,
1267                 G_STRUCT_OFFSET (ESourceRegistryClass, source_enabled),
1268                 NULL, NULL,
1269                 g_cclosure_marshal_VOID__OBJECT,
1270                 G_TYPE_NONE, 1,
1271                 E_TYPE_SOURCE);
1272
1273         /**
1274          * ESourceRegistry::source-disabled:
1275          * @registry: the #ESourceRegistry which emitted the signal
1276          * @source: the #ESource that got disabled
1277          *
1278          * Emitted when an #ESource #ESource:enabled property becomes %FALSE.
1279          **/
1280         signals[SOURCE_DISABLED] = g_signal_new (
1281                 "source-disabled",
1282                 G_OBJECT_CLASS_TYPE (object_class),
1283                 G_SIGNAL_RUN_LAST,
1284                 G_STRUCT_OFFSET (ESourceRegistryClass, source_disabled),
1285                 NULL, NULL,
1286                 g_cclosure_marshal_VOID__OBJECT,
1287                 G_TYPE_NONE, 1,
1288                 E_TYPE_SOURCE);
1289 }
1290
1291 static void
1292 e_source_registry_initable_init (GInitableIface *interface)
1293 {
1294         interface->init = source_registry_initable_init;
1295 }
1296
1297 static void
1298 e_source_registry_init (ESourceRegistry *registry)
1299 {
1300         registry->priv = E_SOURCE_REGISTRY_GET_PRIVATE (registry);
1301
1302         /* This is so the object manager thread can schedule signal
1303          * emissions on the thread-default context for this thread. */
1304         registry->priv->main_context = g_main_context_ref_thread_default ();
1305
1306         /* D-Bus object path -> ESource */
1307         registry->priv->object_path_table =
1308                 g_hash_table_new_full (
1309                         (GHashFunc) g_str_hash,
1310                         (GEqualFunc) g_str_equal,
1311                         (GDestroyNotify) g_free,
1312                         (GDestroyNotify) g_object_unref);
1313
1314         g_mutex_init (&registry->priv->object_path_table_lock);
1315
1316         /* UID string -> ESource */
1317         registry->priv->sources = g_hash_table_new_full (
1318                 (GHashFunc) g_str_hash,
1319                 (GEqualFunc) g_str_equal,
1320                 (GDestroyNotify) g_free,
1321                 (GDestroyNotify) source_registry_unref_source);
1322
1323         g_mutex_init (&registry->priv->sources_lock);
1324
1325         registry->priv->settings = g_settings_new (GSETTINGS_SCHEMA);
1326
1327         g_signal_connect (
1328                 registry->priv->settings, "changed",
1329                 G_CALLBACK (source_registry_settings_changed_cb), registry);
1330 }
1331
1332 /**
1333  * e_source_registry_new_sync:
1334  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1335  * @error: return location for a #GError, or %NULL
1336  *
1337  * Creates a new #ESourceRegistry front-end for the registry D-Bus service.
1338  * If an error occurs in connecting to the D-Bus service, the function sets
1339  * @error and returns %NULL.
1340  *
1341  * Returns: a new #ESourceRegistry, or %NULL
1342  *
1343  * Since: 3.6
1344  **/
1345 ESourceRegistry *
1346 e_source_registry_new_sync (GCancellable *cancellable,
1347                             GError **error)
1348 {
1349         /* XXX Work around http://bugzilla.gnome.org/show_bug.cgi?id=683519
1350          *     until GObject's type initialization deadlock issue is fixed.
1351          *     Apparently only the synchronous instantiation is affected. */
1352         REGISTER_TYPE (G_TYPE_DBUS_CONNECTION);
1353
1354         return g_initable_new (
1355                 E_TYPE_SOURCE_REGISTRY,
1356                 cancellable, error, NULL);
1357 }
1358
1359 /**
1360  * e_source_registry_new:
1361  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1362  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1363  *            is satisfied
1364  * @user_data: (closure): data to pass to the callback function
1365  *
1366  * Asynchronously creates a new #ESourceRegistry front-end for the registry
1367  * D-Bus service.
1368  *
1369  * When the operation is finished, @callback will be called.  You can then
1370  * call e_source_registry_new_finish() to get the result of the operation.
1371  *
1372  * Since: 3.6
1373  **/
1374 void
1375 e_source_registry_new (GCancellable *cancellable,
1376                        GAsyncReadyCallback callback,
1377                        gpointer user_data)
1378 {
1379         g_async_initable_new_async (
1380                 E_TYPE_SOURCE_REGISTRY,
1381                 G_PRIORITY_DEFAULT, cancellable,
1382                 callback, user_data, NULL);
1383 }
1384
1385 /**
1386  * e_source_registry_new_finish:
1387  * @result: a #GAsyncResult
1388  * @error: return location for a #GError, or %NULL
1389  *
1390  * Finishes the operation started with e_source_registry_new_finish().
1391  * If an error occurs in connecting to the D-Bus service, the function
1392  * sets @error and returns %NULL.
1393  *
1394  * Returns: a new #ESourceRegistry, or %NULL
1395  *
1396  * Since: 3.6
1397  **/
1398 ESourceRegistry *
1399 e_source_registry_new_finish (GAsyncResult *result,
1400                               GError **error)
1401 {
1402         GObject *source_object;
1403         GObject *object;
1404
1405         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1406
1407         source_object = g_async_result_get_source_object (result);
1408         g_return_val_if_fail (source_object != NULL, NULL);
1409
1410         object = g_async_initable_new_finish (
1411                 G_ASYNC_INITABLE (source_object), result, error);
1412
1413         g_object_unref (source_object);
1414
1415         return (object != NULL) ? E_SOURCE_REGISTRY (object) : NULL;
1416 }
1417
1418 /* Helper for e_source_registry_authenticate() */
1419 static void
1420 source_registry_authenticate_thread (GSimpleAsyncResult *simple,
1421                                      GObject *object,
1422                                      GCancellable *cancellable)
1423 {
1424         AsyncContext *async_context;
1425         GError *error = NULL;
1426
1427         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1428
1429         e_source_registry_authenticate_sync (
1430                 E_SOURCE_REGISTRY (object),
1431                 async_context->source,
1432                 async_context->auth,
1433                 cancellable, &error);
1434
1435         if (error != NULL)
1436                 g_simple_async_result_take_error (simple, error);
1437 }
1438
1439 /* Helper for e_source_registry_authenticate_sync() */
1440 static gboolean
1441 source_registry_authenticate_respond_cb (AuthContext *auth_context)
1442 {
1443         ESourceAuthenticationResult auth_result;
1444         GError *non_fatal_error = NULL;
1445
1446         g_return_val_if_fail (auth_context->authenticating, FALSE);
1447
1448         auth_result = auth_context->auth_result;
1449
1450         /* Allow the next authentication attempt to proceed. */
1451         auth_context->authenticating = FALSE;
1452
1453         /* Send the server a status update based on the authentication
1454          * result.  Note, we don't really care if the D-Bus message gets
1455          * through to the server at this point.  If it doesn't, the auth
1456          * session will either time out on its own or the authentication
1457          * dialog will eventually be dismissed by the user. */
1458
1459         /* If we were cancelled from our side, we have a bit of a dilemma.
1460          * We need to tell the server to cancel the authentication session,
1461          * but that involves making a synchronous D-Bus call, which we are
1462          * not supposed to do if we know we've been cancelled.  But if we
1463          * don't tell the server, the authentication session will be left
1464          * to timeout on its own (which may take minutes), and meanwhile
1465          * all other authentication requests are blocked.  So choose the
1466          * lesser evil and make the synchronous call but without passing
1467          * the already-cancelled GCancellable. */
1468         if (g_cancellable_is_cancelled (auth_context->cancellable)) {
1469                 e_dbus_authenticator_call_cancel_sync (
1470                         auth_context->dbus_auth,
1471                         NULL, &non_fatal_error);
1472                 g_main_loop_quit (auth_context->main_loop);
1473                 auth_context->success = FALSE;
1474
1475         /* If an error occurred while attempting to authenticate,
1476          * tell the server to cancel the authentication session. */
1477         } else if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
1478                 e_dbus_authenticator_call_cancel_sync (
1479                         auth_context->dbus_auth,
1480                         auth_context->cancellable,
1481                         &non_fatal_error);
1482                 g_main_loop_quit (auth_context->main_loop);
1483                 auth_context->success = FALSE;
1484
1485         /* If the password was accepted, let the server know so it
1486          * can close any authentication dialogs and save the user
1487          * provided password to the keyring. */
1488         } else if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
1489                 e_dbus_authenticator_call_accepted_sync (
1490                         auth_context->dbus_auth,
1491                         auth_context->cancellable,
1492                         &non_fatal_error);
1493                 g_main_loop_quit (auth_context->main_loop);
1494                 auth_context->success = TRUE;
1495
1496         /* If the password was rejected, let the server know so it can
1497          * indicate failure and request a different password, and then
1498          * wait for the next "response" signal. */
1499         } else {
1500                 e_dbus_authenticator_call_rejected_sync (
1501                         auth_context->dbus_auth,
1502                         auth_context->cancellable,
1503                         &non_fatal_error);
1504         }
1505
1506         /* Leave breadcrumbs if something went wrong,
1507          * but don't fail the whole operation over it. */
1508         if (non_fatal_error != NULL) {
1509                 g_warning ("%s: %s", G_STRFUNC, non_fatal_error->message);
1510                 g_error_free (non_fatal_error);
1511         }
1512
1513         return FALSE;
1514 }
1515
1516 /* Helper for e_source_registry_authenticate_sync() */
1517 static void
1518 source_registry_authenticate_authenticate_cb (EDBusAuthenticator *dbus_auth,
1519                                               const gchar *encrypted_secret,
1520                                               AuthContext *auth_context)
1521 {
1522         GSource *idle_source;
1523         GMainContext *main_context;
1524         GString *password;
1525         gboolean valid_secret;
1526
1527         /* We should only get one secret at a time. */
1528         g_return_if_fail (!auth_context->authenticating);
1529
1530         valid_secret = gcr_secret_exchange_receive (
1531                 auth_context->secret_exchange, encrypted_secret);
1532         g_return_if_fail (valid_secret);
1533
1534         auth_context->authenticating = TRUE;
1535
1536         /* This avoids revealing the password in a stack trace. */
1537         password = g_string_new (
1538                 gcr_secret_exchange_get_secret (
1539                 auth_context->secret_exchange, NULL));
1540
1541         /* Try authenticating with the given password.  We have to
1542          * call this synchronously because some authenticators use
1543          * mutexes to serialize I/O operations and are not prepared
1544          * to make authentication attempts from a different thread.
1545          *
1546          * Unfortunately this means we won't notice server-side
1547          * dismissals while the main loop is blocked.  We respond
1548          * to the server from a low-priority idle callback so that
1549          * any pending "dismissed" signals get handled first. */
1550
1551         auth_context->auth_result =
1552                 e_source_authenticator_try_password_sync (
1553                         auth_context->auth, password,
1554                         auth_context->cancellable,
1555                         auth_context->error);
1556
1557         idle_source = g_idle_source_new ();
1558         main_context = g_main_context_get_thread_default ();
1559         g_source_set_callback (
1560                 idle_source, (GSourceFunc)
1561                 source_registry_authenticate_respond_cb,
1562                 auth_context, NULL);
1563         g_source_attach (idle_source, main_context);
1564         g_source_unref (idle_source);
1565
1566         g_string_free (password, TRUE);
1567 }
1568
1569 /* Helper for e_source_registry_authenticate_sync() */
1570 static void
1571 source_registry_authenticate_dismissed_cb (EDBusAuthenticator *dbus_auth,
1572                                            AuthContext *auth_context)
1573 {
1574         /* Be careful not to overwrite an existing error in case this
1575          * is called after e_source_authenticator_try_password_sync()
1576          * but prior to the idle callback. */
1577         if (auth_context->auth_result != E_SOURCE_AUTHENTICATION_ERROR) {
1578                 /* XXX Use a separate error code for dismissals? */
1579                 g_set_error_literal (
1580                         auth_context->error,
1581                         G_IO_ERROR, G_IO_ERROR_CANCELLED,
1582                         _("The user declined to authenticate"));
1583                 auth_context->auth_result = E_SOURCE_AUTHENTICATION_ERROR;
1584         }
1585
1586         g_main_loop_quit (auth_context->main_loop);
1587         auth_context->success = FALSE;
1588 }
1589
1590 /* Helper for e_source_registry_authenticate_sync() */
1591 static gboolean
1592 source_registry_call_authenticate_for_source (ESourceRegistry *registry,
1593                                               ESourceAuthenticator *auth,
1594                                               ESource *source,
1595                                               gchar **out_object_path,
1596                                               GCancellable *cancellable,
1597                                               GError **error)
1598 {
1599         ESource *collection;
1600         const gchar *uid;
1601         gchar *prompt_title = NULL;
1602         gchar *prompt_message = NULL;
1603         gchar *prompt_description = NULL;
1604         gboolean success;
1605
1606         /* If the source is a member of a collection, we want to store
1607          * the password under the UID of the "collection" source so it
1608          * will apply to the entire collection.
1609          *
1610          * XXX This assumes all sources in a collection share a single
1611          *     password.  If that turns out not to be true in all cases
1612          *     we could maybe add a "SharedPassword: true/false" key to
1613          *     [Collection] and apply it here.
1614          */
1615         collection = e_source_registry_find_extension (
1616                 registry, source, E_SOURCE_EXTENSION_COLLECTION);
1617         if (collection != NULL)
1618                 source = collection;
1619         else
1620                 g_object_ref (source);
1621
1622         uid = e_source_get_uid (source);
1623
1624         e_source_authenticator_get_prompt_strings (
1625                 auth, source,
1626                 &prompt_title,
1627                 &prompt_message,
1628                 &prompt_description);
1629
1630         success = e_dbus_source_manager_call_authenticate_sync (
1631                 registry->priv->dbus_source_manager, uid,
1632                 prompt_title, prompt_message, prompt_description,
1633                 out_object_path, cancellable, error);
1634
1635         g_free (prompt_title);
1636         g_free (prompt_message);
1637         g_free (prompt_description);
1638
1639         g_object_unref (source);
1640
1641         return success;
1642 }
1643
1644 /**
1645  * e_source_registry_authenticate_sync:
1646  * @registry: an #ESourceRegistry
1647  * @source: an #ESource
1648  * @auth: an #ESourceAuthenticator
1649  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1650  * @error: return location for a #GError, or %NULL
1651  *
1652  * Authenticates @source, using @auth to handle the authentication
1653  * attempts.  The operation loops until authentication is successful or
1654  * the user aborts further authentication attempts.  If an error occurs,
1655  * the function will set @error and return %FALSE.
1656  *
1657  * Note that @source need not have a #GDBusObject, which means this
1658  * function can test authentication on a scratch #ESource.
1659  *
1660  * Only backend implementations and data source editors should call this
1661  * function.  The intent is for basic client applications to not have to
1662  * deal with authentication at all.
1663  *
1664  * Returns: %TRUE on success, %FALSE on failure
1665  *
1666  * Since: 3.6
1667  **/
1668 gboolean
1669 e_source_registry_authenticate_sync (ESourceRegistry *registry,
1670                                      ESource *source,
1671                                      ESourceAuthenticator *auth,
1672                                      GCancellable *cancellable,
1673                                      GError **error)
1674 {
1675         AuthContext *auth_context;
1676         GMainContext *main_context;
1677         EDBusAuthenticator *dbus_auth;
1678         gchar *encryption_key;
1679         gchar *object_path = NULL;
1680         gboolean success;
1681
1682         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1683         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1684         g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth), FALSE);
1685
1686         /* This extracts authentication prompt details for the ESource
1687          * before initiating an authentication session with the server,
1688          * so split it out of the main algorithm for clarity's sake. */
1689         success = source_registry_call_authenticate_for_source (
1690                 registry, auth, source, &object_path, cancellable, error);
1691
1692         if (!success) {
1693                 g_warn_if_fail (object_path == NULL);
1694                 return FALSE;
1695         }
1696
1697         g_return_val_if_fail (object_path != NULL, FALSE);
1698
1699         main_context = g_main_context_new ();
1700         g_main_context_push_thread_default (main_context);
1701
1702         dbus_auth = e_dbus_authenticator_proxy_new_for_bus_sync (
1703                 G_BUS_TYPE_SESSION,
1704                 G_DBUS_PROXY_FLAGS_NONE,
1705                 SOURCES_DBUS_SERVICE_NAME,
1706                 object_path, cancellable, error);
1707
1708         g_free (object_path);
1709
1710         if (dbus_auth == NULL) {
1711                 success = FALSE;
1712                 goto exit;
1713         }
1714
1715         auth_context = g_slice_new0 (AuthContext);
1716         auth_context->auth = g_object_ref (auth);
1717         auth_context->dbus_auth = dbus_auth;  /* takes ownership */
1718         auth_context->main_loop = g_main_loop_new (main_context, FALSE);
1719         auth_context->error = error;
1720
1721         /* This just needs to be something other than
1722          * E_SOURCE_AUTHENTICATION_ERROR so we don't trip
1723          * up source_registry_authenticate_dismissed_cb(). */
1724         auth_context->auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
1725
1726         if (G_IS_CANCELLABLE (cancellable))
1727                 auth_context->cancellable = g_object_ref (cancellable);
1728
1729         auth_context->secret_exchange =
1730                 gcr_secret_exchange_new (GCR_SECRET_EXCHANGE_PROTOCOL_1);
1731
1732         g_signal_connect (
1733                 dbus_auth, "authenticate",
1734                 G_CALLBACK (source_registry_authenticate_authenticate_cb),
1735                 auth_context);
1736
1737         g_signal_connect (
1738                 dbus_auth, "dismissed",
1739                 G_CALLBACK (source_registry_authenticate_dismissed_cb),
1740                 auth_context);
1741
1742         encryption_key = gcr_secret_exchange_begin (
1743                 auth_context->secret_exchange);
1744
1745         /* Signal the D-Bus server that we're ready to begin the
1746          * authentication session.  This must happen AFTER we've
1747          * connected to the response signal since the server may
1748          * already have a response ready and waiting for us. */
1749         success = e_dbus_authenticator_call_ready_sync (
1750                 dbus_auth, encryption_key, cancellable, error);
1751
1752         g_free (encryption_key);
1753
1754         if (success) {
1755                 g_main_loop_run (auth_context->main_loop);
1756                 success = auth_context->success;
1757         }
1758
1759         auth_context_free (auth_context);
1760
1761 exit:
1762         g_main_context_pop_thread_default (main_context);
1763         g_main_context_unref (main_context);
1764
1765         return success;
1766 }
1767
1768 /**
1769  * e_source_registry_authenticate:
1770  * @registry: an #ESourceRegistry
1771  * @source: an #ESource
1772  * @auth: an #ESourceAuthenticator
1773  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1774  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1775  *            is satisfied
1776  * @user_data: (closure): data to pass to the callback function
1777  *
1778  * Asynchronously authenticates @source, using @auth to handle the
1779  * authentication attempts.  The operation loops until authentication
1780  * is successful or the user aborts further authentication attempts.
1781  *
1782  * Note that @source need not have a #GDBusObject, which means this
1783  * function can test authentication on a scratch #ESource.
1784  *
1785  * When the operation is finished, @callback will be called.  You can then
1786  * call e_source_registry_authenticate_finish() to get the result of the
1787  * operation.
1788  *
1789  * Only backend implementations and data source editors should call this
1790  * function.  The intent is for basic client applications to not have to
1791  * deal with authentication at all.
1792  *
1793  * Since: 3.6
1794  **/
1795 void
1796 e_source_registry_authenticate (ESourceRegistry *registry,
1797                                 ESource *source,
1798                                 ESourceAuthenticator *auth,
1799                                 GCancellable *cancellable,
1800                                 GAsyncReadyCallback callback,
1801                                 gpointer user_data)
1802 {
1803         GSimpleAsyncResult *simple;
1804         AsyncContext *async_context;
1805
1806         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
1807         g_return_if_fail (E_IS_SOURCE (source));
1808         g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
1809
1810         async_context = g_slice_new0 (AsyncContext);
1811         async_context->source = g_object_ref (source);
1812         async_context->auth = g_object_ref (auth);
1813
1814         simple = g_simple_async_result_new (
1815                 G_OBJECT (registry), callback, user_data,
1816                 e_source_registry_authenticate);
1817
1818         g_simple_async_result_set_check_cancellable (simple, cancellable);
1819
1820         g_simple_async_result_set_op_res_gpointer (
1821                 simple, async_context, (GDestroyNotify) async_context_free);
1822
1823         g_simple_async_result_run_in_thread (
1824                 simple, source_registry_authenticate_thread,
1825                 G_PRIORITY_DEFAULT, cancellable);
1826
1827         g_object_unref (simple);
1828 }
1829
1830 /**
1831  * e_source_registry_authenticate_finish:
1832  * @registry: an #ESourceRegistry
1833  * @result: a #GAsyncResult
1834  * @error: return location for a #GError, or %NULL
1835  *
1836  * Finishes the operation started with e_source_registry_authenticate().
1837  * If an error occurred, the function will set @error and return %FALSE.
1838  *
1839  * Returns: %TRUE on success, %FALSE on failure
1840  *
1841  * Since: 3.6
1842  **/
1843 gboolean
1844 e_source_registry_authenticate_finish (ESourceRegistry *registry,
1845                                        GAsyncResult *result,
1846                                        GError **error)
1847 {
1848         GSimpleAsyncResult *simple;
1849
1850         g_return_val_if_fail (
1851                 g_simple_async_result_is_valid (
1852                 result, G_OBJECT (registry),
1853                 e_source_registry_authenticate), FALSE);
1854
1855         simple = G_SIMPLE_ASYNC_RESULT (result);
1856
1857         /* Assume success unless a GError is set. */
1858         return !g_simple_async_result_propagate_error (simple, error);
1859 }
1860
1861 /* Helper for e_source_registry_commit_source() */
1862 static void
1863 source_registry_commit_source_thread (GSimpleAsyncResult *simple,
1864                                       GObject *object,
1865                                       GCancellable *cancellable)
1866 {
1867         AsyncContext *async_context;
1868         GError *error = NULL;
1869
1870         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1871
1872         e_source_registry_commit_source_sync (
1873                 E_SOURCE_REGISTRY (object),
1874                 async_context->source,
1875                 cancellable, &error);
1876
1877         if (error != NULL)
1878                 g_simple_async_result_take_error (simple, error);
1879 }
1880
1881 /**
1882  * e_source_registry_commit_source_sync:
1883  * @registry: an #ESourceRegistry
1884  * @source: an #ESource with changes to commit
1885  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1886  * @error: return location for #GError, or %NULL
1887  *
1888  * This is a convenience function intended for use with graphical
1889  * #ESource editors.  Call this function when the user is finished
1890  * making changes to @source.
1891  *
1892  * If @source has a #GDBusObject, its contents are submitted to the D-Bus
1893  * service through e_source_write_sync().
1894  *
1895  * If @source does NOT have a #GDBusObject (implying it's a scratch
1896  * #ESource), its contents are submitted to the D-Bus service through
1897  * either e_source_remote_create_sync() if @source is to be a collection
1898  * member, or e_source_registry_create_sources_sync() if @source to be an
1899  * independent data source.
1900  *
1901  * If an error occurs, the function will set @error and return %FALSE.
1902  *
1903  * Returns: %TRUE on success, %FALSE on failure
1904  *
1905  * Since: 3.6
1906  **/
1907 gboolean
1908 e_source_registry_commit_source_sync (ESourceRegistry *registry,
1909                                       ESource *source,
1910                                       GCancellable *cancellable,
1911                                       GError **error)
1912 {
1913         GDBusObject *dbus_object;
1914         ESource *collection_source;
1915         gboolean collection_member;
1916         gboolean success;
1917
1918         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
1919         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1920
1921         dbus_object = e_source_ref_dbus_object (source);
1922
1923         collection_source = e_source_registry_find_extension (
1924                 registry, source, E_SOURCE_EXTENSION_COLLECTION);
1925
1926         collection_member =
1927                 (collection_source != NULL) &&
1928                 (collection_source != source);
1929
1930         if (dbus_object != NULL) {
1931                 success = e_source_write_sync (source, cancellable, error);
1932                 g_object_unref (dbus_object);
1933
1934         } else if (collection_member) {
1935                 success = e_source_remote_create_sync (
1936                         collection_source, source, cancellable, error);
1937
1938         } else {
1939                 GList *list = g_list_prepend (NULL, source);
1940                 success = e_source_registry_create_sources_sync (
1941                         registry, list, cancellable, error);
1942                 g_list_free (list);
1943         }
1944
1945         if (collection_source != NULL)
1946                 g_object_unref (collection_source);
1947
1948         return success;
1949 }
1950
1951 /**
1952  * e_source_registry_commit_source:
1953  * @registry: an #ESourceRegistry
1954  * @source: an #ESource with changes to commit
1955  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1956  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1957  *            is satisfied
1958  * @user_data: (closure): data to pass to the callback function
1959  *
1960  * See e_source_registry_commit_source_sync() for details.
1961  *
1962  * When the operation is finished, @callback will be called.  You can then
1963  * call e_source_registry_commit_source_finish() to get the result of the
1964  * operation.
1965  *
1966  * Since: 3.6
1967  **/
1968 void
1969 e_source_registry_commit_source (ESourceRegistry *registry,
1970                                  ESource *source,
1971                                  GCancellable *cancellable,
1972                                  GAsyncReadyCallback callback,
1973                                  gpointer user_data)
1974 {
1975         GSimpleAsyncResult *simple;
1976         AsyncContext *async_context;
1977
1978         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
1979         g_return_if_fail (E_IS_SOURCE (source));
1980
1981         async_context = g_slice_new0 (AsyncContext);
1982         async_context->source = g_object_ref (source);
1983
1984         simple = g_simple_async_result_new (
1985                 G_OBJECT (registry), callback, user_data,
1986                 e_source_registry_commit_source);
1987
1988         g_simple_async_result_set_check_cancellable (simple, cancellable);
1989
1990         g_simple_async_result_set_op_res_gpointer (
1991                 simple, async_context, (GDestroyNotify) async_context_free);
1992
1993         g_simple_async_result_run_in_thread (
1994                 simple, source_registry_commit_source_thread,
1995                 G_PRIORITY_DEFAULT, cancellable);
1996
1997         g_object_unref (simple);
1998 }
1999
2000 /**
2001  * e_source_registry_commit_source_finish:
2002  * @registry: an #ESourceRegistry
2003  * @result: a #GAsyncResult
2004  * @error: return location for a #GError, or %NULL
2005  *
2006  * Finishes the operation started with e_source_registry_commit_source().
2007  *
2008  * If an error occurred, the function will set @error and return %FALSE.
2009  *
2010  * Returns: %TRUE on success, %FALSE on failure
2011  *
2012  * Since: 3.6
2013  **/
2014 gboolean
2015 e_source_registry_commit_source_finish (ESourceRegistry *registry,
2016                                         GAsyncResult *result,
2017                                         GError **error)
2018 {
2019         GSimpleAsyncResult *simple;
2020
2021         g_return_val_if_fail (
2022                 g_simple_async_result_is_valid (
2023                 result, G_OBJECT (registry),
2024                 e_source_registry_commit_source), FALSE);
2025
2026         simple = G_SIMPLE_ASYNC_RESULT (result);
2027
2028         /* Assume success unless a GError is set. */
2029         return !g_simple_async_result_propagate_error (simple, error);
2030 }
2031
2032 /* Helper for e_source_registry_create_sources() */
2033 static void
2034 source_registry_create_sources_thread (GSimpleAsyncResult *simple,
2035                                        GObject *object,
2036                                        GCancellable *cancellable)
2037 {
2038         AsyncContext *async_context;
2039         GError *error = NULL;
2040
2041         async_context = g_simple_async_result_get_op_res_gpointer (simple);
2042
2043         e_source_registry_create_sources_sync (
2044                 E_SOURCE_REGISTRY (object),
2045                 async_context->list_of_sources,
2046                 cancellable, &error);
2047
2048         if (error != NULL)
2049                 g_simple_async_result_take_error (simple, error);
2050 }
2051
2052 /* Helper for e_source_registry_create_sources_sync() */
2053 static gboolean
2054 source_registry_create_sources_main_loop_quit_cb (gpointer user_data)
2055 {
2056         GMainLoop *main_loop = user_data;
2057
2058         g_main_loop_quit (main_loop);
2059
2060         return FALSE;
2061 }
2062
2063 /* Helper for e_source_registry_create_sources_sync() */
2064 static void
2065 source_registry_create_sources_object_added_cb (GDBusObjectManager *object_manager,
2066                                                 GDBusObject *dbus_object,
2067                                                 CreateContext *create_context)
2068 {
2069         EDBusObject *e_dbus_object;
2070         EDBusSource *e_dbus_source;
2071         const gchar *uid;
2072
2073         e_dbus_object = E_DBUS_OBJECT (dbus_object);
2074         e_dbus_source = e_dbus_object_get_source (e_dbus_object);
2075         uid = e_dbus_source_get_uid (e_dbus_source);
2076
2077         g_hash_table_remove (create_context->pending_uids, uid);
2078
2079         /* The hash table will be empty when all of the expected
2080          * GDBusObjects have been added to the GDBusObjectManager. */
2081         if (g_hash_table_size (create_context->pending_uids) == 0) {
2082                 GSource *idle_source;
2083
2084                 idle_source = g_idle_source_new ();
2085                 g_source_set_callback (
2086                         idle_source,
2087                         source_registry_create_sources_main_loop_quit_cb,
2088                         g_main_loop_ref (create_context->main_loop),
2089                         (GDestroyNotify) g_main_loop_unref);
2090                 g_source_attach (idle_source, create_context->main_context);
2091                 g_source_unref (idle_source);
2092         }
2093 }
2094
2095 /**
2096  * e_source_registry_create_sources_sync:
2097  * @registry: an #ESourceRegistry
2098  * @list_of_sources: (element-type ESource): a list of #ESource instances with
2099  * no #GDBusObject
2100  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2101  * @error: return location for a #GError, or %NULL
2102  *
2103  * Requests the D-Bus service create new key files for each #ESource in
2104  * @list_of_sources.  Each list element must be a scratch #ESource with
2105  * no #GDBusObject.
2106  *
2107  * If an error occurs, the function will set @error and return %FALSE.
2108  *
2109  * Returns: %TRUE on success, %FALSE on failure
2110  *
2111  * Since: 3.6
2112  **/
2113 gboolean
2114 e_source_registry_create_sources_sync (ESourceRegistry *registry,
2115                                        GList *list_of_sources,
2116                                        GCancellable *cancellable,
2117                                        GError **error)
2118 {
2119         CreateContext *create_context;
2120         GVariantBuilder builder;
2121         GVariant *variant;
2122         GList *link;
2123         gulong object_added_id;
2124         gboolean success;
2125
2126         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
2127
2128         /* Verify the list elements are all ESources. */
2129         for (link = list_of_sources; link != NULL; link = g_list_next (link))
2130                 g_return_val_if_fail (E_IS_SOURCE (link->data), FALSE);
2131
2132         create_context = create_context_new ();
2133         g_main_context_push_thread_default (create_context->main_context);
2134
2135         g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2136
2137         for (link = list_of_sources; link != NULL; link = g_list_next (link)) {
2138                 ESource *source;
2139                 gchar *source_data;
2140                 gchar *uid;
2141
2142                 source = E_SOURCE (link->data);
2143                 uid = e_source_dup_uid (source);
2144
2145                 /* Takes ownership of the UID string. */
2146                 g_hash_table_add (create_context->pending_uids, uid);
2147
2148                 source_data = e_source_to_string (source, NULL);
2149                 g_variant_builder_add (&builder, "{ss}", uid, source_data);
2150                 g_free (source_data);
2151         }
2152
2153         variant = g_variant_builder_end (&builder);
2154
2155         /* Use G_CONNECT_AFTER so source_registry_object_added_cb()
2156          * runs first and actually adds the ESource to the internal
2157          * hash table before we go quitting our main loop. */
2158         object_added_id = g_signal_connect_after (
2159                 registry->priv->dbus_object_manager, "object-added",
2160                 G_CALLBACK (source_registry_create_sources_object_added_cb),
2161                 create_context);
2162
2163         /* This function sinks the floating GVariant reference. */
2164         success = e_dbus_source_manager_call_create_sources_sync (
2165                 registry->priv->dbus_source_manager,
2166                 variant, cancellable, error);
2167
2168         g_variant_builder_clear (&builder);
2169
2170         /* Wait for an "object-added" signal for each created ESource.
2171          * But also set a short timeout to avoid getting stuck here in
2172          * case the registry service adds sources to its orphan table,
2173          * which prevents them from being exported over D-Bus. */
2174         if (success) {
2175                 GSource *timeout_source;
2176
2177                 timeout_source = g_timeout_source_new_seconds (2);
2178                 g_source_set_callback (
2179                         timeout_source,
2180                         source_registry_create_sources_main_loop_quit_cb,
2181                         g_main_loop_ref (create_context->main_loop),
2182                         (GDestroyNotify) g_main_loop_unref);
2183                 g_source_attach (timeout_source, create_context->main_context);
2184                 g_source_unref (timeout_source);
2185
2186                 g_main_loop_run (create_context->main_loop);
2187         }
2188
2189         g_signal_handler_disconnect (
2190                 registry->priv->dbus_object_manager, object_added_id);
2191
2192         g_main_context_pop_thread_default (create_context->main_context);
2193         create_context_free (create_context);
2194
2195         return success;
2196 }
2197
2198 /**
2199  * e_source_registry_create_sources:
2200  * @registry: an #ESourceRegistry
2201  * @list_of_sources: (element-type ESource): a list of #ESource instances with
2202  * no #GDBusObject
2203  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2204  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2205  *            is satisfied
2206  * @user_data: (closure): data to pass to the callback function
2207  *
2208  * Asynchronously requests the D-Bus service create new key files for each
2209  * #ESource in @list_of_sources.  Each list element must be a scratch
2210  * #ESource with no #GDBusObject.
2211  *
2212  * When the operation is finished, @callback will be called.  You can then
2213  * call e_source_registry_create_sources_finish() to get the result of the
2214  * operation.
2215  *
2216  * Since: 3.6
2217  **/
2218 void
2219 e_source_registry_create_sources (ESourceRegistry *registry,
2220                                   GList *list_of_sources,
2221                                   GCancellable *cancellable,
2222                                   GAsyncReadyCallback callback,
2223                                   gpointer user_data)
2224 {
2225         GSimpleAsyncResult *simple;
2226         AsyncContext *async_context;
2227         GList *link;
2228
2229         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2230
2231         /* Verify the list elements are all ESources. */
2232         for (link = list_of_sources; link != NULL; link = g_list_next (link))
2233                 g_return_if_fail (E_IS_SOURCE (link->data));
2234
2235         async_context = g_slice_new0 (AsyncContext);
2236         async_context->list_of_sources = g_list_copy (list_of_sources);
2237
2238         g_list_foreach (
2239                 async_context->list_of_sources,
2240                 (GFunc) g_object_ref, NULL);
2241
2242         simple = g_simple_async_result_new (
2243                 G_OBJECT (registry), callback, user_data,
2244                 e_source_registry_create_sources);
2245
2246         g_simple_async_result_set_check_cancellable (simple, cancellable);
2247
2248         g_simple_async_result_set_op_res_gpointer (
2249                 simple, async_context, (GDestroyNotify) async_context_free);
2250
2251         g_simple_async_result_run_in_thread (
2252                 simple, source_registry_create_sources_thread,
2253                 G_PRIORITY_DEFAULT, cancellable);
2254
2255         g_object_unref (simple);
2256 }
2257
2258 /**
2259  * e_source_registry_create_sources_finish:
2260  * @registry: an #ESourceRegistry
2261  * @result: a #GAsyncResult
2262  * @error: return location for a #GError, or %NULL
2263  *
2264  * Finishes the operation started with e_source_registry_create_sources().
2265  *
2266  * If an error occurred, the function will set @error and return %FALSE.
2267  *
2268  * Returns: %TRUE on success, %FALSE on failure
2269  *
2270  * Since: 3.6
2271  **/
2272 gboolean
2273 e_source_registry_create_sources_finish (ESourceRegistry *registry,
2274                                          GAsyncResult *result,
2275                                          GError **error)
2276 {
2277         GSimpleAsyncResult *simple;
2278
2279         g_return_val_if_fail (
2280                 g_simple_async_result_is_valid (
2281                 result, G_OBJECT (registry),
2282                 e_source_registry_create_sources), FALSE);
2283
2284         simple = G_SIMPLE_ASYNC_RESULT (result);
2285
2286         /* Assume success unless a GError is set. */
2287         return !g_simple_async_result_propagate_error (simple, error);
2288 }
2289
2290 /**
2291  * e_source_registry_ref_source:
2292  * @registry: an #ESourceRegistry
2293  * @uid: a unique identifier string
2294  *
2295  * Looks up an #ESource in @registry by its unique identifier string.
2296  *
2297  * The returned #ESource is referenced for thread-safety and must be
2298  * unreferenced with g_object_unref() when finished with it.
2299  *
2300  * Returns: (transfer full): an #ESource, or %NULL if no match was found
2301  *
2302  * Since: 3.6
2303  **/
2304 ESource *
2305 e_source_registry_ref_source (ESourceRegistry *registry,
2306                               const gchar *uid)
2307 {
2308         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2309         g_return_val_if_fail (uid != NULL, NULL);
2310
2311         return source_registry_sources_lookup (registry, uid);
2312 }
2313
2314 /**
2315  * e_source_registry_list_sources:
2316  * @registry: an #ESourceRegistry
2317  * @extension_name: (allow-none): an extension name, or %NULL
2318  *
2319  * Returns a list of registered sources, sorted by display name.  If
2320  * @extension_name is given, restrict the list to sources having that
2321  * extension name.
2322  *
2323  * The sources returned in the list are referenced for thread-safety.
2324  * They must each be unreferenced with g_object_unref() when finished
2325  * when them.  Free the returned list itself with g_list_free().
2326  *
2327  * An easy way to free the list properly in one step is as follows:
2328  *
2329  * |[
2330  *   g_list_free_full (list, g_object_unref);
2331  * ]|
2332  *
2333  * Returns: (element-type ESource) (transfer full): a sorted list of sources
2334  *
2335  * Since: 3.6
2336  **/
2337 GList *
2338 e_source_registry_list_sources (ESourceRegistry *registry,
2339                                 const gchar *extension_name)
2340 {
2341         GList *list, *link;
2342         GQueue trash = G_QUEUE_INIT;
2343
2344         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2345
2346         list = g_list_sort (
2347                 source_registry_sources_get_values (registry),
2348                 (GCompareFunc) e_source_compare_by_display_name);
2349
2350         if (extension_name == NULL)
2351                 return list;
2352
2353         for (link = list; link != NULL; link = g_list_next (link)) {
2354                 ESource *source = E_SOURCE (link->data);
2355
2356                 if (!e_source_has_extension (source, extension_name)) {
2357                         g_queue_push_tail (&trash, link);
2358                         g_object_unref (source);
2359                 }
2360         }
2361
2362         /* We do want pop_head() here, not pop_head_link(). */
2363         while ((link = g_queue_pop_head (&trash)) != NULL)
2364                 list = g_list_delete_link (list, link);
2365
2366         return list;
2367 }
2368
2369 /**
2370  * e_source_registry_check_enabled:
2371  * @registry: an #ESourceRegistry
2372  * @source: an #ESource
2373  *
2374  * Determines whether @source is "effectively" enabled by examining its
2375  * own #ESource:enabled property as well as those of its ancestors in the
2376  * #ESource hierarchy.  If all examined #ESource:enabled properties are
2377  * %TRUE, then the function returns %TRUE.  If any are %FALSE, then the
2378  * function returns %FALSE.
2379  *
2380  * Use this function instead of e_source_get_enabled() to determine
2381  * things like whether to display an #ESource in a user interface or
2382  * whether to act on the data set described by the #ESource.
2383  *
2384  * Returns: whether @source is "effectively" enabled
2385  *
2386  * Since: 3.8
2387  **/
2388 gboolean
2389 e_source_registry_check_enabled (ESourceRegistry *registry,
2390                                  ESource *source)
2391 {
2392         gboolean enabled;
2393         gchar *parent_uid;
2394
2395         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
2396         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2397
2398         enabled = e_source_get_enabled (source);
2399         parent_uid = e_source_dup_parent (source);
2400
2401         while (enabled && parent_uid != NULL) {
2402                 ESource *parent;
2403
2404                 parent = e_source_registry_ref_source (registry, parent_uid);
2405
2406                 g_free (parent_uid);
2407                 parent_uid = NULL;
2408
2409                 if (parent != NULL) {
2410                         enabled = e_source_get_enabled (parent);
2411                         parent_uid = e_source_dup_parent (parent);
2412                         g_object_unref (parent);
2413                 }
2414         }
2415
2416         g_free (parent_uid);
2417
2418         return enabled;
2419 }
2420
2421 /**
2422  * e_source_registry_find_extension:
2423  * @registry: an #ESourceRegistry
2424  * @source: an #ESource
2425  * @extension_name: the extension name to find
2426  *
2427  * Examines @source and its ancestors and returns the "deepest" #ESource
2428  * having an #ESourceExtension with the given @extension_name.  If neither
2429  * @source nor any of its ancestors have such an extension, the function
2430  * returns %NULL.
2431  *
2432  * This function is useful in cases when an #ESourceExtension is meant to
2433  * apply to both the #ESource it belongs to and the #ESource's descendants.
2434  *
2435  * A common example is the #ESourceCollection extension, where descendants
2436  * of an #ESource having an #ESourceCollection extension are implied to be
2437  * members of that collection.  In that example, this function can be used
2438  * to test whether @source is a member of a collection.
2439  *
2440  * The returned #ESource is referenced for thread-safety and must be
2441  * unreferenced with g_object_unref() when finished with it.
2442  *
2443  * Note the function returns the #ESource containing the #ESourceExtension
2444  * instead of the #ESourceExtension itself because extension instances are
2445  * not to be referenced directly (see e_source_get_extension()).
2446  *
2447  * Returns: (transfer full): an #ESource, or %NULL if no match was found
2448  *
2449  * Since: 3.6
2450  **/
2451 ESource *
2452 e_source_registry_find_extension (ESourceRegistry *registry,
2453                                   ESource *source,
2454                                   const gchar *extension_name)
2455 {
2456         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2457         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2458         g_return_val_if_fail (extension_name != NULL, NULL);
2459
2460         g_object_ref (source);
2461
2462         while (!e_source_has_extension (source, extension_name)) {
2463                 gchar *uid;
2464
2465                 uid = e_source_dup_parent (source);
2466
2467                 g_object_unref (source);
2468                 source = NULL;
2469
2470                 if (uid != NULL) {
2471                         source = e_source_registry_ref_source (registry, uid);
2472                         g_free (uid);
2473                 }
2474
2475                 if (source == NULL)
2476                         break;
2477         }
2478
2479         return source;
2480 }
2481
2482 /* Helper for e_source_registry_build_display_tree() */
2483 static gint
2484 source_registry_compare_nodes (GNode *node_a,
2485                                GNode *node_b)
2486 {
2487         ESource *source_a = E_SOURCE (node_a->data);
2488         ESource *source_b = E_SOURCE (node_b->data);
2489         const gchar *uid_a, *uid_b;
2490
2491         uid_a = e_source_get_uid (source_a);
2492         uid_b = e_source_get_uid (source_b);
2493
2494         /* Sanity check, with runtime warnings. */
2495         if (uid_a == NULL) {
2496                 g_warn_if_reached ();
2497                 uid_a = "";
2498         }
2499         if (uid_b == NULL) {
2500                 g_warn_if_reached ();
2501                 uid_b = "";
2502         }
2503
2504         /* The built-in "local-stub" source comes first at depth 1. */
2505
2506         if (g_strcmp0 (uid_a, "local-stub") == 0)
2507                 return -1;
2508
2509         if (g_strcmp0 (uid_b, "local-stub") == 0)
2510                 return 1;
2511
2512         /* The built-in "system-*" sources come first at depth 2. */
2513
2514         if (g_str_has_prefix (uid_a, "system-"))
2515                 return -1;
2516
2517         if (g_str_has_prefix (uid_b, "system-"))
2518                 return 1;
2519
2520         return e_source_compare_by_display_name (source_a, source_b);
2521 }
2522
2523 /* Helper for e_source_registry_build_display_tree() */
2524 static gboolean
2525 source_registry_prune_nodes (GNode *node,
2526                              const gchar *extension_name)
2527 {
2528         GQueue queue = G_QUEUE_INIT;
2529         GNode *child_node;
2530
2531         /* Unlink all the child nodes and place them in a queue. */
2532         while ((child_node = g_node_first_child (node)) != NULL) {
2533                 g_node_unlink (child_node);
2534                 g_queue_push_tail (&queue, child_node);
2535         }
2536
2537         /* Sort the queue by source name. */
2538         g_queue_sort (
2539                 &queue, (GCompareDataFunc)
2540                 source_registry_compare_nodes, NULL);
2541
2542         /* Pop nodes off the head of the queue until the queue is empty.
2543          * If the node has either its own children or the given extension
2544          * name, put it back under the parent node (preserving the sorted
2545          * order).  Otherwise delete the node and its descendants. */
2546         while ((child_node = g_queue_pop_head (&queue)) != NULL) {
2547                 ESource *child = E_SOURCE (child_node->data);
2548                 gboolean append_child_node = FALSE;
2549
2550                 if (extension_name == NULL)
2551                         append_child_node = e_source_get_enabled (child);
2552
2553                 else if (e_source_has_extension (child, extension_name))
2554                         append_child_node = e_source_get_enabled (child);
2555
2556                 else if (g_node_first_child (child_node) != NULL)
2557                         append_child_node = e_source_get_enabled (child);
2558
2559                 if (append_child_node)
2560                         g_node_append (node, child_node);
2561                 else
2562                         e_source_registry_free_display_tree (child_node);
2563         }
2564
2565         return FALSE;
2566 }
2567
2568 /**
2569  * e_source_registry_build_display_tree:
2570  * @registry: an #ESourceRegistry
2571  * @extension_name: (allow-none): an extension name, or %NULL
2572  *
2573  * Returns a single #GNode tree of registered sources that can be used to
2574  * populate a #GtkTreeModel.  (The root #GNode is just an empty placeholder.)
2575  *
2576  * Similar to e_source_registry_list_sources(), an @extension_name can be
2577  * given to restrict the tree to sources having that extension name.  Parents
2578  * of matched sources are included in the tree regardless of whether they have
2579  * an extension named @extension_name.
2580  *
2581  * Disabled leaf nodes are automatically excluded from the #GNode tree.
2582  *
2583  * The sources returned in the tree are referenced for thread-safety.
2584  * They must each be unreferenced with g_object_unref() when finished
2585  * with them.  Free the returned tree itself with g_node_destroy().
2586  * For convenience, e_source_registry_free_display_tree() does all
2587  * that in one step.
2588  *
2589  * Returns: (element-type ESource) (transfer full): a tree of sources,
2590  *          arranged for display
2591  *
2592  * Since: 3.6
2593  **/
2594 GNode *
2595 e_source_registry_build_display_tree (ESourceRegistry *registry,
2596                                       const gchar *extension_name)
2597 {
2598         GNode *root;
2599
2600         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2601
2602         /* Assemble all data sources into a tree. */
2603         root = source_registry_sources_build_tree (registry);
2604
2605         /* Prune unwanted nodes from the copied source trees.
2606          * This must be done in "post" order (children first)
2607          * since it reorders and deletes child nodes. */
2608         g_node_traverse (
2609                 root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
2610                 (GNodeTraverseFunc) source_registry_prune_nodes,
2611                 (gpointer) extension_name);
2612
2613         return root;
2614 }
2615
2616 /* Helper for e_source_registry_free_display_tree() */
2617 static void
2618 source_registry_unref_nodes (GNode *node)
2619 {
2620         while (node != NULL) {
2621                 if (node->children != NULL)
2622                         source_registry_unref_nodes (node->children);
2623                 if (node->data != NULL)
2624                         g_object_unref (node->data);
2625                 node = node->next;
2626         }
2627 }
2628
2629 /**
2630  * e_source_registry_free_display_tree:
2631  * @display_tree: a tree of sources, arranged for display
2632  *
2633  * Convenience function to free a #GNode tree of registered
2634  * sources created by e_source_registry_build_display_tree().
2635  *
2636  * Since: 3.6
2637  **/
2638 void
2639 e_source_registry_free_display_tree (GNode *display_tree)
2640 {
2641         g_return_if_fail (display_tree != NULL);
2642
2643         /* XXX This would be easier if GLib had something like
2644          *     g_node_destroy_full() which took a GDestroyNotify.
2645          *     Then the tree would not have to be traversed twice. */
2646
2647         source_registry_unref_nodes (display_tree);
2648         g_node_destroy (display_tree);
2649 }
2650
2651 /* Helper for e_source_registry_debug_dump() */
2652 static gboolean
2653 source_registry_debug_dump_cb (GNode *node)
2654 {
2655         guint ii, depth;
2656
2657         /* Root node is an empty placeholder. */
2658         if (G_NODE_IS_ROOT (node))
2659                 return FALSE;
2660
2661         depth = g_node_depth (node);
2662         for (ii = 2; ii < depth; ii++)
2663                 g_print ("    ");
2664
2665         if (E_IS_SOURCE (node->data)) {
2666                 ESource *source = E_SOURCE (node->data);
2667                 g_print ("\"%s\" ", e_source_get_display_name (source));
2668                 g_print ("(%s)", e_source_get_uid (source));
2669         }
2670
2671         g_print ("\n");
2672
2673         return FALSE;
2674 }
2675
2676 /**
2677  * e_source_registry_debug_dump:
2678  * @registry: an #ESourceRegistry
2679  * @extension_name: (allow-none): an extension name, or %NULL
2680  *
2681  * Handy debugging function that uses e_source_registry_build_display_tree()
2682  * to print a tree of registered sources to standard output.
2683  *
2684  * Since: 3.6
2685  **/
2686 void
2687 e_source_registry_debug_dump (ESourceRegistry *registry,
2688                               const gchar *extension_name)
2689 {
2690         GNode *root;
2691
2692         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2693
2694         root = e_source_registry_build_display_tree (registry, extension_name);
2695
2696         g_node_traverse (
2697                 root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2698                 (GNodeTraverseFunc) source_registry_debug_dump_cb, NULL);
2699
2700         e_source_registry_free_display_tree (root);
2701 }
2702
2703 /**
2704  * e_source_registry_ref_builtin_address_book:
2705  * @registry: an #ESourceRegistry
2706  *
2707  * Returns the built-in address book #ESource.
2708  *
2709  * This #ESource is always present and makes for a safe fallback.
2710  *
2711  * The returned #ESource is referenced for thread-safety and must be
2712  * unreferenced with g_object_unref() when finished with it.
2713  *
2714  * Returns: (transfer full): the built-in address book #ESource
2715  *
2716  * Since: 3.6
2717  **/
2718 ESource *
2719 e_source_registry_ref_builtin_address_book (ESourceRegistry *registry)
2720 {
2721         ESource *source;
2722         const gchar *uid;
2723
2724         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2725
2726         uid = E_SOURCE_BUILTIN_ADDRESS_BOOK_UID;
2727         source = e_source_registry_ref_source (registry, uid);
2728         g_return_val_if_fail (source != NULL, NULL);
2729
2730         return source;
2731 }
2732
2733 /**
2734  * e_source_registry_ref_default_address_book:
2735  * @registry: an #ESourceRegistry
2736  *
2737  * Returns the #ESource most recently passed to
2738  * e_source_registry_set_default_address_book() either in this session
2739  * or a previous session, or else falls back to the built-in address book.
2740  *
2741  * The returned #ESource is referenced for thread-safety and must be
2742  * unreferenced with g_object_unref() when finished with it.
2743  *
2744  * Returns: (transfer full): the default address book #ESource
2745  *
2746  * Since: 3.6
2747  **/
2748 ESource *
2749 e_source_registry_ref_default_address_book (ESourceRegistry *registry)
2750 {
2751         const gchar *key;
2752         ESource *source;
2753         gchar *uid;
2754
2755         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2756
2757         key = E_SETTINGS_DEFAULT_ADDRESS_BOOK_KEY;
2758         uid = g_settings_get_string (registry->priv->settings, key);
2759         source = e_source_registry_ref_source (registry, uid);
2760         g_free (uid);
2761
2762         /* The built-in source is always present. */
2763         if (source == NULL)
2764                 source = e_source_registry_ref_builtin_address_book (registry);
2765
2766         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2767
2768         return source;
2769 }
2770
2771 /**
2772  * e_source_registry_set_default_address_book:
2773  * @registry: an #ESourceRegistry
2774  * @default_source: (allow-none): an address book #ESource, or %NULL
2775  *
2776  * Sets @default_source as the default address book.  If @default_source
2777  * is %NULL, the default address book is reset to the built-in address book.
2778  * This setting will persist across sessions until changed.
2779  *
2780  * Since: 3.6
2781  **/
2782 void
2783 e_source_registry_set_default_address_book (ESourceRegistry *registry,
2784                                             ESource *default_source)
2785 {
2786         const gchar *key;
2787         const gchar *uid;
2788
2789         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2790
2791         if (default_source != NULL) {
2792                 g_return_if_fail (E_IS_SOURCE (default_source));
2793                 uid = e_source_get_uid (default_source);
2794         } else {
2795                 uid = E_SOURCE_BUILTIN_ADDRESS_BOOK_UID;
2796         }
2797
2798         key = E_SETTINGS_DEFAULT_ADDRESS_BOOK_KEY;
2799         g_settings_set_string (registry->priv->settings, key, uid);
2800
2801         /* The GSettings::changed signal will trigger a "notify" signal
2802          * from the registry, so no need to call g_object_notify() here. */
2803 }
2804
2805 /**
2806  * e_source_registry_ref_builtin_calendar:
2807  * @registry: an #ESourceRegistry
2808  *
2809  * Returns the built-in calendar #ESource.
2810  *
2811  * This #ESource is always present and makes for a safe fallback.
2812  *
2813  * The returned #ESource is referenced for thread-safety and must be
2814  * unreferenced with g_object_unref() when finished with it.
2815  *
2816  * Returns: (transfer full): the built-in calendar #ESource
2817  *
2818  * Since: 3.6
2819  **/
2820 ESource *
2821 e_source_registry_ref_builtin_calendar (ESourceRegistry *registry)
2822 {
2823         ESource *source;
2824         const gchar *uid;
2825
2826         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2827
2828         uid = E_SOURCE_BUILTIN_CALENDAR_UID;
2829         source = e_source_registry_ref_source (registry, uid);
2830         g_return_val_if_fail (source != NULL, NULL);
2831
2832         return source;
2833 }
2834
2835 /**
2836  * e_source_registry_ref_default_calendar:
2837  * @registry: an #ESourceRegistry
2838  *
2839  * Returns the #ESource most recently passed to
2840  * e_source_registry_set_default_calendar() either in this session
2841  * or a previous session, or else falls back to the built-in calendar.
2842  *
2843  * The returned #ESource is referenced for thread-safety and must be
2844  * unreferenced with g_object_unref() when finished with it.
2845  *
2846  * Returns: (transfer full): the default calendar #ESource
2847  *
2848  * Since: 3.6
2849  **/
2850 ESource *
2851 e_source_registry_ref_default_calendar (ESourceRegistry *registry)
2852 {
2853         const gchar *key;
2854         ESource *source;
2855         gchar *uid;
2856
2857         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2858
2859         key = E_SETTINGS_DEFAULT_CALENDAR_KEY;
2860         uid = g_settings_get_string (registry->priv->settings, key);
2861         source = e_source_registry_ref_source (registry, uid);
2862         g_free (uid);
2863
2864         /* The built-in source is always present. */
2865         if (source == NULL)
2866                 source = e_source_registry_ref_builtin_calendar (registry);
2867
2868         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2869
2870         return source;
2871 }
2872
2873 /**
2874  * e_source_registry_set_default_calendar:
2875  * @registry: an #ESourceRegistry
2876  * @default_source: (allow-none): a calendar #ESource, or %NULL
2877  *
2878  * Sets @default_source as the default calendar.  If @default_source
2879  * is %NULL, the default calendar is reset to the built-in calendar.
2880  * This setting will persist across sessions until changed.
2881  *
2882  * Since: 3.6
2883  **/
2884 void
2885 e_source_registry_set_default_calendar (ESourceRegistry *registry,
2886                                         ESource *default_source)
2887 {
2888         const gchar *key;
2889         const gchar *uid;
2890
2891         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2892
2893         if (default_source != NULL) {
2894                 g_return_if_fail (E_IS_SOURCE (default_source));
2895                 uid = e_source_get_uid (default_source);
2896         } else {
2897                 uid = E_SOURCE_BUILTIN_CALENDAR_UID;
2898         }
2899
2900         key = E_SETTINGS_DEFAULT_CALENDAR_KEY;
2901         g_settings_set_string (registry->priv->settings, key, uid);
2902
2903         /* The GSettings::changed signal will trigger a "notify" signal
2904          * from the registry, so no need to call g_object_notify() here. */
2905 }
2906
2907 /**
2908  * e_source_registry_ref_builtin_mail_account:
2909  * @registry: an #ESourceRegistry
2910  *
2911  * Returns the built-in mail account #ESource.
2912  *
2913  * This #ESource is always present and makes for a safe fallback.
2914  *
2915  * The returned #ESource is referenced for thread-safety and must be
2916  * unreferenced with g_object_unref() when finished with it.
2917  *
2918  * Returns: (transfer full): the built-in mail account #ESource
2919  *
2920  * Since: 3.6
2921  **/
2922 ESource *
2923 e_source_registry_ref_builtin_mail_account (ESourceRegistry *registry)
2924 {
2925         ESource *source;
2926         const gchar *uid;
2927
2928         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2929
2930         uid = E_SOURCE_BUILTIN_MAIL_ACCOUNT_UID;
2931         source = e_source_registry_ref_source (registry, uid);
2932         g_return_val_if_fail (source != NULL, NULL);
2933
2934         return source;
2935 }
2936
2937 /**
2938  * e_source_registry_ref_default_mail_account:
2939  * @registry: an #ESourceRegistry
2940  *
2941  * Returns the #ESource most recently passed to
2942  * e_source_registry_set_default_mail_account() either in this session
2943  * or a previous session, or else falls back to the built-in mail account.
2944  *
2945  * The returned #ESource is referenced for thread-safety and must be
2946  * unreferenced with g_object_unref() when finished with it.
2947  *
2948  * Returns: (transfer full): the default mail account #ESource
2949  *
2950  * Since: 3.6
2951  **/
2952 ESource *
2953 e_source_registry_ref_default_mail_account (ESourceRegistry *registry)
2954 {
2955         const gchar *key;
2956         ESource *source;
2957         gchar *uid;
2958
2959         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
2960
2961         key = E_SETTINGS_DEFAULT_MAIL_ACCOUNT_KEY;
2962         uid = g_settings_get_string (registry->priv->settings, key);
2963         source = e_source_registry_ref_source (registry, uid);
2964         g_free (uid);
2965
2966         /* The built-in source is always present. */
2967         if (source == NULL)
2968                 source = e_source_registry_ref_builtin_mail_account (registry);
2969
2970         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2971
2972         return source;
2973 }
2974
2975 /**
2976  * e_source_registry_set_default_mail_account:
2977  * @registry: an #ESourceRegistry
2978  * @default_source: (allow-none): a mail account #ESource, or %NULL
2979  *
2980  * Sets @default_source as the default mail account.  If @default_source
2981  * is %NULL, the default mail account is reset to the built-in mail account.
2982  * This setting will persist across sessions until changed.
2983  *
2984  * Since: 3.6
2985  **/
2986 void
2987 e_source_registry_set_default_mail_account (ESourceRegistry *registry,
2988                                             ESource *default_source)
2989 {
2990         const gchar *key;
2991         const gchar *uid;
2992
2993         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
2994
2995         if (default_source != NULL) {
2996                 g_return_if_fail (E_IS_SOURCE (default_source));
2997                 uid = e_source_get_uid (default_source);
2998         } else {
2999                 uid = E_SOURCE_BUILTIN_MAIL_ACCOUNT_UID;
3000         }
3001
3002         key = E_SETTINGS_DEFAULT_MAIL_ACCOUNT_KEY;
3003         g_settings_set_string (registry->priv->settings, key, uid);
3004
3005         /* The GSettings::changed signal will trigger a "notify" signal
3006          * from the registry, so no need to call g_object_notify() here. */
3007 }
3008
3009 /* Helper for e_source_registry_ref_default_mail_identity() */
3010 static ESource *
3011 source_registry_ref_any_mail_identity (ESourceRegistry *registry)
3012 {
3013         ESource *source;
3014         GList *list, *link;
3015         const gchar *extension_name;
3016         gchar *uid = NULL;
3017
3018         /* First fallback: Return the mail identity named
3019          *                 by the default mail account. */
3020
3021         source = e_source_registry_ref_default_mail_account (registry);
3022
3023         /* This should never be NULL, but just to be safe. */
3024         if (source != NULL) {
3025                 ESourceMailAccount *extension;
3026
3027                 extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
3028                 extension = e_source_get_extension (source, extension_name);
3029                 uid = e_source_mail_account_dup_identity_uid (extension);
3030
3031                 g_object_unref (source);
3032                 source = NULL;
3033         }
3034
3035         if (uid != NULL) {
3036                 source = e_source_registry_ref_source (registry, uid);
3037                 g_free (uid);
3038         }
3039
3040         if (source != NULL)
3041                 return source;
3042
3043         /* Second fallback: Pick any available mail identity,
3044          *                  preferring enabled identities. */
3045
3046         extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
3047         list = e_source_registry_list_sources (registry, extension_name);
3048
3049         for (link = list; link != NULL; link = g_list_next (link)) {
3050                 ESource *candidate = E_SOURCE (link->data);
3051
3052                 if (e_source_registry_check_enabled (registry, candidate)) {
3053                         source = g_object_ref (candidate);
3054                         break;
3055                 }
3056         }
3057
3058         if (source == NULL && list != NULL)
3059                 source = g_object_ref (list->data);
3060
3061         g_list_free_full (list, (GDestroyNotify) g_object_unref);
3062
3063         return source;
3064 }
3065
3066 /**
3067  * e_source_registry_ref_default_mail_identity:
3068  * @registry: an #ESourceRegistry
3069  *
3070  * Returns the #ESource most recently passed to
3071  * e_source_registry_set_default_mail_identity() either in this session
3072  * or a previous session, or else falls back to the mail identity named
3073  * by the default mail account.  If even that fails it returns any mail
3074  * identity from @registry, or %NULL if there are none.
3075  *
3076  * The returned #ESource is referenced for thread-safety and must be
3077  * unreferenced with g_object_unref() when finished with it.
3078  *
3079  * Returns: (transfer full): the default mail identity #ESource, or %NULL
3080  *
3081  * Since: 3.6
3082  **/
3083 ESource *
3084 e_source_registry_ref_default_mail_identity (ESourceRegistry *registry)
3085 {
3086         const gchar *key;
3087         ESource *source;
3088         gchar *uid;
3089
3090         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3091
3092         key = E_SETTINGS_DEFAULT_MAIL_IDENTITY_KEY;
3093         uid = g_settings_get_string (registry->priv->settings, key);
3094         source = e_source_registry_ref_source (registry, uid);
3095         g_free (uid);
3096
3097         if (source == NULL)
3098                 source = source_registry_ref_any_mail_identity (registry);
3099
3100         return source;
3101 }
3102
3103 /**
3104  * e_source_registry_set_default_mail_identity:
3105  * @registry: an #ESourceRegistry
3106  * @default_source: (allow-none): a mail identity #ESource, or %NULL
3107  *
3108  * Sets @default_source as the default mail identity.  If @default_source
3109  * is %NULL, the next request for the default mail identity will use the
3110  * fallbacks described in e_source_registry_get_default_mail_identity().
3111  *
3112  * Since: 3.6
3113  **/
3114 void
3115 e_source_registry_set_default_mail_identity (ESourceRegistry *registry,
3116                                              ESource *default_source)
3117 {
3118         const gchar *key;
3119         const gchar *uid;
3120
3121         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3122
3123         if (default_source != NULL) {
3124                 g_return_if_fail (E_IS_SOURCE (default_source));
3125                 uid = e_source_get_uid (default_source);
3126         } else {
3127                 uid = "";  /* no built-in mail identity */
3128         }
3129
3130         key = E_SETTINGS_DEFAULT_MAIL_IDENTITY_KEY;
3131         g_settings_set_string (registry->priv->settings, key, uid);
3132
3133         /* The GSettings::changed signal will trigger a "notify" signal
3134          * from the registry, so no need to call g_object_notify() here. */
3135 }
3136
3137 /**
3138  * e_source_registry_ref_builtin_memo_list:
3139  * @registry: an #ESourceRegistry
3140  *
3141  * Returns the built-in memo list #ESource.
3142  *
3143  * This #ESource is always present and makes for a safe fallback.
3144  *
3145  * The returned #ESource is referenced for thread-safety and must be
3146  * unreferenced with g_object_unref() when finished with it.
3147  *
3148  * Returns: (transfer full): the built-in memo list #ESource
3149  *
3150  * Since: 3.6
3151  **/
3152 ESource *
3153 e_source_registry_ref_builtin_memo_list (ESourceRegistry *registry)
3154 {
3155         ESource *source;
3156         const gchar *uid;
3157
3158         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3159
3160         uid = E_SOURCE_BUILTIN_MEMO_LIST_UID;
3161         source = e_source_registry_ref_source (registry, uid);
3162         g_return_val_if_fail (source != NULL, NULL);
3163
3164         return source;
3165 }
3166
3167 /**
3168  * e_source_registry_ref_default_memo_list:
3169  * @registry: an #ESourceRegistry
3170  *
3171  * Returns the #ESource most recently passed to
3172  * e_source_registry_set_default_memo_list() either in this session
3173  * or a previous session, or else falls back to the built-in memo list.
3174  *
3175  * The returned #ESource is referenced for thread-safety and must be
3176  * unreferenced with g_object_unref() when finished with it.
3177  *
3178  * Returns: (transfer full): the default memo list #ESource
3179  *
3180  * Since: 3.6
3181  **/
3182 ESource *
3183 e_source_registry_ref_default_memo_list (ESourceRegistry *registry)
3184 {
3185         const gchar *key;
3186         ESource *source;
3187         gchar *uid;
3188
3189         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3190
3191         key = E_SETTINGS_DEFAULT_MEMO_LIST_KEY;
3192         uid = g_settings_get_string (registry->priv->settings, key);
3193         source = e_source_registry_ref_source (registry, uid);
3194         g_free (uid);
3195
3196         /* The built-in source is always present. */
3197         if (source == NULL)
3198                 source = e_source_registry_ref_builtin_memo_list (registry);
3199
3200         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3201
3202         return source;
3203 }
3204
3205 /**
3206  * e_source_registry_set_default_memo_list:
3207  * @registry: an #ESourceRegistry
3208  * @default_source: (allow-none): a memo list #ESource, or %NULL
3209  *
3210  * Sets @default_source as the default memo list.  If @default_source
3211  * is %NULL, the default memo list is reset to the built-in memo list.
3212  * This setting will persist across sessions until changed.
3213  *
3214  * Since: 3.6
3215  **/
3216 void
3217 e_source_registry_set_default_memo_list (ESourceRegistry *registry,
3218                                          ESource *default_source)
3219 {
3220         const gchar *key;
3221         const gchar *uid;
3222
3223         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3224
3225         if (default_source != NULL) {
3226                 g_return_if_fail (E_IS_SOURCE (default_source));
3227                 uid = e_source_get_uid (default_source);
3228         } else {
3229                 uid = E_SOURCE_BUILTIN_MEMO_LIST_UID;
3230         }
3231
3232         key = E_SETTINGS_DEFAULT_MEMO_LIST_KEY;
3233         g_settings_set_string (registry->priv->settings, key, uid);
3234
3235         /* The GSettings::changed signal will trigger a "notify" signal
3236          * from the registry, so no need to call g_object_notify() here. */
3237 }
3238
3239 /**
3240  * e_source_registry_ref_builtin_task_list:
3241  * @registry: an #ESourceRegistry
3242  *
3243  * Returns the built-in task list #ESource.
3244  *
3245  * This #ESource is always present and makes for a safe fallback.
3246  *
3247  * The returned #ESource is referenced for thread-safety and must be
3248  * unreferenced with g_object_unref() when finished with it.
3249  *
3250  * Returns: (transfer full): the built-in task list #ESource
3251  *
3252  * Since: 3.6
3253  **/
3254 ESource *
3255 e_source_registry_ref_builtin_task_list (ESourceRegistry *registry)
3256 {
3257         ESource *source;
3258         const gchar *uid;
3259
3260         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3261
3262         uid = E_SOURCE_BUILTIN_TASK_LIST_UID;
3263         source = e_source_registry_ref_source (registry, uid);
3264         g_return_val_if_fail (source != NULL, NULL);
3265
3266         return source;
3267 }
3268
3269 /**
3270  * e_source_registry_ref_default_task_list:
3271  * @registry: an #ESourceRegistry
3272  *
3273  * Returns the #ESource most recently passed to
3274  * e_source_registry_set_default_task_list() either in this session
3275  * or a previous session, or else falls back to the built-in task list.
3276  *
3277  * The returned #ESource is referenced for thread-safety and must be
3278  * unreferenced with g_object_unref() when finished with it.
3279  *
3280  * Returns: (transfer full): the default task list #ESource
3281  *
3282  * Since: 3.6
3283  **/
3284 ESource *
3285 e_source_registry_ref_default_task_list (ESourceRegistry *registry)
3286 {
3287         const gchar *key;
3288         ESource *source;
3289         gchar *uid;
3290
3291         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3292
3293         key = E_SETTINGS_DEFAULT_TASK_LIST_KEY;
3294         uid = g_settings_get_string (registry->priv->settings, key);
3295         source = e_source_registry_ref_source (registry, uid);
3296         g_free (uid);
3297
3298         /* The built-in source is always present. */
3299         if (source == NULL)
3300                 source = e_source_registry_ref_builtin_task_list (registry);
3301
3302         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3303
3304         return source;
3305 }
3306
3307 /**
3308  * e_source_registry_set_default_task_list:
3309  * @registry: an #ESourceRegistry
3310  * @default_source: (allow-none): a task list #ESource, or %NULL
3311  *
3312  * Sets @default_source as the default task list.  If @default_source
3313  * is %NULL, the default task list is reset to the built-in task list.
3314  * This setting will persist across sessions until changed.
3315  *
3316  * Since: 3.6
3317  **/
3318 void
3319 e_source_registry_set_default_task_list (ESourceRegistry *registry,
3320                                          ESource *default_source)
3321 {
3322         const gchar *key;
3323         const gchar *uid;
3324
3325         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3326
3327         if (default_source != NULL) {
3328                 g_return_if_fail (E_IS_SOURCE (default_source));
3329                 uid = e_source_get_uid (default_source);
3330         } else {
3331                 uid = E_SOURCE_BUILTIN_TASK_LIST_UID;
3332         }
3333
3334         key = E_SETTINGS_DEFAULT_TASK_LIST_KEY;
3335         g_settings_set_string (registry->priv->settings, key, uid);
3336
3337         /* The GSettings::changed signal will trigger a "notify" signal
3338          * from the registry, so no need to call g_object_notify() here. */
3339 }
3340
3341 /**
3342  * e_source_registry_ref_default_for_extension_name:
3343  * @registry: an #ESourceRegistry
3344  * @extension_name: an extension_name
3345  *
3346  * This is a convenience function to return a default #ESource based on
3347  * @extension_name.  This only works with a subset of extension names.
3348  *
3349  * If @extension_name is #E_SOURCE_EXTENSION_ADDRESS_BOOK, the function
3350  * returns the current default address book, or else falls back to the
3351  * built-in address book.
3352  *
3353  * If @extension_name is #E_SOURCE_EXTENSION_CALENDAR, the function returns
3354  * the current default calendar, or else falls back to the built-in calendar.
3355  *
3356  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_ACCOUNT, the function
3357  * returns the current default mail account, or else falls back to the
3358  * built-in mail account.
3359  *
3360  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_IDENTITY, the function
3361  * returns the current default mail identity, or else falls back to the
3362  * mail identity named by the current default mail account.
3363  *
3364  * If @extension_name is #E_SOURCE_EXTENSION_MEMO_LIST, the function returns
3365  * the current default memo list, or else falls back to the built-in memo list.
3366  *
3367  * If @extension_name is #E_SOURCE_EXTENSION_TASK_LIST, the function returns
3368  * the current default task list, or else falls back to the built-in task list.
3369  *
3370  * For all other values of @extension_name, the function returns %NULL.
3371  *
3372  * The returned #ESource is referenced for thread-safety and must be
3373  * unreferenced with g_object_unref() when finished with it.
3374  *
3375  * Returns: (transfer full): the default #ESource based on @extension_name
3376  *
3377  * Since: 3.6
3378  **/
3379 ESource *
3380 e_source_registry_ref_default_for_extension_name (ESourceRegistry *registry,
3381                                                   const gchar *extension_name)
3382 {
3383         g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
3384         g_return_val_if_fail (extension_name != NULL, NULL);
3385
3386         if (strcmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0)
3387                 return e_source_registry_ref_default_address_book (registry);
3388
3389         if (strcmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0)
3390                 return e_source_registry_ref_default_calendar (registry);
3391
3392         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_ACCOUNT) == 0)
3393                 return e_source_registry_ref_default_mail_account (registry);
3394
3395         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_IDENTITY) == 0)
3396                 return e_source_registry_ref_default_mail_identity (registry);
3397
3398         if (strcmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0)
3399                 return e_source_registry_ref_default_memo_list (registry);
3400
3401         if (strcmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0)
3402                 return e_source_registry_ref_default_task_list (registry);
3403
3404         return NULL;
3405 }
3406
3407 /**
3408  * e_source_registry_set_default_for_extension_name:
3409  * @registry: an #ESourceRegistry
3410  * @extension_name: an extension name
3411  * @default_source: (allow-none): an #ESource, or %NULL
3412  *
3413  * This is a convenience function to set a default #ESource based on
3414  * @extension_name.  This only works with a subset of extension names.
3415  *
3416  * If @extension_name is #E_SOURCE_EXTENSION_ADDRESS_BOOK, the function
3417  * sets @default_source as the default address book.  If @default_source
3418  * is %NULL, the default address book is reset to the built-in address book.
3419  *
3420  * If @extension_name is #E_SOURCE_EXTENSION_CALENDAR, the function sets
3421  * @default_source as the default calendar.  If @default_source is %NULL,
3422  * the default calendar is reset to the built-in calendar.
3423  *
3424  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_ACCOUNT, the function
3425  * sets @default_source as the default mail account.  If @default_source
3426  * is %NULL, the default mail account is reset to the built-in mail account.
3427  *
3428  * If @extension_name is #E_SOURCE_EXTENSION_MAIL_IDENTITY, the function
3429  * sets @default_source as the default mail identity.  If @default_source
3430  * is %NULL, the next request for the default mail identity will return
3431  * the mail identity named by the default mail account.
3432  *
3433  * If @extension_name is #E_SOURCE_EXTENSION_MEMO_LIST, the function sets
3434  * @default_source as the default memo list.  If @default_source is %NULL,
3435  * the default memo list is reset to the built-in memo list.
3436  *
3437  * If @extension_name is #E_SOURCE_EXTENSION_TASK_LIST, the function sets
3438  * @default_source as the default task list.  If @default_source is %NULL,
3439  * the default task list is reset to the built-in task list.
3440  *
3441  * For all other values of @extension_name, the function does nothing.
3442  *
3443  * Since: 3.6
3444  **/
3445 void
3446 e_source_registry_set_default_for_extension_name (ESourceRegistry *registry,
3447                                                   const gchar *extension_name,
3448                                                   ESource *default_source)
3449 {
3450         g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
3451         g_return_if_fail (extension_name != NULL);
3452
3453         if (strcmp (extension_name, E_SOURCE_EXTENSION_ADDRESS_BOOK) == 0)
3454                 e_source_registry_set_default_address_book (
3455                         registry, default_source);
3456
3457         if (strcmp (extension_name, E_SOURCE_EXTENSION_CALENDAR) == 0)
3458                 e_source_registry_set_default_calendar (
3459                         registry, default_source);
3460
3461         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_ACCOUNT) == 0)
3462                 e_source_registry_set_default_mail_account (
3463                         registry, default_source);
3464
3465         if (strcmp (extension_name, E_SOURCE_EXTENSION_MAIL_IDENTITY) == 0)
3466                 e_source_registry_set_default_mail_identity (
3467                         registry, default_source);
3468
3469         if (strcmp (extension_name, E_SOURCE_EXTENSION_MEMO_LIST) == 0)
3470                 e_source_registry_set_default_memo_list (
3471                         registry, default_source);
3472
3473         if (strcmp (extension_name, E_SOURCE_EXTENSION_TASK_LIST) == 0)
3474                 e_source_registry_set_default_task_list (
3475                         registry, default_source);
3476 }
3477