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