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