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