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