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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->priv->object_path_table_lock);
375
376 removed = g_hash_table_remove (object_path_table, object_path);
377
378 g_mutex_unlock (®istry->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 (®istry->priv->service_restart_table_lock);
394
395 g_hash_table_add (service_restart_table, g_strdup (uid));
396
397 g_mutex_unlock (®istry->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 (®istry->priv->service_restart_table_lock);
412
413 removed = g_hash_table_remove (service_restart_table, uid);
414
415 g_mutex_unlock (®istry->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 (®istry->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 (®istry->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 (®istry->priv->sources_lock);
449
450 removed = g_hash_table_remove (registry->priv->sources, uid);
451
452 g_mutex_unlock (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->priv->init_error, local_error);
1478 goto exit;
1479 }
1480
1481 exit:
1482 registry->priv->initialized = TRUE;
1483 g_mutex_unlock (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry->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 (®istry);
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