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