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