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