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