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