1ed8d25cf86104ae018ba98f20fbf4cec0c4b3d7
[platform/upstream/evolution-data-server.git] / libedataserver / e-source.c
1 /*
2  * e-source.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  */
18
19 /**
20  * SECTION: e-source
21  * @include: libedataserver/libedataserver.h
22  * @short_description: Hierarchical data sources
23  *
24  * An #ESource (or "data source") is a description of a file or network
25  * location where data can be obtained (such as a mail account), or a
26  * description of a resource at that location (such as a mail folder).
27  *
28  * In more concrete terms, it's an interface for a key file.  All such
29  * key files have a main group named [Data Source].  The keys in a
30  * [Data Source] group map to #GObject properties in an #ESource.
31  *
32  * Additional groups in the key file are referred to as "extensions".
33  * #ESourceExtension serves as the base class for writing interfaces
34  * for these additional key file groups.  The keys in one of these
35  * key file groups map to #GObject properties in some custom subclass
36  * of #ESourceExtension which was written specifically for that key
37  * file group.  For example, a key file might include a group named
38  * [Calendar], whose keys map to #GObject properties in an extension
39  * class named #ESourceCalendar.
40  *
41  * Each #ESource contains an internal dictionary of extension objects,
42  * accessible by their key file group name.  e_source_get_extension()
43  * can look up extension objects by name.
44  *
45  * An #ESource is identified by a unique identifier string, or "UID",
46  * which is also the basename of the corresponding key file.  Additional
47  * files related to the #ESource, such as cache files, are usually kept
48  * in a directory named after the UID of the #ESource.  Similarly, the
49  * password for an account described by an #ESource is kept in GNOME
50  * Keyring under the UID of the #ESource.  This makes finding these
51  * additional resources simple.
52  *
53  * Several extensions for common information such as authentication
54  * details are built into libedataserver (#ESourceAuthentication, for
55  * example).  Backend modules may also define their own extensions for
56  * information and settings unique to the backend.  #ESourceExtension
57  * subclasses written for specific backends are generally not available
58  * to applications and shared libraries.  This is by design, to try and
59  * keep backend-specific knowledge from creeping into places it doesn't
60  * belong.
61  **/
62
63 #include "e-source.h"
64
65 #include <config.h>
66 #include <string.h>
67 #include <glib/gi18n-lib.h>
68
69 /* Private D-Bus classes. */
70 #include <e-dbus-source.h>
71
72 #include "e-data-server-util.h"
73 #include "e-source-extension.h"
74 #include "e-uid.h"
75
76 /* built-in extension types */
77 #include "e-source-address-book.h"
78 #include "e-source-alarms.h"
79 #include "e-source-authentication.h"
80 #include "e-source-autocomplete.h"
81 #include "e-source-calendar.h"
82 #include "e-source-camel.h"
83 #include "e-source-collection.h"
84 #include "e-source-goa.h"
85 #include "e-source-mail-account.h"
86 #include "e-source-mail-composition.h"
87 #include "e-source-mail-identity.h"
88 #include "e-source-mail-signature.h"
89 #include "e-source-mail-submission.h"
90 #include "e-source-mail-transport.h"
91 #include "e-source-mdn.h"
92 #include "e-source-offline.h"
93 #include "e-source-openpgp.h"
94 #include "e-source-refresh.h"
95 #include "e-source-resource.h"
96 #include "e-source-security.h"
97 #include "e-source-selectable.h"
98 #include "e-source-smime.h"
99 #include "e-source-webdav.h"
100
101 #define E_SOURCE_GET_PRIVATE(obj) \
102         (G_TYPE_INSTANCE_GET_PRIVATE \
103         ((obj), E_TYPE_SOURCE, ESourcePrivate))
104
105 /* This forces the GType to be registered in a way that
106  * avoids a "statement with no effect" compiler warning. */
107 #define REGISTER_TYPE(type) \
108         (g_type_class_unref (g_type_class_ref (type)))
109
110 #define PRIMARY_GROUP_NAME      "Data Source"
111
112 typedef struct _AsyncContext AsyncContext;
113
114 struct _ESourcePrivate {
115         GDBusObject *dbus_object;
116         GMainContext *main_context;
117
118         GSource *changed;
119         GMutex *changed_lock;
120
121         GMutex *property_lock;
122
123         gchar *display_name;
124         gchar *collate_key;
125         gchar *parent;
126         gchar *uid;
127
128         /* The lock guards the key file and hash table. */
129
130         GKeyFile *key_file;
131         GStaticRecMutex lock;
132         GHashTable *extensions;
133
134         gboolean enabled;
135         gboolean initialized;
136 };
137
138 struct _AsyncContext {
139         ESource *scratch_source;
140 };
141
142 enum {
143         PROP_0,
144         PROP_DBUS_OBJECT,
145         PROP_DISPLAY_NAME,
146         PROP_ENABLED,
147         PROP_MAIN_CONTEXT,
148         PROP_PARENT,
149         PROP_REMOTE_CREATABLE,
150         PROP_REMOTE_DELETABLE,
151         PROP_REMOVABLE,
152         PROP_UID,
153         PROP_WRITABLE
154 };
155
156 enum {
157         CHANGED,
158         LAST_SIGNAL
159 };
160
161 static guint signals[LAST_SIGNAL];
162
163 /* Forward Declarations */
164 static void     e_source_initable_init          (GInitableIface *interface);
165
166 G_DEFINE_TYPE_WITH_CODE (
167         ESource,
168         e_source,
169         G_TYPE_OBJECT,
170         G_IMPLEMENT_INTERFACE (
171                 G_TYPE_INITABLE,
172                 e_source_initable_init))
173
174 static void
175 async_context_free (AsyncContext *async_context)
176 {
177         if (async_context->scratch_source != NULL)
178                 g_object_unref (async_context->scratch_source);
179
180         g_slice_free (AsyncContext, async_context);
181 }
182
183 static void
184 source_find_extension_classes_rec (GType parent_type,
185                                    GHashTable *hash_table)
186 {
187         GType *children;
188         guint n_children, ii;
189
190         children = g_type_children (parent_type, &n_children);
191
192         for (ii = 0; ii < n_children; ii++) {
193                 GType type = children[ii];
194                 ESourceExtensionClass *class;
195                 gpointer key;
196
197                 /* Recurse over the child's children. */
198                 source_find_extension_classes_rec (type, hash_table);
199
200                 /* Skip abstract types. */
201                 if (G_TYPE_IS_ABSTRACT (type))
202                         continue;
203
204                 class = g_type_class_ref (type);
205                 key = (gpointer) class->name;
206
207                 if (key != NULL)
208                         g_hash_table_insert (hash_table, key, class);
209                 else
210                         g_type_class_unref (class);
211         }
212
213         g_free (children);
214 }
215
216 static GHashTable *
217 source_find_extension_classes (void)
218 {
219         GHashTable *hash_table;
220
221         hash_table = g_hash_table_new_full (
222                 (GHashFunc) g_str_hash,
223                 (GEqualFunc) g_str_equal,
224                 (GDestroyNotify) NULL,
225                 (GDestroyNotify) g_type_class_unref);
226
227         source_find_extension_classes_rec (
228                 E_TYPE_SOURCE_EXTENSION, hash_table);
229
230         return hash_table;
231 }
232
233 static void
234 source_localized_hack (GKeyFile *key_file,
235                        const gchar *group_name,
236                        const gchar *key,
237                        const gchar *new_value)
238 {
239         const gchar * const *language_names;
240         gint ii;
241
242         /* XXX If we're changing a string key that has translations,
243          *     set "key[$CURRENT_LOCALE]" (if available) to the new
244          *     value so g_key_file_get_locale_string() will pick it
245          *     up.  This is not a perfect solution however.  When a
246          *     different locale is used the value may revert to its
247          *     original localized string.  Good enough for now. */
248
249         language_names = g_get_language_names ();
250
251         for (ii = 0; language_names[ii] != NULL; ii++) {
252                 gboolean has_localized_key;
253                 gchar *localized_key;
254
255                 localized_key = g_strdup_printf (
256                         "%s[%s]", key, language_names[ii]);
257                 has_localized_key = g_key_file_has_key (
258                         key_file, group_name, localized_key, NULL);
259
260                 if (has_localized_key)
261                         g_key_file_set_string (
262                                 key_file, group_name,
263                                 localized_key, new_value);
264
265                 g_free (localized_key);
266
267                 if (has_localized_key)
268                         return;
269         }
270
271         g_key_file_set_string (key_file, group_name, key, new_value);
272 }
273
274 static void
275 source_set_key_file_from_property (GObject *object,
276                                    GParamSpec *pspec,
277                                    GKeyFile *key_file,
278                                    const gchar *group_name)
279 {
280         GValue *pvalue;
281         GValue *svalue;
282         gchar *key;
283
284         pvalue = g_slice_new0 (GValue);
285         g_value_init (pvalue, pspec->value_type);
286         g_object_get_property (object, pspec->name, pvalue);
287
288         svalue = g_slice_new0 (GValue);
289         g_value_init (svalue, G_TYPE_STRING);
290
291         key = e_source_parameter_to_key (pspec->name);
292
293         /* For the most part we can just transform any supported
294          * property type to a string, with a couple exceptions. */
295
296         /* Transforming a boolean GValue to a string results in
297          * "TRUE" or "FALSE" (all uppercase), but GKeyFile only
298          * recognizes "true" or "false" (all lowercase).  So we
299          * have to use g_key_file_set_boolean(). */
300         if (G_VALUE_HOLDS_BOOLEAN (pvalue)) {
301                 gboolean v_boolean = g_value_get_boolean (pvalue);
302                 g_key_file_set_boolean (key_file, group_name, key, v_boolean);
303
304         /* Store UIN64 in hexa */
305         } else if (G_VALUE_HOLDS_UINT64 (pvalue)) {
306                 gchar *v_str;
307
308                 v_str = g_strdup_printf (
309                         "%016" G_GINT64_MODIFIER "X",
310                         g_value_get_uint64 (pvalue));
311                 g_key_file_set_string (key_file, group_name, key, v_str);
312                 g_free (v_str);
313
314         /* String GValues may contain characters that need escaping. */
315         } else if (G_VALUE_HOLDS_STRING (pvalue)) {
316                 const gchar *v_string = g_value_get_string (pvalue);
317
318                 if (v_string == NULL)
319                         v_string = "";
320
321                 /* Special case for localized "DisplayName" keys. */
322                 source_localized_hack (key_file, group_name, key, v_string);
323
324         /* Transforming an enum GValue to a string results in
325          * the GEnumValue name.  We want the shorter nickname. */
326         } else if (G_VALUE_HOLDS_ENUM (pvalue)) {
327                 GParamSpecEnum *enum_pspec;
328                 GEnumClass *enum_class;
329                 GEnumValue *enum_value;
330                 gint value;
331
332                 enum_pspec = G_PARAM_SPEC_ENUM (pspec);
333                 enum_class = enum_pspec->enum_class;
334
335                 value = g_value_get_enum (pvalue);
336                 enum_value = g_enum_get_value (enum_class, value);
337
338                 if (enum_value == NULL) {
339                         value = enum_pspec->default_value;
340                         enum_value = g_enum_get_value (enum_class, value);
341                 }
342
343                 if (enum_value != NULL)
344                         g_key_file_set_string (
345                                 key_file, group_name, key,
346                                 enum_value->value_nick);
347
348         } else if (G_VALUE_HOLDS (pvalue, G_TYPE_STRV)) {
349                 const gchar **strv = g_value_get_boxed (pvalue);
350                 guint length = 0;
351
352                 if (strv != NULL)
353                         length = g_strv_length ((gchar **) strv);
354                 g_key_file_set_string_list (
355                         key_file, group_name, key, strv, length);
356
357         /* For GValues holding a GFile object we save the URI. */
358         } else if (G_VALUE_HOLDS (pvalue, G_TYPE_FILE)) {
359                 GFile *file = g_value_get_object (pvalue);
360                 gchar *uri = NULL;
361
362                 if (file != NULL)
363                         uri = g_file_get_uri (file);
364                 g_key_file_set_string (
365                         key_file, group_name, key,
366                         (uri != NULL) ? uri : "");
367                 g_free (uri);
368
369         } else if (g_value_transform (pvalue, svalue)) {
370                 const gchar *value = g_value_get_string (svalue);
371                 g_key_file_set_value (key_file, group_name, key, value);
372         }
373
374         g_free (key);
375         g_value_unset (pvalue);
376         g_value_unset (svalue);
377         g_slice_free (GValue, pvalue);
378         g_slice_free (GValue, svalue);
379 }
380
381 static void
382 source_set_property_from_key_file (GObject *object,
383                                    GParamSpec *pspec,
384                                    GKeyFile *key_file,
385                                    const gchar *group_name)
386 {
387         gchar *key;
388         GValue *value;
389         GError *error = NULL;
390
391         value = g_slice_new0 (GValue);
392         key = e_source_parameter_to_key (pspec->name);
393
394         if (G_IS_PARAM_SPEC_CHAR (pspec) ||
395             G_IS_PARAM_SPEC_UCHAR (pspec) ||
396             G_IS_PARAM_SPEC_INT (pspec) ||
397             G_IS_PARAM_SPEC_UINT (pspec) ||
398             G_IS_PARAM_SPEC_LONG (pspec) ||
399             G_IS_PARAM_SPEC_ULONG (pspec)) {
400                 gint v_int;
401
402                 v_int = g_key_file_get_integer (
403                         key_file, group_name, key, &error);
404                 if (error == NULL) {
405                         g_value_init (value, G_TYPE_INT);
406                         g_value_set_int (value, v_int);
407                 }
408
409         } else if (G_IS_PARAM_SPEC_INT64 (pspec)) {
410                 gint64 v_int64;
411
412                 v_int64 = g_key_file_get_int64 (
413                         key_file, group_name, key, &error);
414                 if (error == NULL) {
415                         g_value_init (value, G_TYPE_INT64);
416                         g_value_set_int64 (value, v_int64);
417                 }
418
419         } else if (G_IS_PARAM_SPEC_UINT64 (pspec)) {
420                 guint64 v_uint64;
421                 gchar *v_str;
422
423                 v_str = g_key_file_get_string (
424                         key_file, group_name, key, &error);
425                 if (error == NULL) {
426                         v_uint64 = g_ascii_strtoull (v_str, NULL, 16);
427
428                         g_value_init (value, G_TYPE_UINT64);
429                         g_value_set_uint64 (value, v_uint64);
430                 }
431
432                 g_free (v_str);
433
434         } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
435                 gboolean v_boolean;
436
437                 v_boolean = g_key_file_get_boolean (
438                         key_file, group_name, key, &error);
439                 if (error == NULL) {
440                         g_value_init (value, G_TYPE_BOOLEAN);
441                         g_value_set_boolean (value, v_boolean);
442                 }
443
444         } else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
445                 gchar *nick;
446
447                 nick = g_key_file_get_string (
448                         key_file, group_name, key, &error);
449                 if (error == NULL) {
450                         GParamSpecEnum *enum_pspec;
451                         GEnumValue *enum_value;
452
453                         enum_pspec = G_PARAM_SPEC_ENUM (pspec);
454                         enum_value = g_enum_get_value_by_nick (
455                                 enum_pspec->enum_class, nick);
456                         if (enum_value != NULL) {
457                                 g_value_init (value, pspec->value_type);
458                                 g_value_set_enum (value, enum_value->value);
459                         }
460                         g_free (nick);
461                 }
462
463         } else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
464                    G_IS_PARAM_SPEC_DOUBLE (pspec)) {
465                 gdouble v_double;
466
467                 v_double = g_key_file_get_double (
468                         key_file, group_name, key, &error);
469                 if (error == NULL) {
470                         g_value_init (value, G_TYPE_DOUBLE);
471                         g_value_set_double (value, v_double);
472                 }
473
474         } else if (G_IS_PARAM_SPEC_STRING (pspec)) {
475                 gchar *v_string;
476
477                 /* Get the localized string if present. */
478                 v_string = g_key_file_get_locale_string (
479                         key_file, group_name, key, NULL, &error);
480                 if (error == NULL) {
481                         g_value_init (value, G_TYPE_STRING);
482                         g_value_take_string (value, v_string);
483                 }
484
485         } else if (g_type_is_a (pspec->value_type, G_TYPE_STRV)) {
486                 gchar **strv;
487
488                 strv = g_key_file_get_string_list (
489                         key_file, group_name, key, NULL, &error);
490                 if (error == NULL) {
491                         g_value_init (value, G_TYPE_STRV);
492                         g_value_take_boxed (value, strv);
493                 }
494
495         } else if (g_type_is_a (pspec->value_type, G_TYPE_FILE)) {
496                 gchar *uri;
497
498                 /* Create the GFile from the URI string. */
499                 uri = g_key_file_get_locale_string (
500                         key_file, group_name, key, NULL, &error);
501                 if (error == NULL) {
502                         GFile *file = NULL;
503                         if (uri != NULL && *uri != '\0')
504                                 file = g_file_new_for_uri (uri);
505                         g_value_init (value, pspec->value_type);
506                         g_value_take_object (value, file);
507                         g_free (uri);
508                 }
509
510         } else {
511                 g_warning (
512                         "No GKeyFile-to-GValue converter defined "
513                         "for type '%s'", G_PARAM_SPEC_TYPE_NAME (pspec));
514         }
515
516         /* If a value could not be retrieved from the key
517          * file, restore the property to its default value. */
518         if (error != NULL) {
519                 g_value_init (value, pspec->value_type);
520                 g_param_value_set_default (pspec, value);
521                 g_error_free (error);
522         }
523
524         if (G_IS_VALUE (value)) {
525                 g_object_set_property (object, pspec->name, value);
526                 g_value_unset (value);
527         }
528
529         g_slice_free (GValue, value);
530         g_free (key);
531 }
532
533 static void
534 source_load_from_key_file (GObject *object,
535                            GKeyFile *key_file,
536                            const gchar *group_name)
537 {
538         GObjectClass *class;
539         GParamSpec **properties;
540         guint n_properties, ii;
541
542         class = G_OBJECT_GET_CLASS (object);
543         properties = g_object_class_list_properties (class, &n_properties);
544
545         g_object_freeze_notify (object);
546
547         for (ii = 0; ii < n_properties; ii++) {
548                 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
549                         source_set_property_from_key_file (
550                                 object, properties[ii], key_file, group_name);
551                 }
552         }
553
554         g_object_thaw_notify (object);
555
556         g_free (properties);
557 }
558
559 static void
560 source_save_to_key_file (GObject *object,
561                          GKeyFile *key_file,
562                          const gchar *group_name)
563 {
564         GObjectClass *class;
565         GParamSpec **properties;
566         guint n_properties, ii;
567
568         class = G_OBJECT_GET_CLASS (object);
569         properties = g_object_class_list_properties (class, &n_properties);
570
571         for (ii = 0; ii < n_properties; ii++) {
572                 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
573                         source_set_key_file_from_property (
574                                 object, properties[ii], key_file, group_name);
575                 }
576         }
577
578         g_free (properties);
579 }
580
581 static gboolean
582 source_parse_dbus_data (ESource *source,
583                         GError **error)
584 {
585         GHashTableIter iter;
586         EDBusObject *dbus_object;
587         EDBusSource *dbus_source;
588         GKeyFile *key_file;
589         gpointer group_name;
590         gpointer extension;
591         gchar *data;
592         gboolean success;
593
594         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
595
596         dbus_source = e_dbus_object_get_source (dbus_object);
597         data = e_dbus_source_dup_data (dbus_source);
598         g_object_unref (dbus_source);
599
600         g_return_val_if_fail (data != NULL, FALSE);
601
602         key_file = source->priv->key_file;
603
604         success = g_key_file_load_from_data (
605                 key_file, data, strlen (data),
606                 G_KEY_FILE_KEEP_COMMENTS |
607                 G_KEY_FILE_KEEP_TRANSLATIONS,
608                 error);
609
610         g_free (data);
611         data = NULL;
612
613         if (!success)
614                 return FALSE;
615
616         /* Make sure the key file has a [Data Source] group. */
617         if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
618                 g_set_error (
619                         error, G_KEY_FILE_ERROR,
620                         G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
621                         _("Source file is missing a [%s] group"),
622                         PRIMARY_GROUP_NAME);
623                 return FALSE;
624         }
625
626         /* Load key file values from the [Data Source] group and from
627          * any other groups for which an extension object has already
628          * been created.  Note that not all the extension classes may
629          * be registered at this point, so avoid attempting to create
630          * new extension objects here.  Extension objects are created
631          * on-demand in e_source_get_extension(). */
632
633         source_load_from_key_file (
634                 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
635
636         g_hash_table_iter_init (&iter, source->priv->extensions);
637         while (g_hash_table_iter_next (&iter, &group_name, &extension))
638                 source_load_from_key_file (extension, key_file, group_name);
639
640         return TRUE;
641 }
642
643 static void
644 source_notify_dbus_data_cb (EDBusSource *dbus_source,
645                             GParamSpec *pspec,
646                             ESource *source)
647 {
648         GError *error = NULL;
649
650         g_static_rec_mutex_lock (&source->priv->lock);
651
652         /* Since the source data came from a GKeyFile structure on the
653          * server-side, this should never fail.  But we'll print error
654          * messages to the terminal just in case. */
655         if (!source_parse_dbus_data (source, &error)) {
656                 g_return_if_fail (error != NULL);
657                 g_warning ("%s", error->message);
658                 g_error_free (error);
659         }
660
661         g_static_rec_mutex_unlock (&source->priv->lock);
662 }
663
664 static gboolean
665 source_idle_changed_cb (gpointer user_data)
666 {
667         ESource *source = E_SOURCE (user_data);
668
669         /* If the ESource is still initializing itself in a different
670          * thread, skip the signal emission and try again on the next
671          * main loop iteration.  This is a busy wait but it should be
672          * a very short wait. */
673         if (!source->priv->initialized)
674                 return TRUE;
675
676         g_mutex_lock (source->priv->changed_lock);
677         if (source->priv->changed != NULL) {
678                 g_source_unref (source->priv->changed);
679                 source->priv->changed = NULL;
680         }
681         g_mutex_unlock (source->priv->changed_lock);
682
683         g_signal_emit (source, signals[CHANGED], 0);
684
685         return FALSE;
686 }
687
688 static void
689 source_set_dbus_object (ESource *source,
690                         EDBusObject *dbus_object)
691 {
692         /* D-Bus object will be NULL when configuring a new source. */
693         if (dbus_object == NULL)
694                 return;
695
696         g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
697         g_return_if_fail (source->priv->dbus_object == NULL);
698
699         source->priv->dbus_object = g_object_ref (dbus_object);
700 }
701
702 static void
703 source_set_main_context (ESource *source,
704                          GMainContext *main_context)
705 {
706         g_return_if_fail (source->priv->main_context == NULL);
707
708         source->priv->main_context =
709                 (main_context != NULL) ?
710                 g_main_context_ref (main_context) :
711                 g_main_context_ref_thread_default ();
712 }
713
714 static void
715 source_set_property (GObject *object,
716                      guint property_id,
717                      const GValue *value,
718                      GParamSpec *pspec)
719 {
720         switch (property_id) {
721                 case PROP_DBUS_OBJECT:
722                         source_set_dbus_object (
723                                 E_SOURCE (object),
724                                 g_value_get_object (value));
725                         return;
726
727                 case PROP_DISPLAY_NAME:
728                         e_source_set_display_name (
729                                 E_SOURCE (object),
730                                 g_value_get_string (value));
731                         return;
732
733                 case PROP_ENABLED:
734                         e_source_set_enabled (
735                                 E_SOURCE (object),
736                                 g_value_get_boolean (value));
737                         return;
738
739                 case PROP_MAIN_CONTEXT:
740                         source_set_main_context (
741                                 E_SOURCE (object),
742                                 g_value_get_boxed (value));
743                         return;
744
745                 case PROP_PARENT:
746                         e_source_set_parent (
747                                 E_SOURCE (object),
748                                 g_value_get_string (value));
749                         return;
750         }
751
752         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
753 }
754
755 static void
756 source_get_property (GObject *object,
757                      guint property_id,
758                      GValue *value,
759                      GParamSpec *pspec)
760 {
761         switch (property_id) {
762                 case PROP_DBUS_OBJECT:
763                         g_value_take_object (
764                                 value, e_source_ref_dbus_object (
765                                 E_SOURCE (object)));
766                         return;
767
768                 case PROP_DISPLAY_NAME:
769                         g_value_take_string (
770                                 value, e_source_dup_display_name (
771                                 E_SOURCE (object)));
772                         return;
773
774                 case PROP_ENABLED:
775                         g_value_set_boolean (
776                                 value, e_source_get_enabled (
777                                 E_SOURCE (object)));
778                         return;
779
780                 case PROP_MAIN_CONTEXT:
781                         g_value_take_boxed (
782                                 value, e_source_ref_main_context (
783                                 E_SOURCE (object)));
784                         return;
785
786                 case PROP_PARENT:
787                         g_value_take_string (
788                                 value, e_source_dup_parent (
789                                 E_SOURCE (object)));
790                         return;
791
792                 case PROP_REMOTE_CREATABLE:
793                         g_value_set_boolean (
794                                 value, e_source_get_remote_creatable (
795                                 E_SOURCE (object)));
796                         return;
797
798                 case PROP_REMOTE_DELETABLE:
799                         g_value_set_boolean (
800                                 value, e_source_get_remote_deletable (
801                                 E_SOURCE (object)));
802                         return;
803
804                 case PROP_REMOVABLE:
805                         g_value_set_boolean (
806                                 value, e_source_get_removable (
807                                 E_SOURCE (object)));
808                         return;
809
810                 case PROP_UID:
811                         g_value_take_string (
812                                 value, e_source_dup_uid (
813                                 E_SOURCE (object)));
814                         return;
815
816                 case PROP_WRITABLE:
817                         g_value_set_boolean (
818                                 value, e_source_get_writable (
819                                 E_SOURCE (object)));
820                         return;
821         }
822
823         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
824 }
825
826 static void
827 source_dispose (GObject *object)
828 {
829         ESourcePrivate *priv;
830
831         priv = E_SOURCE_GET_PRIVATE (object);
832
833         if (priv->dbus_object != NULL) {
834                 EDBusObject *dbus_object;
835                 EDBusSource *dbus_source;
836
837                 dbus_object = E_DBUS_OBJECT (priv->dbus_object);
838
839                 dbus_source = e_dbus_object_get_source (dbus_object);
840                 if (dbus_source != NULL) {
841                         g_signal_handlers_disconnect_matched (
842                                 dbus_source, G_SIGNAL_MATCH_DATA,
843                                 0, 0, NULL, NULL, object);
844                         g_object_unref (dbus_source);
845                 }
846
847                 g_object_unref (priv->dbus_object);
848                 priv->dbus_object = NULL;
849         }
850
851         if (priv->main_context != NULL) {
852                 g_main_context_unref (priv->main_context);
853                 priv->main_context = NULL;
854         }
855
856         /* XXX Maybe not necessary to acquire the lock? */
857         g_mutex_lock (priv->changed_lock);
858         if (priv->changed != NULL) {
859                 g_source_destroy (priv->changed);
860                 g_source_unref (priv->changed);
861                 priv->changed = NULL;
862         }
863         g_mutex_unlock (priv->changed_lock);
864
865         g_hash_table_remove_all (priv->extensions);
866
867         /* Chain up to parent's dispose() method. */
868         G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
869 }
870
871 static void
872 source_finalize (GObject *object)
873 {
874         ESourcePrivate *priv;
875
876         priv = E_SOURCE_GET_PRIVATE (object);
877
878         g_mutex_free (priv->changed_lock);
879         g_mutex_free (priv->property_lock);
880
881         g_free (priv->display_name);
882         g_free (priv->collate_key);
883         g_free (priv->parent);
884         g_free (priv->uid);
885
886         g_key_file_free (priv->key_file);
887         g_static_rec_mutex_free (&priv->lock);
888         g_hash_table_destroy (priv->extensions);
889
890         /* Chain up to parent's finalize() method. */
891         G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
892 }
893
894 static void
895 source_notify (GObject *object,
896                GParamSpec *pspec)
897 {
898         if ((pspec->flags & E_SOURCE_PARAM_SETTING) != 0)
899                 e_source_changed (E_SOURCE (object));
900 }
901
902 static gboolean
903 source_remove_sync (ESource *source,
904                     GCancellable *cancellable,
905                     GError **error)
906 {
907         EDBusObject *dbus_object;
908         EDBusSourceRemovable *dbus_source;
909         gboolean success;
910
911         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
912
913         dbus_source = e_dbus_object_get_source_removable (dbus_object);
914
915         if (dbus_source == NULL) {
916                 g_set_error (
917                         error, G_IO_ERROR,
918                         G_IO_ERROR_PERMISSION_DENIED,
919                         _("Data source '%s' is not removable"),
920                         e_source_get_display_name (source));
921                 return FALSE;
922         }
923
924         success = e_dbus_source_removable_call_remove_sync (
925                 dbus_source, cancellable, error);
926
927         g_object_unref (dbus_source);
928
929         return success;
930 }
931
932 /* Helper for source_remove() */
933 static void
934 source_remove_thread (GSimpleAsyncResult *simple,
935                       GObject *object,
936                       GCancellable *cancellable)
937 {
938         GError *error = NULL;
939
940         e_source_remove_sync (E_SOURCE (object), cancellable, &error);
941
942         if (error != NULL)
943                 g_simple_async_result_take_error (simple, error);
944 }
945
946 static void
947 source_remove (ESource *source,
948                GCancellable *cancellable,
949                GAsyncReadyCallback callback,
950                gpointer user_data)
951 {
952         GSimpleAsyncResult *simple;
953
954         simple = g_simple_async_result_new (
955                 G_OBJECT (source), callback, user_data, source_remove);
956
957         g_simple_async_result_set_check_cancellable (simple, cancellable);
958
959         g_simple_async_result_run_in_thread (
960                 simple, source_remove_thread,
961                 G_PRIORITY_DEFAULT, cancellable);
962
963         g_object_unref (simple);
964 }
965
966 static gboolean
967 source_remove_finish (ESource *source,
968                       GAsyncResult *result,
969                       GError **error)
970 {
971         GSimpleAsyncResult *simple;
972
973         g_return_val_if_fail (
974                 g_simple_async_result_is_valid (
975                 result, G_OBJECT (source), source_remove), FALSE);
976
977         simple = G_SIMPLE_ASYNC_RESULT (result);
978
979         /* Assume success unless a GError is set. */
980         return !g_simple_async_result_propagate_error (simple, error);
981 }
982
983 static gboolean
984 source_write_sync (ESource *source,
985                    GCancellable *cancellable,
986                    GError **error)
987 {
988         EDBusObject *dbus_object;
989         EDBusSourceWritable *dbus_source;
990         gboolean success;
991         gchar *data;
992
993         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
994
995         dbus_source = e_dbus_object_get_source_writable (dbus_object);
996
997         if (dbus_source == NULL) {
998                 g_set_error (
999                         error, G_IO_ERROR,
1000                         G_IO_ERROR_PERMISSION_DENIED,
1001                         _("Data source '%s' is not writable"),
1002                         e_source_get_display_name (source));
1003                 return FALSE;
1004         }
1005
1006         data = e_source_to_string (source, NULL);
1007
1008         success = e_dbus_source_writable_call_write_sync (
1009                 dbus_source, data, cancellable, error);
1010
1011         g_free (data);
1012
1013         g_object_unref (dbus_source);
1014
1015         return success;
1016 }
1017
1018 /* Helper for source_write() */
1019 static void
1020 source_write_thread (GSimpleAsyncResult *simple,
1021                      GObject *object,
1022                      GCancellable *cancellable)
1023 {
1024         GError *error = NULL;
1025
1026         e_source_write_sync (E_SOURCE (object), cancellable, &error);
1027
1028         if (error != NULL)
1029                 g_simple_async_result_take_error (simple, error);
1030 }
1031
1032 static void
1033 source_write (ESource *source,
1034               GCancellable *cancellable,
1035               GAsyncReadyCallback callback,
1036               gpointer user_data)
1037 {
1038         GSimpleAsyncResult *simple;
1039
1040         simple = g_simple_async_result_new (
1041                 G_OBJECT (source), callback, user_data, source_write);
1042
1043         g_simple_async_result_set_check_cancellable (simple, cancellable);
1044
1045         g_simple_async_result_run_in_thread (
1046                 simple, source_write_thread,
1047                 G_PRIORITY_DEFAULT, cancellable);
1048
1049         g_object_unref (simple);
1050 }
1051
1052 static gboolean
1053 source_write_finish (ESource *source,
1054                      GAsyncResult *result,
1055                      GError **error)
1056 {
1057         GSimpleAsyncResult *simple;
1058
1059         g_return_val_if_fail (
1060                 g_simple_async_result_is_valid (
1061                 result, G_OBJECT (source), source_write), FALSE);
1062
1063         simple = G_SIMPLE_ASYNC_RESULT (result);
1064
1065         /* Assume success unless a GError is set. */
1066         return !g_simple_async_result_propagate_error (simple, error);
1067 }
1068
1069 static gboolean
1070 source_remote_create_sync (ESource *source,
1071                            ESource *scratch_source,
1072                            GCancellable *cancellable,
1073                            GError **error)
1074 {
1075         EDBusSourceRemoteCreatable *dbus_interface = NULL;
1076         GDBusObject *dbus_object;
1077         gchar *uid, *data;
1078         gboolean success;
1079
1080         dbus_object = e_source_ref_dbus_object (source);
1081         if (dbus_object != NULL) {
1082                 dbus_interface =
1083                         e_dbus_object_get_source_remote_creatable (
1084                         E_DBUS_OBJECT (dbus_object));
1085                 g_object_unref (dbus_object);
1086         }
1087
1088         if (dbus_interface == NULL) {
1089                 g_set_error (
1090                         error, G_IO_ERROR,
1091                         G_IO_ERROR_NOT_SUPPORTED,
1092                         _("Data source '%s' does not "
1093                         "support creating remote resources"),
1094                         e_source_get_display_name (source));
1095                 return FALSE;
1096         }
1097
1098         uid = e_source_dup_uid (scratch_source);
1099         data = e_source_to_string (scratch_source, NULL);
1100
1101         success = e_dbus_source_remote_creatable_call_create_sync (
1102                 dbus_interface, uid, data, cancellable, error);
1103
1104         g_free (data);
1105         g_free (uid);
1106
1107         g_object_unref (dbus_interface);
1108
1109         return success;
1110 }
1111
1112 /* Helper for source_remote_create() */
1113 static void
1114 source_remote_create_thread (GSimpleAsyncResult *simple,
1115                              GObject *object,
1116                              GCancellable *cancellable)
1117 {
1118         AsyncContext *async_context;
1119         GError *error = NULL;
1120
1121         async_context = g_simple_async_result_get_op_res_gpointer (simple);
1122
1123         e_source_remote_create_sync (
1124                 E_SOURCE (object),
1125                 async_context->scratch_source,
1126                 cancellable, &error);
1127
1128         if (error != NULL)
1129                 g_simple_async_result_take_error (simple, error);
1130 }
1131
1132 static void
1133 source_remote_create (ESource *source,
1134                       ESource *scratch_source,
1135                       GCancellable *cancellable,
1136                       GAsyncReadyCallback callback,
1137                       gpointer user_data)
1138 {
1139         GSimpleAsyncResult *simple;
1140         AsyncContext *async_context;
1141
1142         async_context = g_slice_new0 (AsyncContext);
1143         async_context->scratch_source = g_object_ref (scratch_source);
1144
1145         simple = g_simple_async_result_new (
1146                 G_OBJECT (source), callback,
1147                 user_data, source_remote_create);
1148
1149         g_simple_async_result_set_check_cancellable (simple, cancellable);
1150
1151         g_simple_async_result_set_op_res_gpointer (
1152                 simple, async_context, (GDestroyNotify) async_context_free);
1153
1154         g_simple_async_result_run_in_thread (
1155                 simple, source_remote_create_thread,
1156                 G_PRIORITY_DEFAULT, cancellable);
1157
1158         g_object_unref (simple);
1159 }
1160
1161 static gboolean
1162 source_remote_create_finish (ESource *source,
1163                              GAsyncResult *result,
1164                              GError **error)
1165 {
1166         GSimpleAsyncResult *simple;
1167
1168         g_return_val_if_fail (
1169                 g_simple_async_result_is_valid (
1170                 result, G_OBJECT (source), source_remote_create), FALSE);
1171
1172         simple = G_SIMPLE_ASYNC_RESULT (result);
1173
1174         /* Assume success unless a GError is set. */
1175         return !g_simple_async_result_propagate_error (simple, error);
1176 }
1177
1178 static gboolean
1179 source_remote_delete_sync (ESource *source,
1180                            GCancellable *cancellable,
1181                            GError **error)
1182 {
1183         EDBusSourceRemoteDeletable *dbus_interface = NULL;
1184         GDBusObject *dbus_object;
1185         gboolean success;
1186
1187         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1188
1189         dbus_object = e_source_ref_dbus_object (source);
1190         if (dbus_object != NULL) {
1191                 dbus_interface =
1192                         e_dbus_object_get_source_remote_deletable (
1193                         E_DBUS_OBJECT (dbus_object));
1194                 g_object_unref (dbus_object);
1195         }
1196
1197         if (dbus_interface == NULL) {
1198                 g_set_error (
1199                         error, G_IO_ERROR,
1200                         G_IO_ERROR_NOT_SUPPORTED,
1201                         _("Data source '%s' does not "
1202                         "support deleting remote resources"),
1203                         e_source_get_display_name (source));
1204                 return FALSE;
1205         }
1206
1207         success = e_dbus_source_remote_deletable_call_delete_sync (
1208                 dbus_interface, cancellable, error);
1209
1210         g_object_unref (dbus_interface);
1211
1212         return success;
1213 }
1214
1215 /* Helper for source_remote_delete() */
1216 static void
1217 source_remote_delete_thread (GSimpleAsyncResult *simple,
1218                              GObject *object,
1219                              GCancellable *cancellable)
1220 {
1221         GError *error = NULL;
1222
1223         e_source_remote_delete_sync (
1224                 E_SOURCE (object), cancellable, &error);
1225
1226         if (error != NULL)
1227                 g_simple_async_result_take_error (simple, error);
1228 }
1229
1230 static void
1231 source_remote_delete (ESource *source,
1232                       GCancellable *cancellable,
1233                       GAsyncReadyCallback callback,
1234                       gpointer user_data)
1235 {
1236         GSimpleAsyncResult *simple;
1237
1238         simple = g_simple_async_result_new (
1239                 G_OBJECT (source), callback,
1240                 user_data, source_remote_delete);
1241
1242         g_simple_async_result_set_check_cancellable (simple, cancellable);
1243
1244         g_simple_async_result_run_in_thread (
1245                 simple, source_remote_delete_thread,
1246                 G_PRIORITY_DEFAULT, cancellable);
1247
1248         g_object_unref (simple);
1249 }
1250
1251 static gboolean
1252 source_remote_delete_finish (ESource *source,
1253                              GAsyncResult *result,
1254                              GError **error)
1255 {
1256         GSimpleAsyncResult *simple;
1257
1258         g_return_val_if_fail (
1259                 g_simple_async_result_is_valid (
1260                 result, G_OBJECT (source), source_remote_delete), FALSE);
1261
1262         simple = G_SIMPLE_ASYNC_RESULT (result);
1263
1264         /* Assume success unless a GError is set. */
1265         return !g_simple_async_result_propagate_error (simple, error);
1266 }
1267
1268 static gboolean
1269 source_initable_init (GInitable *initable,
1270                       GCancellable *cancellable,
1271                       GError **error)
1272 {
1273         ESource *source;
1274         gboolean success = TRUE;
1275
1276         source = E_SOURCE (initable);
1277
1278         /* The D-Bus object has the unique identifier (UID). */
1279         if (source->priv->dbus_object != NULL) {
1280                 EDBusObject *dbus_object;
1281                 EDBusSource *dbus_source;
1282
1283                 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1284
1285                 /* An EDBusObject lacking an EDBusSource
1286                  * interface indicates a programmer error. */
1287                 dbus_source = e_dbus_object_get_source (dbus_object);
1288                 g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1289
1290                 /* Allow authentication prompts for a data source
1291                  * when a new client-side proxy object is created.
1292                  * The thought being if you cancel an authentication
1293                  * prompt you won't be bothered again until you start
1294                  * (or restart) a new E-D-S client app.
1295                  *
1296                  * Failure here is non-fatal, ignore errors.
1297                  *
1298                  * XXX Only GDBusProxy objects may call this.  Sources
1299                  *     created server-side can't invoke remote methods.
1300                  */
1301                 if (G_IS_DBUS_PROXY (dbus_source))
1302                         e_dbus_source_call_allow_auth_prompt_sync (
1303                                 dbus_source, cancellable, NULL);
1304
1305                 /* The UID never changes, so we can cache a copy. */
1306                 source->priv->uid = e_dbus_source_dup_uid (dbus_source);
1307
1308                 g_signal_connect (
1309                         dbus_source, "notify::data",
1310                         G_CALLBACK (source_notify_dbus_data_cb), source);
1311
1312                 success = source_parse_dbus_data (source, error);
1313
1314                 g_object_unref (dbus_source);
1315
1316         /* No D-Bus object implies we're configuring a new source,
1317          * so generate a new unique identifier (UID) for it. */
1318         } else {
1319                 source->priv->uid = e_uid_new ();
1320         }
1321
1322         /* Try to avoid a spurious "changed" emission. */
1323         g_mutex_lock (source->priv->changed_lock);
1324         if (source->priv->changed != NULL) {
1325                 g_source_destroy (source->priv->changed);
1326                 g_source_unref (source->priv->changed);
1327                 source->priv->changed = NULL;
1328         }
1329         g_mutex_unlock (source->priv->changed_lock);
1330
1331         source->priv->initialized = TRUE;
1332
1333         return success;
1334 }
1335
1336 static void
1337 e_source_class_init (ESourceClass *class)
1338 {
1339         GObjectClass *object_class;
1340
1341         g_type_class_add_private (class, sizeof (ESourcePrivate));
1342
1343         object_class = G_OBJECT_CLASS (class);
1344         object_class->set_property = source_set_property;
1345         object_class->get_property = source_get_property;
1346         object_class->dispose = source_dispose;
1347         object_class->finalize = source_finalize;
1348         object_class->notify = source_notify;
1349
1350         class->remove_sync = source_remove_sync;
1351         class->remove = source_remove;
1352         class->remove_finish = source_remove_finish;
1353         class->write_sync = source_write_sync;
1354         class->write = source_write;
1355         class->write_finish = source_write_finish;
1356         class->remote_create_sync = source_remote_create_sync;
1357         class->remote_create = source_remote_create;
1358         class->remote_create_finish = source_remote_create_finish;
1359         class->remote_delete_sync = source_remote_delete_sync;
1360         class->remote_delete = source_remote_delete;
1361         class->remote_delete_finish = source_remote_delete_finish;
1362
1363         g_object_class_install_property (
1364                 object_class,
1365                 PROP_DBUS_OBJECT,
1366                 g_param_spec_object (
1367                         "dbus-object",
1368                         "D-Bus Object",
1369                         "The D-Bus object for the data source",
1370                         E_DBUS_TYPE_OBJECT,
1371                         G_PARAM_READWRITE |
1372                         G_PARAM_CONSTRUCT_ONLY |
1373                         G_PARAM_STATIC_STRINGS));
1374
1375         g_object_class_install_property (
1376                 object_class,
1377                 PROP_DISPLAY_NAME,
1378                 g_param_spec_string (
1379                         "display-name",
1380                         "Display Name",
1381                         "The human-readable name of the data source",
1382                         _("Unnamed"),
1383                         G_PARAM_READWRITE |
1384                         G_PARAM_CONSTRUCT |
1385                         G_PARAM_STATIC_STRINGS |
1386                         E_SOURCE_PARAM_SETTING));
1387
1388         g_object_class_install_property (
1389                 object_class,
1390                 PROP_ENABLED,
1391                 g_param_spec_boolean (
1392                         "enabled",
1393                         "Enabled",
1394                         "Whether the data source is enabled",
1395                         TRUE,
1396                         G_PARAM_READWRITE |
1397                         G_PARAM_CONSTRUCT |
1398                         G_PARAM_STATIC_STRINGS |
1399                         E_SOURCE_PARAM_SETTING));
1400
1401         g_object_class_install_property (
1402                 object_class,
1403                 PROP_MAIN_CONTEXT,
1404                 g_param_spec_boxed (
1405                         "main-context",
1406                         "Main Context",
1407                         "The GMainContext used for signal emissions",
1408                         G_TYPE_MAIN_CONTEXT,
1409                         G_PARAM_READWRITE |
1410                         G_PARAM_CONSTRUCT_ONLY |
1411                         G_PARAM_STATIC_STRINGS));
1412
1413         g_object_class_install_property (
1414                 object_class,
1415                 PROP_PARENT,
1416                 g_param_spec_string (
1417                         "parent",
1418                         "Parent",
1419                         "The unique identity of the parent data source",
1420                         NULL,
1421                         G_PARAM_READWRITE |
1422                         G_PARAM_STATIC_STRINGS |
1423                         E_SOURCE_PARAM_SETTING));
1424
1425         g_object_class_install_property (
1426                 object_class,
1427                 PROP_REMOTE_CREATABLE,
1428                 g_param_spec_boolean (
1429                         "remote-creatable",
1430                         "Remote Creatable",
1431                         "Whether the data source "
1432                         "can create remote resources",
1433                         FALSE,
1434                         G_PARAM_READABLE |
1435                         G_PARAM_STATIC_STRINGS));
1436
1437         g_object_class_install_property (
1438                 object_class,
1439                 PROP_REMOTE_DELETABLE,
1440                 g_param_spec_boolean (
1441                         "remote-deletable",
1442                         "Remote Deletable",
1443                         "Whether the data source "
1444                         "can delete remote resources",
1445                         FALSE,
1446                         G_PARAM_READABLE |
1447                         G_PARAM_STATIC_STRINGS));
1448
1449         g_object_class_install_property (
1450                 object_class,
1451                 PROP_REMOVABLE,
1452                 g_param_spec_boolean (
1453                         "removable",
1454                         "Removable",
1455                         "Whether the data source is removable",
1456                         FALSE,
1457                         G_PARAM_READABLE |
1458                         G_PARAM_STATIC_STRINGS));
1459
1460         g_object_class_install_property (
1461                 object_class,
1462                 PROP_UID,
1463                 g_param_spec_string (
1464                         "uid",
1465                         "UID",
1466                         "The unique identity of the data source",
1467                         NULL,
1468                         G_PARAM_READABLE |
1469                         G_PARAM_STATIC_STRINGS));
1470
1471         g_object_class_install_property (
1472                 object_class,
1473                 PROP_WRITABLE,
1474                 g_param_spec_boolean (
1475                         "writable",
1476                         "Writable",
1477                         "Whether the data source is writable",
1478                         FALSE,
1479                         G_PARAM_READABLE |
1480                         G_PARAM_STATIC_STRINGS));
1481
1482         /**
1483          * ESource::changed:
1484          * @source: the #ESource that received the signal
1485          *
1486          * The ::changed signal is emitted when a property in @source or
1487          * one of its extension objects changes.  A common use for this
1488          * signal is to notify a #GtkTreeModel containing data collected
1489          * from #ESource<!-- -->s that it needs to update a row.
1490          **/
1491         signals[CHANGED] = g_signal_new (
1492                 "changed",
1493                 G_TYPE_FROM_CLASS (class),
1494                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
1495                 G_STRUCT_OFFSET (ESourceClass, changed),
1496                 NULL, NULL,
1497                 g_cclosure_marshal_VOID__VOID,
1498                 G_TYPE_NONE, 0);
1499
1500         /* Register built-in ESourceExtension types. */
1501         REGISTER_TYPE (E_TYPE_SOURCE_ADDRESS_BOOK);
1502         REGISTER_TYPE (E_TYPE_SOURCE_ALARMS);
1503         REGISTER_TYPE (E_TYPE_SOURCE_AUTHENTICATION);
1504         REGISTER_TYPE (E_TYPE_SOURCE_AUTOCOMPLETE);
1505         REGISTER_TYPE (E_TYPE_SOURCE_CALENDAR);
1506         REGISTER_TYPE (E_TYPE_SOURCE_COLLECTION);
1507         REGISTER_TYPE (E_TYPE_SOURCE_GOA);
1508         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_ACCOUNT);
1509         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_COMPOSITION);
1510         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_IDENTITY);
1511         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_SIGNATURE);
1512         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_SUBMISSION);
1513         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_TRANSPORT);
1514         REGISTER_TYPE (E_TYPE_SOURCE_MDN);
1515         REGISTER_TYPE (E_TYPE_SOURCE_MEMO_LIST);
1516         REGISTER_TYPE (E_TYPE_SOURCE_OFFLINE);
1517         REGISTER_TYPE (E_TYPE_SOURCE_OPENPGP);
1518         REGISTER_TYPE (E_TYPE_SOURCE_REFRESH);
1519         REGISTER_TYPE (E_TYPE_SOURCE_RESOURCE);
1520         REGISTER_TYPE (E_TYPE_SOURCE_SECURITY);
1521         REGISTER_TYPE (E_TYPE_SOURCE_SELECTABLE);
1522         REGISTER_TYPE (E_TYPE_SOURCE_SMIME);
1523         REGISTER_TYPE (E_TYPE_SOURCE_TASK_LIST);
1524         REGISTER_TYPE (E_TYPE_SOURCE_WEBDAV);
1525 }
1526
1527 static void
1528 e_source_initable_init (GInitableIface *interface)
1529 {
1530         interface->init = source_initable_init;
1531 }
1532
1533 static void
1534 e_source_init (ESource *source)
1535 {
1536         GHashTable *extensions;
1537
1538         /* Don't do this as part of class initialization because it
1539          * loads Camel modules and can screw up introspection, which
1540          * occurs at compile-time before Camel modules are installed. */
1541         e_source_camel_register_types ();
1542
1543         extensions = g_hash_table_new_full (
1544                 (GHashFunc) g_str_hash,
1545                 (GEqualFunc) g_str_equal,
1546                 (GDestroyNotify) g_free,
1547                 (GDestroyNotify) g_object_unref);
1548
1549         source->priv = E_SOURCE_GET_PRIVATE (source);
1550         source->priv->changed_lock = g_mutex_new ();
1551         source->priv->property_lock = g_mutex_new ();
1552         source->priv->key_file = g_key_file_new ();
1553         source->priv->extensions = extensions;
1554
1555         g_static_rec_mutex_init (&source->priv->lock);
1556 }
1557
1558 /**
1559  * e_source_new:
1560  * @dbus_object: (allow-none): a #GDBusObject or %NULL
1561  * @main_context: (allow-none): a #GMainContext or %NULL
1562  * @error: return location for a #GError, or %NULL
1563  *
1564  * Creates a new #ESource instance.
1565  *
1566  * The #ESource::changed signal will be emitted from @main_context if given,
1567  * or else from the thread-default #GMainContext at the time this function is
1568  * called.
1569  *
1570  * The only time the function should be called outside of #ESourceRegistry
1571  * is to create a so-called "scratch" #ESource for editing in a Properties
1572  * window or an account setup assistant.
1573  *
1574  * FIXME: Elaborate on scratch sources.
1575  *
1576  * Returns: a new #ESource, or %NULL on error
1577  *
1578  * Since: 3.6
1579  **/
1580 ESource *
1581 e_source_new (GDBusObject *dbus_object,
1582               GMainContext *main_context,
1583               GError **error)
1584 {
1585         if (dbus_object != NULL)
1586                 g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), NULL);
1587
1588         return g_initable_new (
1589                 E_TYPE_SOURCE, NULL, error,
1590                 "dbus-object", dbus_object,
1591                 "main-context", main_context,
1592                 NULL);
1593 }
1594
1595 /**
1596  * e_source_hash:
1597  * @source: an #ESource
1598  *
1599  * Generates a hash value for @source.  This function is intended for
1600  * easily hashing an #ESource to add to a #GHashTable or similar data
1601  * structure.
1602  *
1603  * Returns: a hash value for @source.
1604  *
1605  * Since: 3.6
1606  **/
1607 guint
1608 e_source_hash (ESource *source)
1609 {
1610         const gchar *uid;
1611
1612         g_return_val_if_fail (E_IS_SOURCE (source), 0);
1613
1614         uid = e_source_get_uid (source);
1615
1616         return g_str_hash (uid);
1617 }
1618
1619 /**
1620  * e_source_equal:
1621  * @source1: the first #ESource
1622  * @source2: the second #ESource
1623  *
1624  * Checks two #ESource instances for equality.  #ESource instances are
1625  * equal if their unique identifier strings are equal.
1626  *
1627  * Returns: %TRUE if @source1 and @source2 are equal
1628  *
1629  * Since: 3.6
1630  **/
1631 gboolean
1632 e_source_equal (ESource *source1,
1633                 ESource *source2)
1634 {
1635         const gchar *uid1, *uid2;
1636
1637         g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
1638         g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
1639
1640         if (source1 == source2)
1641                 return TRUE;
1642
1643         uid1 = e_source_get_uid (source1);
1644         uid2 = e_source_get_uid (source2);
1645
1646         return g_str_equal (uid1, uid2);
1647 }
1648
1649 /**
1650  * e_source_changed:
1651  * @source: an #ESource
1652  *
1653  * Emits the #ESource::changed signal from an idle callback in
1654  * @source's #ESource:main-context.
1655  *
1656  * This function is primarily intended for use by #ESourceExtension
1657  * when emitting a #GObject::notify signal on one of its properties.
1658  *
1659  * Since: 3.6
1660  **/
1661 void
1662 e_source_changed (ESource *source)
1663 {
1664         g_return_if_fail (E_IS_SOURCE (source));
1665
1666         g_mutex_lock (source->priv->changed_lock);
1667         if (source->priv->changed == NULL) {
1668                 source->priv->changed = g_idle_source_new ();
1669                 g_source_set_callback (
1670                         source->priv->changed,
1671                         source_idle_changed_cb,
1672                         source, (GDestroyNotify) NULL);
1673                 g_source_attach (
1674                         source->priv->changed,
1675                         source->priv->main_context);
1676         }
1677         g_mutex_unlock (source->priv->changed_lock);
1678 }
1679
1680 /**
1681  * e_source_get_uid:
1682  * @source: an #ESource
1683  *
1684  * Returns the unique identifier string for @source.
1685  *
1686  * Returns: the UID for @source
1687  *
1688  * Since: 3.6
1689  **/
1690 const gchar *
1691 e_source_get_uid (ESource *source)
1692 {
1693         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1694
1695         return source->priv->uid;
1696 }
1697
1698 /**
1699  * e_source_dup_uid:
1700  * @source: an #ESource
1701  *
1702  * Thread-safe variation of e_source_get_uid().
1703  * Use this function when accessing @source from multiple threads.
1704  *
1705  * The returned string should be freed with g_free() when no longer needed.
1706  *
1707  * Returns: a newly-allocated copy of #ESource:uid
1708  *
1709  * Since: 3.6
1710  **/
1711 gchar *
1712 e_source_dup_uid (ESource *source)
1713 {
1714         const gchar *protected;
1715         gchar *duplicate;
1716
1717         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1718
1719         /* Perhaps we don't need to lock the mutex since
1720          * this is a read-only property but it can't hurt. */
1721
1722         g_mutex_lock (source->priv->property_lock);
1723
1724         protected = e_source_get_uid (source);
1725         duplicate = g_strdup (protected);
1726
1727         g_mutex_unlock (source->priv->property_lock);
1728
1729         return duplicate;
1730 }
1731
1732 /**
1733  * e_source_get_parent:
1734  * @source: an #ESource
1735  *
1736  * Returns the unique identifier string of the parent #ESource.
1737  *
1738  * Returns: the UID of the parent #ESource
1739  *
1740  * Since: 3.6
1741  **/
1742 const gchar *
1743 e_source_get_parent (ESource *source)
1744 {
1745         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1746
1747         return source->priv->parent;
1748 }
1749
1750 /**
1751  * e_source_dup_parent:
1752  * @source: an #ESource
1753  *
1754  * Thread-safe variation of e_source_get_parent().
1755  * Use this function when accessing @source from multiple threads.
1756  *
1757  * The returned string should be freed with g_free() when no longer needed.
1758  *
1759  * Returns: a newly-allocated copy of #ESource:parent
1760  *
1761  * Since: 3.6
1762  **/
1763 gchar *
1764 e_source_dup_parent (ESource *source)
1765 {
1766         const gchar *protected;
1767         gchar *duplicate;
1768
1769         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1770
1771         g_mutex_lock (source->priv->property_lock);
1772
1773         protected = e_source_get_parent (source);
1774         duplicate = g_strdup (protected);
1775
1776         g_mutex_unlock (source->priv->property_lock);
1777
1778         return duplicate;
1779 }
1780
1781 /**
1782  * e_source_set_parent:
1783  * @source: an #ESource
1784  * @parent: (allow-none): the UID of the parent #ESource, or %NULL
1785  *
1786  * Identifies the parent of @source by its unique identifier string.
1787  * This can only be set prior to adding @source to an #ESourceRegistry.
1788  *
1789  * The internal copy of #ESource:parent is automatically stripped of leading
1790  * and trailing whitespace.  If the resulting string is empty, %NULL is set
1791  * instead.
1792  *
1793  * Since: 3.6
1794  **/
1795 void
1796 e_source_set_parent (ESource *source,
1797                      const gchar *parent)
1798 {
1799         g_return_if_fail (E_IS_SOURCE (source));
1800
1801         g_mutex_lock (source->priv->property_lock);
1802
1803         if (g_strcmp0 (source->priv->parent, parent) == 0) {
1804                 g_mutex_unlock (source->priv->property_lock);
1805                 return;
1806         }
1807
1808         g_free (source->priv->parent);
1809         source->priv->parent = e_util_strdup_strip (parent);
1810
1811         g_mutex_unlock (source->priv->property_lock);
1812
1813         g_object_notify (G_OBJECT (source), "parent");
1814 }
1815
1816 /**
1817  * e_source_get_enabled:
1818  * @source: an #ESource
1819  *
1820  * Returns %TRUE if @source is enabled.
1821  *
1822  * An application should try to honor this setting if at all possible,
1823  * even if it does not provide a way to change the setting through its
1824  * user interface.  Disabled data sources should generally be hidden.
1825  *
1826  * Returns: whether @source is enabled
1827  *
1828  * Since: 3.6
1829  **/
1830 gboolean
1831 e_source_get_enabled (ESource *source)
1832 {
1833         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1834
1835         return source->priv->enabled;
1836 }
1837
1838 /**
1839  * e_source_set_enabled:
1840  * @source: an #ESource
1841  * @enabled: whether to enable @source
1842  *
1843  * Enables or disables @source.
1844  *
1845  * An application should try to honor this setting if at all possible,
1846  * even if it does not provide a way to change the setting through its
1847  * user interface.  Disabled data sources should generally be hidden.
1848  *
1849  * Since: 3.6
1850  **/
1851 void
1852 e_source_set_enabled (ESource *source,
1853                       gboolean enabled)
1854 {
1855         g_return_if_fail (E_IS_SOURCE (source));
1856
1857         if (source->priv->enabled == enabled)
1858                 return;
1859
1860         source->priv->enabled = enabled;
1861
1862         g_object_notify (G_OBJECT (source), "enabled");
1863 }
1864
1865 /**
1866  * e_source_get_writable:
1867  * @source: an #ESource
1868  *
1869  * Returns whether the D-Bus service will accept changes to @source.
1870  * If @source is not writable, calls to e_source_write() will fail.
1871  *
1872  * Returns: whether @source is writable
1873  *
1874  * Since: 3.6
1875  **/
1876 gboolean
1877 e_source_get_writable (ESource *source)
1878 {
1879         EDBusObject *dbus_object;
1880         EDBusSourceWritable *dbus_source;
1881
1882         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1883
1884         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1885         dbus_source = e_dbus_object_peek_source_writable (dbus_object);
1886
1887         return (dbus_source != NULL);
1888 }
1889
1890 /**
1891  * e_source_get_removable:
1892  * @source: an #ESource
1893  *
1894  * Returns whether the D-Bus service will allow @source to be removed.
1895  * If @source is not writable, calls to e_source_remove() will fail.
1896  *
1897  * Returns: whether @source is removable
1898  *
1899  * Since: 3.6
1900  **/
1901 gboolean
1902 e_source_get_removable (ESource *source)
1903 {
1904         EDBusObject *dbus_object;
1905         EDBusSourceRemovable *dbus_source;
1906
1907         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1908
1909         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1910         dbus_source = e_dbus_object_peek_source_removable (dbus_object);
1911
1912         return (dbus_source != NULL);
1913 }
1914
1915 /**
1916  * e_source_get_remote_creatable:
1917  * @source: an #ESource
1918  *
1919  * Returns whether new resources can be created on a remote server by
1920  * calling e_source_remote_create() on @source.
1921  *
1922  * Generally this is only %TRUE if @source has an #ESourceCollection
1923  * extension, which means there is an #ECollectionBackend in the D-Bus
1924  * service that can handle create requests.  If @source does not have
1925  * this capability, calls to e_source_remote_create() will fail.
1926  *
1927  * Returns: whether @source can create remote resources
1928  *
1929  * Since: 3.6
1930  **/
1931 gboolean
1932 e_source_get_remote_creatable (ESource *source)
1933 {
1934         EDBusObject *dbus_object;
1935         EDBusSourceRemoteCreatable *dbus_source;
1936
1937         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1938
1939         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1940         dbus_source = e_dbus_object_peek_source_remote_creatable (dbus_object);
1941
1942         return (dbus_source != NULL);
1943 }
1944
1945 /**
1946  * e_source_get_remote_deletable:
1947  * @source: an #ESource
1948  *
1949  * Returns whether the resource represented by @source can be deleted
1950  * from a remote server by calling e_source_remote_delete().
1951  *
1952  * Generally this is only %TRUE if @source is a child of an #ESource
1953  * which has an #ESourceCollection extension, which means there is an
1954  * #ECollectionBackend in the D-Bus service that can handle delete
1955  * requests.  If @source does not have this capability, calls to
1956  * e_source_remote_delete() will fail.
1957  *
1958  * Returns: whether @source can delete remote resources
1959  *
1960  * Since: 3.6
1961  **/
1962 gboolean
1963 e_source_get_remote_deletable (ESource *source)
1964 {
1965         EDBusObject *dbus_object;
1966         EDBusSourceRemoteDeletable *dbus_source;
1967
1968         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1969
1970         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1971         dbus_source = e_dbus_object_peek_source_remote_deletable (dbus_object);
1972
1973         return (dbus_source != NULL);
1974 }
1975
1976 /**
1977  * e_source_get_extension:
1978  * @source: an #ESource
1979  * @extension_name: an extension name
1980  *
1981  * Returns an instance of some #ESourceExtension subclass which registered
1982  * itself under @extension_name.  If no such instance exists within @source,
1983  * one will be created.  It is the caller's responsibility to know which
1984  * subclass is being returned.
1985  *
1986  * If you just want to test for the existence of an extension within @source
1987  * without creating it, use e_source_has_extension().
1988  *
1989  * Extension instances are owned by their #ESource and should not be
1990  * referenced directly.  Instead, reference the #ESource instance and
1991  * use this function to fetch the extension instance as needed.
1992  *
1993  * Returns: (type ESourceExtension) (transfer none): an instance of some
1994  * #ESourceExtension subclass
1995  *
1996  * Since: 3.6
1997  **/
1998 gpointer
1999 e_source_get_extension (ESource *source,
2000                         const gchar *extension_name)
2001 {
2002         ESourceExtension *extension;
2003         GHashTable *hash_table;
2004         GTypeClass *class;
2005
2006         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2007         g_return_val_if_fail (extension_name != NULL, NULL);
2008
2009         g_static_rec_mutex_lock (&source->priv->lock);
2010
2011         /* Check if we already have the extension. */
2012         extension = g_hash_table_lookup (
2013                 source->priv->extensions, extension_name);
2014         if (extension != NULL)
2015                 goto exit;
2016
2017         /* Find all subclasses of ESourceExtensionClass. */
2018         hash_table = source_find_extension_classes ();
2019         class = g_hash_table_lookup (hash_table, extension_name);
2020
2021         /* Create a new instance of the appropriate GType. */
2022         if (class != NULL) {
2023                 extension = g_object_new (
2024                         G_TYPE_FROM_CLASS (class),
2025                         "source", source, NULL);
2026                 source_load_from_key_file (
2027                         G_OBJECT (extension),
2028                         source->priv->key_file,
2029                         extension_name);
2030                 g_hash_table_insert (
2031                         source->priv->extensions,
2032                         g_strdup (extension_name), extension);
2033         } else {
2034                 /* XXX Tie this into a debug setting for ESources. */
2035 #ifdef DEBUG
2036                 g_critical (
2037                         "No registered GType for ESource "
2038                         "extension '%s'", extension_name);
2039 #endif
2040         }
2041
2042         g_hash_table_destroy (hash_table);
2043
2044 exit:
2045         g_static_rec_mutex_unlock (&source->priv->lock);
2046
2047         return extension;
2048 }
2049
2050 /**
2051  * e_source_has_extension:
2052  * @source: an #ESource
2053  * @extension_name: an extension name
2054  *
2055  * Checks whether @source has an #ESourceExtension with the given name.
2056  *
2057  * Returns: %TRUE if @source has such an extension, %FALSE if not
2058  *
2059  * Since: 3.6
2060  **/
2061 gboolean
2062 e_source_has_extension (ESource *source,
2063                         const gchar *extension_name)
2064 {
2065         ESourceExtension *extension;
2066
2067         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2068         g_return_val_if_fail (extension_name != NULL, FALSE);
2069
2070         g_static_rec_mutex_lock (&source->priv->lock);
2071
2072         /* Two cases to check for, either one is good enough:
2073          * 1) Our internal GKeyFile has a group named 'extension_name'.
2074          * 2) Our 'extensions' table has an entry for 'extension_name'.
2075          *
2076          * We have to check both data structures in case a new extension
2077          * not present in the GKeyFile was instantiated, but we have not
2078          * yet updated our internal GKeyFile.  A common occurrence when
2079          * editing a brand new data source.
2080          *
2081          * When checking the GKeyFile we want to actually fetch the
2082          * extension with e_source_get_extension() to make sure it's
2083          * a registered extension name and not just an arbitrary key
2084          * file group name. */
2085
2086         if (g_key_file_has_group (source->priv->key_file, extension_name)) {
2087                 extension = e_source_get_extension (source, extension_name);
2088         } else {
2089                 GHashTable *hash_table = source->priv->extensions;
2090                 extension = g_hash_table_lookup (hash_table, extension_name);
2091         }
2092
2093         g_static_rec_mutex_unlock (&source->priv->lock);
2094
2095         return (extension != NULL);
2096 }
2097
2098 /**
2099  * e_source_ref_dbus_object:
2100  * @source: an #ESource
2101  *
2102  * Returns the #GDBusObject that was passed to e_source_new().
2103  *
2104  * The returned #GDBusObject is referenced for thread-safety and must be
2105  * unreferenced with g_object_unref() when finished with it.
2106  *
2107  * Returns: (transfer full): the #GDBusObject for @source, or %NULL
2108  *
2109  * Since: 3.6
2110  **/
2111 GDBusObject *
2112 e_source_ref_dbus_object (ESource *source)
2113 {
2114         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2115
2116         if (source->priv->dbus_object == NULL)
2117                 return NULL;
2118
2119         return g_object_ref (source->priv->dbus_object);
2120 }
2121
2122 /**
2123  * e_source_ref_main_context:
2124  * @source: an #ESource
2125  *
2126  * Returns the #GMainContext from which #ESource::changed signals are
2127  * emitted.
2128  *
2129  * The returned #GMainContext is referenced for thread-safety and must be
2130  * unreferenced with g_main_context_unref() when finished with it.
2131  *
2132  * Returns: (transfer full): the #GMainContext for signal emissions
2133  *
2134  * Since: 3.6
2135  **/
2136 GMainContext *
2137 e_source_ref_main_context (ESource *source)
2138 {
2139         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2140
2141         return g_main_context_ref (source->priv->main_context);
2142 }
2143
2144 /**
2145  * e_source_get_display_name:
2146  * @source: an #ESource
2147  *
2148  * Returns the display name for @source.  Use the display name to
2149  * represent the #ESource in a user interface.
2150  *
2151  * Returns: the display name for @source
2152  *
2153  * Since: 3.6
2154  **/
2155 const gchar *
2156 e_source_get_display_name (ESource *source)
2157 {
2158         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2159
2160         return source->priv->display_name;
2161 }
2162
2163 /**
2164  * e_source_dup_display_name:
2165  * @source: an #ESource
2166  *
2167  * Thread-safe variation of e_source_get_display_name().
2168  * Use this function when accessing @source from multiple threads.
2169  *
2170  * The returned string should be freed with g_free() when no longer needed.
2171  *
2172  * Returns: a newly-allocated copy of #ESource:display-name
2173  *
2174  * Since: 3.6
2175  **/
2176 gchar *
2177 e_source_dup_display_name (ESource *source)
2178 {
2179         const gchar *protected;
2180         gchar *duplicate;
2181
2182         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2183
2184         g_mutex_lock (source->priv->property_lock);
2185
2186         protected = e_source_get_display_name (source);
2187         duplicate = g_strdup (protected);
2188
2189         g_mutex_unlock (source->priv->property_lock);
2190
2191         return duplicate;
2192 }
2193
2194 /**
2195  * e_source_set_display_name:
2196  * @source: an #ESource
2197  * @display_name: a display name
2198  *
2199  * Sets the display name for @source.  The @display_name argument must be a
2200  * valid UTF-8 string.  Use the display name to represent the #ESource in a
2201  * user interface.
2202  *
2203  * The internal copy of @display_name is automatically stripped of leading
2204  * and trailing whitespace.
2205  *
2206  * Since: 3.6
2207  **/
2208 void
2209 e_source_set_display_name (ESource *source,
2210                            const gchar *display_name)
2211 {
2212         g_return_if_fail (E_IS_SOURCE (source));
2213         g_return_if_fail (display_name != NULL);
2214         g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
2215
2216         g_mutex_lock (source->priv->property_lock);
2217
2218         if (g_strcmp0 (source->priv->display_name, display_name) == 0) {
2219                 g_mutex_unlock (source->priv->property_lock);
2220                 return;
2221         }
2222
2223         g_free (source->priv->display_name);
2224         source->priv->display_name = g_strdup (display_name);
2225
2226         /* Strip leading and trailing whitespace. */
2227         g_strstrip (source->priv->display_name);
2228
2229         /* This is used in e_source_compare_by_display_name(). */
2230         g_free (source->priv->collate_key);
2231         source->priv->collate_key = g_utf8_collate_key (display_name, -1);
2232
2233         g_mutex_unlock (source->priv->property_lock);
2234
2235         g_object_notify (G_OBJECT (source), "display-name");
2236 }
2237
2238 /**
2239  * e_source_compare_by_display_name:
2240  * @source1: the first #ESource
2241  * @source2: the second #ESource
2242  *
2243  * Compares two #ESource instances by their display names.  Useful for
2244  * ordering sources in a user interface.
2245  *
2246  * Returns: a negative value if @source1 compares before @source2, zero if
2247  *          they compare equal, or a positive value if @source1 compares
2248  *          after @source2
2249  *
2250  * Since: 3.6
2251  **/
2252 gint
2253 e_source_compare_by_display_name (ESource *source1,
2254                                   ESource *source2)
2255 {
2256         return g_strcmp0 (
2257                 source1->priv->collate_key,
2258                 source2->priv->collate_key);
2259 }
2260
2261 /**
2262  * e_source_to_string:
2263  * @source: an #ESource
2264  * @length: (allow-none): return location for the length of the returned
2265  *          string, or %NULL
2266  *
2267  * Outputs the current contents of @source as a key file string.
2268  * Free the returned string with g_free().
2269  *
2270  * Returns: a newly-allocated string
2271  *
2272  * Since: 3.6
2273  **/
2274 gchar *
2275 e_source_to_string (ESource *source,
2276                     gsize *length)
2277 {
2278         GHashTableIter iter;
2279         GKeyFile *key_file;
2280         gpointer group_name;
2281         gpointer extension;
2282         gchar *data;
2283
2284         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2285
2286         g_static_rec_mutex_lock (&source->priv->lock);
2287
2288         key_file = source->priv->key_file;
2289
2290         source_save_to_key_file (
2291                 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
2292
2293         g_hash_table_iter_init (&iter, source->priv->extensions);
2294         while (g_hash_table_iter_next (&iter, &group_name, &extension))
2295                 source_save_to_key_file (extension, key_file, group_name);
2296
2297         data = g_key_file_to_data (key_file, length, NULL);
2298
2299         g_static_rec_mutex_unlock (&source->priv->lock);
2300
2301         return data;
2302 }
2303
2304 /**
2305  * e_source_parameter_to_key:
2306  * @param_name: a #GParamSpec name
2307  *
2308  * Converts a #GParamSpec name (e.g. "foo-bar" or "foo_bar")
2309  * to "CamelCase" for use as a #GKeyFile key (e.g. "FooBar").
2310  *
2311  * This function is made public only to aid in account migration.
2312  * Applications should not need to use this.
2313  *
2314  * Since: 3.6
2315  **/
2316 gchar *
2317 e_source_parameter_to_key (const gchar *param_name)
2318 {
2319         gboolean uppercase = TRUE;
2320         gchar *key, *cp;
2321         gint ii;
2322
2323         g_return_val_if_fail (param_name != NULL, NULL);
2324
2325         key = cp = g_malloc0 (strlen (param_name) + 1);
2326
2327         for (ii = 0; param_name[ii] != '\0'; ii++) {
2328                 if (g_ascii_isalnum (param_name[ii]) && uppercase) {
2329                         *cp++ = g_ascii_toupper (param_name[ii]);
2330                         uppercase = FALSE;
2331                 } else if (param_name[ii] == '-' || param_name[ii] == '_')
2332                         uppercase = TRUE;
2333                 else
2334                         *cp++ = param_name[ii];
2335         }
2336
2337         return key;
2338 }
2339
2340 /**
2341  * e_source_remove_sync:
2342  * @source: the #ESource to be removed
2343  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2344  * @error: return location for a #GError, or %NULL
2345  *
2346  * Requests the D-Bus service to delete the key files for @source and all of
2347  * its descendants and broadcast their removal to all clients.  The @source
2348  * must be #ESource:removable.
2349  *
2350  * If an error occurs, the functon will set @error and return %FALSE.
2351  *
2352  * Returns: %TRUE on success, %FALSE on failure
2353  *
2354  * Since: 3.6
2355  **/
2356 gboolean
2357 e_source_remove_sync (ESource *source,
2358                       GCancellable *cancellable,
2359                       GError **error)
2360 {
2361         ESourceClass *class;
2362
2363         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2364
2365         class = E_SOURCE_GET_CLASS (source);
2366         g_return_val_if_fail (class->remove_sync != NULL, FALSE);
2367
2368         return class->remove_sync (source, cancellable, error);
2369 }
2370
2371 /**
2372  * e_source_remove:
2373  * @source: the #ESource to be removed
2374  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2375  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2376  *            is satisfied
2377  * @user_data: (closure): data to pass to the callback function
2378  *
2379  * Asynchronously requests the D-Bus service to delete the key files for
2380  * @source and all of its descendants and broadcast their removal to all
2381  * clients.  The @source must be #ESource:removable.
2382  *
2383  * When the operation is finished, @callback will be called.  You can then
2384  * call e_source_remove_finish() to get the result of the operation.
2385  *
2386  * Since: 3.6
2387  **/
2388 void
2389 e_source_remove (ESource *source,
2390                  GCancellable *cancellable,
2391                  GAsyncReadyCallback callback,
2392                  gpointer user_data)
2393 {
2394         ESourceClass *class;
2395
2396         g_return_if_fail (E_IS_SOURCE (source));
2397
2398         class = E_SOURCE_GET_CLASS (source);
2399         g_return_if_fail (class->remove != NULL);
2400
2401         class->remove (source, cancellable, callback, user_data);
2402 }
2403
2404 /**
2405  * e_source_remove_finish:
2406  * @source: the #ESource to be removed
2407  * @result: a #GAsyncResult
2408  * @error: return location for a #GError, or %NULL
2409  *
2410  * Finishes the operation started with e_source_remove().  If an
2411  * error occurred, the function will set @error and return %FALSE.
2412  *
2413  * Returns: %TRUE on success, %FALSE of failure
2414  *
2415  * Since: 3.6
2416  **/
2417 gboolean
2418 e_source_remove_finish (ESource *source,
2419                         GAsyncResult *result,
2420                         GError **error)
2421 {
2422         ESourceClass *class;
2423
2424         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2425         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2426
2427         class = E_SOURCE_GET_CLASS (source);
2428         g_return_val_if_fail (class->remove_finish != NULL, FALSE);
2429
2430         return class->remove_finish (source, result, error);
2431 }
2432
2433 /**
2434  * e_source_write_sync:
2435  * @source: a writable #ESource
2436  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2437  * @error: return location for a #GError, or %NULL
2438  *
2439  * Submits the current contents of @source to the D-Bus service to be
2440  * written to disk and broadcast to other clients.  The @source must
2441  * be #ESource:writable.
2442  *
2443  * If an error occurs, the functon will set @error and return %FALSE.
2444  *
2445  * Returns: %TRUE on success, %FALSE on failure
2446  *
2447  * Since: 3.6
2448  **/
2449 gboolean
2450 e_source_write_sync (ESource *source,
2451                      GCancellable *cancellable,
2452                      GError **error)
2453 {
2454         ESourceClass *class;
2455
2456         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2457
2458         class = E_SOURCE_GET_CLASS (source);
2459         g_return_val_if_fail (class->write_sync != NULL, FALSE);
2460
2461         return class->write_sync (source, cancellable, error);
2462 }
2463
2464 /**
2465  * e_source_write:
2466  * @source: a writable #ESource
2467  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2468  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2469  *            is satisfied
2470  * @user_data: (closure): data to pass to the callback function
2471  *
2472  * Asynchronously submits the current contents of @source to the D-Bus
2473  * service to be written to disk and broadcast to other clients.  The
2474  * @source must be #ESource:writable.
2475  *
2476  * When the operation is finished, @callback will be called.  You can then
2477  * call e_source_write_finish() to get the result of the operation.
2478  *
2479  * Since: 3.6
2480  **/
2481 void
2482 e_source_write (ESource *source,
2483                 GCancellable *cancellable,
2484                 GAsyncReadyCallback callback,
2485                 gpointer user_data)
2486 {
2487         ESourceClass *class;
2488
2489         g_return_if_fail (E_IS_SOURCE (source));
2490
2491         class = E_SOURCE_GET_CLASS (source);
2492         g_return_if_fail (class->write != NULL);
2493
2494         class->write (source, cancellable, callback, user_data);
2495 }
2496
2497 /**
2498  * e_source_write_finish:
2499  * @source: a writable #ESource
2500  * @result: a #GAsyncResult
2501  * @error: return location for a #GError, or %NULL
2502  *
2503  * Finishes the operation started with e_source_write().  If an
2504  * error occurred, the function will set @error and return %FALSE.
2505  *
2506  * Returns: %TRUE on success, %FALSE on failure
2507  *
2508  * Since: 3.6
2509  **/
2510 gboolean
2511 e_source_write_finish (ESource *source,
2512                        GAsyncResult *result,
2513                        GError **error)
2514 {
2515         ESourceClass *class;
2516
2517         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2518         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2519
2520         class = E_SOURCE_GET_CLASS (source);
2521         g_return_val_if_fail (class->write_finish != NULL, FALSE);
2522
2523         return class->write_finish (source, result, error);
2524 }
2525
2526 /**
2527  * e_source_remote_create_sync:
2528  * @source: an #ESource
2529  * @scratch_source: an #ESource describing the resource to create
2530  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2531  * @error: return location for a #GError, or %NULL
2532  *
2533  * Creates a new remote resource by picking out relevant details from
2534  * @scratch_source.  The @scratch_source must be an #ESource with no
2535  * #GDBusObject.  The @source must be #ESource:remote-creatable.
2536  *
2537  * The details required to create the resource vary by #ECollectionBackend,
2538  * but in most cases the @scratch_source need only define the resource type
2539  * (address book, calendar, etc.), a display name for the resource, and
2540  * possibly a server-side path or ID for the resource.
2541  *
2542  * If an error occurs, the function will set @error and return %FALSE.
2543  *
2544  * Returns: %TRUE on success, %FALSE on failure
2545  *
2546  * Since: 3.6
2547  **/
2548 gboolean
2549 e_source_remote_create_sync (ESource *source,
2550                              ESource *scratch_source,
2551                              GCancellable *cancellable,
2552                              GError **error)
2553 {
2554         ESourceClass *class;
2555
2556         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2557         g_return_val_if_fail (E_IS_SOURCE (scratch_source), FALSE);
2558
2559         class = E_SOURCE_GET_CLASS (source);
2560         g_return_val_if_fail (class->remote_create_sync != NULL, FALSE);
2561
2562         return class->remote_create_sync (
2563                 source, scratch_source, cancellable, error);
2564 }
2565
2566 /**
2567  * e_source_remote_create:
2568  * @source: an #ESource
2569  * @scratch_source: an #ESource describing the resource to create
2570  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2571  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2572  *            is satisfied
2573  * @user_data: (closure): data to pass to the callback function
2574  *
2575  * Asynchronously creates a new remote resource by picking out relevant
2576  * details from @scratch_source.  The @scratch_source must be an #ESource
2577  * with no #GDBusObject.  The @source must be #ESource:remote-creatable.
2578  *
2579  * The details required to create the resource vary by #ECollectionBackend,
2580  * but in most cases the @scratch_source need only define the resource type
2581  * (address book, calendar, etc.), a display name for the resource, and
2582  * possibly a server-side path or ID for the resource.
2583  *
2584  * When the operation is finished, @callback will be called.  You can then
2585  * call 3_source_remote_create_finish() to get the result of the operation.
2586  *
2587  * Since: 3.6
2588  **/
2589 void
2590 e_source_remote_create (ESource *source,
2591                         ESource *scratch_source,
2592                         GCancellable *cancellable,
2593                         GAsyncReadyCallback callback,
2594                         gpointer user_data)
2595 {
2596         ESourceClass *class;
2597
2598         g_return_if_fail (E_IS_SOURCE (source));
2599         g_return_if_fail (E_IS_SOURCE (scratch_source));
2600
2601         class = E_SOURCE_GET_CLASS (source);
2602         g_return_if_fail (class->remote_create != NULL);
2603
2604         class->remote_create (
2605                 source, scratch_source,
2606                 cancellable, callback, user_data);
2607 }
2608
2609 /**
2610  * e_source_remote_create_finish:
2611  * @source: an #ESource
2612  * @result: a #GAsyncResult
2613  * @error: return location for a #GError, or %NULL
2614  *
2615  * Finishes the operation started with e_source_remote_create().  If
2616  * an error occurred, the function will set @error and return %FALSE.
2617  *
2618  * Returns: %TRUE on success, %FALSE on failure
2619  *
2620  * Since: 3.6
2621  **/
2622 gboolean
2623 e_source_remote_create_finish (ESource *source,
2624                                GAsyncResult *result,
2625                                GError **error)
2626 {
2627         ESourceClass *class;
2628
2629         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2630
2631         class = E_SOURCE_GET_CLASS (source);
2632         g_return_val_if_fail (class->remote_create_finish != NULL, FALSE);
2633
2634         return class->remote_create_finish (source, result, error);
2635 }
2636
2637 /**
2638  * e_source_remote_delete_sync:
2639  * @source: an #ESource
2640  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2641  * @error: return location for a #GError, or %NULL
2642  *
2643  * Deletes the resource represented by @source from a remote server.
2644  * The @source must be #ESource:remote-deletable.  This will also delete
2645  * the key file for @source and broadcast its removal to all clients,
2646  * similar to e_source_remove_sync().
2647  *
2648  * If an error occurs, the function will set @error and return %FALSE.
2649  *
2650  * Returns: %TRUE on success, %FALSE on failure
2651  *
2652  * Since: 3.6
2653  **/
2654 gboolean
2655 e_source_remote_delete_sync (ESource *source,
2656                              GCancellable *cancellable,
2657                              GError **error)
2658 {
2659         ESourceClass *class;
2660
2661         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2662
2663         class = E_SOURCE_GET_CLASS (source);
2664         g_return_val_if_fail (class->remote_delete_sync != NULL, FALSE);
2665
2666         return class->remote_delete_sync (source, cancellable, error);
2667 }
2668
2669 /**
2670  * e_source_remote_delete:
2671  * @source: an #ESource
2672  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2673  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2674  *            is satisfied
2675  * @user_data: (closure): data to pass to the callback function
2676  *
2677  * Asynchronously deletes the resource represented by @source from a remote
2678  * server.  The @source must be #ESource:remote-deletable.  This will also
2679  * delete the key file for @source and broadcast its removal to all clients,
2680  * similar to e_source_remove().
2681  *
2682  * When the operation is finished, @callback will be called.  You can then
2683  * call e_source_remote_delete_finish() to get the result of the operation.
2684  *
2685  * Since: 3.6
2686  **/
2687 void
2688 e_source_remote_delete (ESource *source,
2689                         GCancellable *cancellable,
2690                         GAsyncReadyCallback callback,
2691                         gpointer user_data)
2692 {
2693         ESourceClass *class;
2694
2695         g_return_if_fail (E_IS_SOURCE (source));
2696
2697         class = E_SOURCE_GET_CLASS (source);
2698         g_return_if_fail (class->remote_delete != NULL);
2699
2700         class->remote_delete (source, cancellable, callback, user_data);
2701 }
2702
2703 /**
2704  * e_source_remote_delete_finish:
2705  * @source: an #ESource
2706  * @result: a #GAsyncResult
2707  * @error: return location for a #GError, or %NULL
2708  *
2709  * Finishes the operation started with e_source_remote_delete().  If
2710  * an error occurred, the function will set @error and return %FALSE.
2711  *
2712  * Returns: %TRUE on success, %FALSE on failure
2713  *
2714  * Since: 3.6
2715  **/
2716 gboolean
2717 e_source_remote_delete_finish (ESource *source,
2718                                GAsyncResult *result,
2719                                GError **error)
2720 {
2721         ESourceClass *class;
2722
2723         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2724
2725         class = E_SOURCE_GET_CLASS (source);
2726         g_return_val_if_fail (class->remote_delete_finish != NULL, FALSE);
2727
2728         return class->remote_delete_finish (source, result, error);
2729 }
2730