Revert "Bug #678901 - Fake ESource::changed notifications"
[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 struct _ESourcePrivate {
113         GDBusObject *dbus_object;
114         GMainContext *main_context;
115
116         GSource *changed;
117         GMutex *changed_lock;
118
119         GMutex *property_lock;
120
121         gchar *display_name;
122         gchar *collate_key;
123         gchar *parent;
124         gchar *uid;
125
126         /* The lock guards the key file and hash table. */
127
128         GKeyFile *key_file;
129         GStaticRecMutex lock;
130         GHashTable *extensions;
131
132         gboolean enabled;
133 };
134
135 enum {
136         PROP_0,
137         PROP_DBUS_OBJECT,
138         PROP_DISPLAY_NAME,
139         PROP_ENABLED,
140         PROP_MAIN_CONTEXT,
141         PROP_PARENT,
142         PROP_REMOVABLE,
143         PROP_UID,
144         PROP_WRITABLE
145 };
146
147 enum {
148         CHANGED,
149         LAST_SIGNAL
150 };
151
152 static guint signals[LAST_SIGNAL];
153
154 /* Forward Declarations */
155 static void     e_source_initable_init          (GInitableIface *interface);
156
157 G_DEFINE_TYPE_WITH_CODE (
158         ESource,
159         e_source,
160         G_TYPE_OBJECT,
161         G_IMPLEMENT_INTERFACE (
162                 G_TYPE_INITABLE,
163                 e_source_initable_init))
164
165 static void
166 source_find_extension_classes_rec (GType parent_type,
167                                    GHashTable *hash_table)
168 {
169         GType *children;
170         guint n_children, ii;
171
172         children = g_type_children (parent_type, &n_children);
173
174         for (ii = 0; ii < n_children; ii++) {
175                 GType type = children[ii];
176                 ESourceExtensionClass *class;
177                 gpointer key;
178
179                 /* Recurse over the child's children. */
180                 source_find_extension_classes_rec (type, hash_table);
181
182                 /* Skip abstract types. */
183                 if (G_TYPE_IS_ABSTRACT (type))
184                         continue;
185
186                 class = g_type_class_ref (type);
187                 key = (gpointer) class->name;
188
189                 if (key != NULL)
190                         g_hash_table_insert (hash_table, key, class);
191                 else
192                         g_type_class_unref (class);
193         }
194
195         g_free (children);
196 }
197
198 static GHashTable *
199 source_find_extension_classes (void)
200 {
201         GHashTable *hash_table;
202
203         hash_table = g_hash_table_new_full (
204                 (GHashFunc) g_str_hash,
205                 (GEqualFunc) g_str_equal,
206                 (GDestroyNotify) NULL,
207                 (GDestroyNotify) g_type_class_unref);
208
209         source_find_extension_classes_rec (
210                 E_TYPE_SOURCE_EXTENSION, hash_table);
211
212         return hash_table;
213 }
214
215 static void
216 source_localized_hack (GKeyFile *key_file,
217                        const gchar *group_name,
218                        const gchar *key,
219                        const gchar *new_value)
220 {
221         const gchar * const *language_names;
222         gint ii;
223
224         /* XXX If we're changing a string key that has translations,
225          *     set "key[$CURRENT_LOCALE]" (if available) to the new
226          *     value so g_key_file_get_locale_string() will pick it
227          *     up.  This is not a perfect solution however.  When a
228          *     different locale is used the value may revert to its
229          *     original localized string.  Good enough for now. */
230
231         language_names = g_get_language_names ();
232
233         for (ii = 0; language_names[ii] != NULL; ii++) {
234                 gboolean has_localized_key;
235                 gchar *localized_key;
236
237                 localized_key = g_strdup_printf (
238                         "%s[%s]", key, language_names[ii]);
239                 has_localized_key = g_key_file_has_key (
240                         key_file, group_name, localized_key, NULL);
241
242                 if (has_localized_key)
243                         g_key_file_set_string (
244                                 key_file, group_name,
245                                 localized_key, new_value);
246
247                 g_free (localized_key);
248
249                 if (has_localized_key)
250                         return;
251         }
252
253         g_key_file_set_string (key_file, group_name, key, new_value);
254 }
255
256 static void
257 source_set_key_file_from_property (GObject *object,
258                                    GParamSpec *pspec,
259                                    GKeyFile *key_file,
260                                    const gchar *group_name)
261 {
262         GValue *pvalue;
263         GValue *svalue;
264         gchar *key;
265
266         pvalue = g_slice_new0 (GValue);
267         g_value_init (pvalue, pspec->value_type);
268         g_object_get_property (object, pspec->name, pvalue);
269
270         svalue = g_slice_new0 (GValue);
271         g_value_init (svalue, G_TYPE_STRING);
272
273         key = e_source_parameter_to_key (pspec->name);
274
275         /* For the most part we can just transform any supported
276          * property type to a string, with a couple exceptions. */
277
278         /* Transforming a boolean GValue to a string results in
279          * "TRUE" or "FALSE" (all uppercase), but GKeyFile only
280          * recognizes "true" or "false" (all lowercase).  So we
281          * have to use g_key_file_set_boolean(). */
282         if (G_VALUE_HOLDS_BOOLEAN (pvalue)) {
283                 gboolean v_boolean = g_value_get_boolean (pvalue);
284                 g_key_file_set_boolean (key_file, group_name, key, v_boolean);
285
286         /* Store UIN64 in hexa */
287         } else if (G_VALUE_HOLDS_UINT64 (pvalue)) {
288                 gchar *v_str;
289
290                 v_str = g_strdup_printf (
291                         "%016" G_GINT64_MODIFIER "X",
292                         g_value_get_uint64 (pvalue));
293                 g_key_file_set_string (key_file, group_name, key, v_str);
294                 g_free (v_str);
295
296         /* String GValues may contain characters that need escaping. */
297         } else if (G_VALUE_HOLDS_STRING (pvalue)) {
298                 const gchar *v_string = g_value_get_string (pvalue);
299
300                 if (v_string == NULL)
301                         v_string = "";
302
303                 /* Special case for localized "DisplayName" keys. */
304                 source_localized_hack (key_file, group_name, key, v_string);
305
306         /* Transforming an enum GValue to a string results in
307          * the GEnumValue name.  We want the shorter nickname. */
308         } else if (G_VALUE_HOLDS_ENUM (pvalue)) {
309                 GParamSpecEnum *enum_pspec;
310                 GEnumClass *enum_class;
311                 GEnumValue *enum_value;
312                 gint value;
313
314                 enum_pspec = G_PARAM_SPEC_ENUM (pspec);
315                 enum_class = enum_pspec->enum_class;
316
317                 value = g_value_get_enum (pvalue);
318                 enum_value = g_enum_get_value (enum_class, value);
319
320                 if (enum_value == NULL) {
321                         value = enum_pspec->default_value;
322                         enum_value = g_enum_get_value (enum_class, value);
323                 }
324
325                 if (enum_value != NULL)
326                         g_key_file_set_string (
327                                 key_file, group_name, key,
328                                 enum_value->value_nick);
329
330         } else if (G_VALUE_HOLDS (pvalue, G_TYPE_STRV)) {
331                 const gchar **strv = g_value_get_boxed (pvalue);
332                 guint length = 0;
333
334                 if (strv != NULL)
335                         length = g_strv_length ((gchar **) strv);
336                 g_key_file_set_string_list (
337                         key_file, group_name, key, strv, length);
338
339         /* For GValues holding a GFile object we save the URI. */
340         } else if (G_VALUE_HOLDS (pvalue, G_TYPE_FILE)) {
341                 GFile *file = g_value_get_object (pvalue);
342                 gchar *uri = NULL;
343
344                 if (file != NULL)
345                         uri = g_file_get_uri (file);
346                 g_key_file_set_string (
347                         key_file, group_name, key,
348                         (uri != NULL) ? uri : "");
349                 g_free (uri);
350
351         } else if (g_value_transform (pvalue, svalue)) {
352                 const gchar *value = g_value_get_string (svalue);
353                 g_key_file_set_value (key_file, group_name, key, value);
354         }
355
356         g_free (key);
357         g_value_unset (pvalue);
358         g_value_unset (svalue);
359         g_slice_free (GValue, pvalue);
360         g_slice_free (GValue, svalue);
361 }
362
363 static void
364 source_set_property_from_key_file (GObject *object,
365                                    GParamSpec *pspec,
366                                    GKeyFile *key_file,
367                                    const gchar *group_name)
368 {
369         gchar *key;
370         GValue *value;
371         GError *error = NULL;
372
373         value = g_slice_new0 (GValue);
374         key = e_source_parameter_to_key (pspec->name);
375
376         if (G_IS_PARAM_SPEC_CHAR (pspec) ||
377             G_IS_PARAM_SPEC_UCHAR (pspec) ||
378             G_IS_PARAM_SPEC_INT (pspec) ||
379             G_IS_PARAM_SPEC_UINT (pspec) ||
380             G_IS_PARAM_SPEC_LONG (pspec) ||
381             G_IS_PARAM_SPEC_ULONG (pspec)) {
382                 gint v_int;
383
384                 v_int = g_key_file_get_integer (
385                         key_file, group_name, key, &error);
386                 if (error == NULL) {
387                         g_value_init (value, G_TYPE_INT);
388                         g_value_set_int (value, v_int);
389                 }
390
391         } else if (G_IS_PARAM_SPEC_INT64 (pspec)) {
392                 gint64 v_int64;
393
394                 v_int64 = g_key_file_get_int64 (
395                         key_file, group_name, key, &error);
396                 if (error == NULL) {
397                         g_value_init (value, G_TYPE_INT64);
398                         g_value_set_int64 (value, v_int64);
399                 }
400
401         } else if (G_IS_PARAM_SPEC_UINT64 (pspec)) {
402                 guint64 v_uint64;
403                 gchar *v_str;
404
405                 v_str = g_key_file_get_string (
406                         key_file, group_name, key, &error);
407                 if (error == NULL) {
408                         v_uint64 = g_ascii_strtoull (v_str, NULL, 16);
409
410                         g_value_init (value, G_TYPE_UINT64);
411                         g_value_set_uint64 (value, v_uint64);
412                 }
413
414                 g_free (v_str);
415
416         } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
417                 gboolean v_boolean;
418
419                 v_boolean = g_key_file_get_boolean (
420                         key_file, group_name, key, &error);
421                 if (error == NULL) {
422                         g_value_init (value, G_TYPE_BOOLEAN);
423                         g_value_set_boolean (value, v_boolean);
424                 }
425
426         } else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
427                 gchar *nick;
428
429                 nick = g_key_file_get_string (
430                         key_file, group_name, key, &error);
431                 if (error == NULL) {
432                         GParamSpecEnum *enum_pspec;
433                         GEnumValue *enum_value;
434
435                         enum_pspec = G_PARAM_SPEC_ENUM (pspec);
436                         enum_value = g_enum_get_value_by_nick (
437                                 enum_pspec->enum_class, nick);
438                         if (enum_value != NULL) {
439                                 g_value_init (value, pspec->value_type);
440                                 g_value_set_enum (value, enum_value->value);
441                         }
442                         g_free (nick);
443                 }
444
445         } else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
446                    G_IS_PARAM_SPEC_DOUBLE (pspec)) {
447                 gdouble v_double;
448
449                 v_double = g_key_file_get_double (
450                         key_file, group_name, key, &error);
451                 if (error == NULL) {
452                         g_value_init (value, G_TYPE_DOUBLE);
453                         g_value_set_double (value, v_double);
454                 }
455
456         } else if (G_IS_PARAM_SPEC_STRING (pspec)) {
457                 gchar *v_string;
458
459                 /* Get the localized string if present. */
460                 v_string = g_key_file_get_locale_string (
461                         key_file, group_name, key, NULL, &error);
462                 if (error == NULL) {
463                         g_value_init (value, G_TYPE_STRING);
464                         g_value_take_string (value, v_string);
465                 }
466
467         } else if (g_type_is_a (pspec->value_type, G_TYPE_STRV)) {
468                 gchar **strv;
469
470                 strv = g_key_file_get_string_list (
471                         key_file, group_name, key, NULL, &error);
472                 if (error == NULL) {
473                         g_value_init (value, G_TYPE_STRV);
474                         g_value_take_boxed (value, strv);
475                 }
476
477         } else if (g_type_is_a (pspec->value_type, G_TYPE_FILE)) {
478                 gchar *uri;
479
480                 /* Create the GFile from the URI string. */
481                 uri = g_key_file_get_locale_string (
482                         key_file, group_name, key, NULL, &error);
483                 if (error == NULL) {
484                         GFile *file = NULL;
485                         if (uri != NULL && *uri != '\0')
486                                 file = g_file_new_for_uri (uri);
487                         g_value_init (value, pspec->value_type);
488                         g_value_take_object (value, file);
489                         g_free (uri);
490                 }
491
492         } else {
493                 g_warning (
494                         "No GKeyFile-to-GValue converter defined "
495                         "for type '%s'", G_PARAM_SPEC_TYPE_NAME (pspec));
496         }
497
498         /* If a value could not be retrieved from the key
499          * file, restore the property to its default value. */
500         if (error != NULL) {
501                 g_value_init (value, pspec->value_type);
502                 g_param_value_set_default (pspec, value);
503                 g_error_free (error);
504         }
505
506         if (G_IS_VALUE (value)) {
507                 g_object_set_property (object, pspec->name, value);
508                 g_value_unset (value);
509         }
510
511         g_slice_free (GValue, value);
512         g_free (key);
513 }
514
515 static void
516 source_load_from_key_file (GObject *object,
517                            GKeyFile *key_file,
518                            const gchar *group_name)
519 {
520         GObjectClass *class;
521         GParamSpec **properties;
522         guint n_properties, ii;
523
524         class = G_OBJECT_GET_CLASS (object);
525         properties = g_object_class_list_properties (class, &n_properties);
526
527         g_object_freeze_notify (object);
528
529         for (ii = 0; ii < n_properties; ii++) {
530                 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
531                         source_set_property_from_key_file (
532                                 object, properties[ii], key_file, group_name);
533                 }
534         }
535
536         g_object_thaw_notify (object);
537
538         g_free (properties);
539 }
540
541 static void
542 source_save_to_key_file (GObject *object,
543                          GKeyFile *key_file,
544                          const gchar *group_name)
545 {
546         GObjectClass *class;
547         GParamSpec **properties;
548         guint n_properties, ii;
549
550         class = G_OBJECT_GET_CLASS (object);
551         properties = g_object_class_list_properties (class, &n_properties);
552
553         for (ii = 0; ii < n_properties; ii++) {
554                 if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
555                         source_set_key_file_from_property (
556                                 object, properties[ii], key_file, group_name);
557                 }
558         }
559
560         g_free (properties);
561 }
562
563 static gboolean
564 source_parse_dbus_data (ESource *source,
565                         GError **error)
566 {
567         GHashTableIter iter;
568         EDBusObject *dbus_object;
569         EDBusSource *dbus_source;
570         GKeyFile *key_file;
571         gpointer group_name;
572         gpointer extension;
573         gchar *data;
574         gboolean success;
575
576         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
577
578         dbus_source = e_dbus_object_get_source (dbus_object);
579         data = e_dbus_source_dup_data (dbus_source);
580         g_object_unref (dbus_source);
581
582         g_return_val_if_fail (data != NULL, FALSE);
583
584         key_file = source->priv->key_file;
585
586         success = g_key_file_load_from_data (
587                 key_file, data, strlen (data),
588                 G_KEY_FILE_KEEP_COMMENTS |
589                 G_KEY_FILE_KEEP_TRANSLATIONS,
590                 error);
591
592         g_free (data);
593         data = NULL;
594
595         if (!success)
596                 return FALSE;
597
598         /* Make sure the key file has a [Data Source] group. */
599         if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
600                 g_set_error (
601                         error, G_KEY_FILE_ERROR,
602                         G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
603                         _("Source file is missing a [%s] group"),
604                         PRIMARY_GROUP_NAME);
605                 return FALSE;
606         }
607
608         /* Load key file values from the [Data Source] group and from
609          * any other groups for which an extension object has already
610          * been created.  Note that not all the extension classes may
611          * be registered at this point, so avoid attempting to create
612          * new extension objects here.  Extension objects are created
613          * on-demand in e_source_get_extension(). */
614
615         source_load_from_key_file (
616                 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
617
618         g_hash_table_iter_init (&iter, source->priv->extensions);
619         while (g_hash_table_iter_next (&iter, &group_name, &extension))
620                 source_load_from_key_file (extension, key_file, group_name);
621
622         return TRUE;
623 }
624
625 static void
626 source_notify_dbus_data_cb (EDBusSource *dbus_source,
627                             GParamSpec *pspec,
628                             ESource *source)
629 {
630         GError *error = NULL;
631
632         g_static_rec_mutex_lock (&source->priv->lock);
633
634         /* Since the source data came from a GKeyFile structure on the
635          * server-side, this should never fail.  But we'll print error
636          * messages to the terminal just in case. */
637         if (!source_parse_dbus_data (source, &error)) {
638                 g_return_if_fail (error != NULL);
639                 g_warning ("%s", error->message);
640                 g_error_free (error);
641         }
642
643         g_static_rec_mutex_unlock (&source->priv->lock);
644 }
645
646 static gboolean
647 source_idle_changed_cb (gpointer user_data)
648 {
649         ESource *source = E_SOURCE (user_data);
650
651         g_mutex_lock (source->priv->changed_lock);
652         if (source->priv->changed != NULL) {
653                 g_source_unref (source->priv->changed);
654                 source->priv->changed = NULL;
655         }
656         g_mutex_unlock (source->priv->changed_lock);
657
658         g_signal_emit (source, signals[CHANGED], 0);
659
660         return FALSE;
661 }
662
663 static void
664 source_set_dbus_object (ESource *source,
665                         EDBusObject *dbus_object)
666 {
667         /* D-Bus object will be NULL when configuring a new source. */
668         if (dbus_object == NULL)
669                 return;
670
671         g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
672         g_return_if_fail (source->priv->dbus_object == NULL);
673
674         source->priv->dbus_object = g_object_ref (dbus_object);
675 }
676
677 static void
678 source_set_main_context (ESource *source,
679                          GMainContext *main_context)
680 {
681         g_return_if_fail (source->priv->main_context == NULL);
682
683         source->priv->main_context =
684                 (main_context != NULL) ?
685                 g_main_context_ref (main_context) :
686                 g_main_context_ref_thread_default ();
687 }
688
689 static void
690 source_set_property (GObject *object,
691                      guint property_id,
692                      const GValue *value,
693                      GParamSpec *pspec)
694 {
695         switch (property_id) {
696                 case PROP_DBUS_OBJECT:
697                         source_set_dbus_object (
698                                 E_SOURCE (object),
699                                 g_value_get_object (value));
700                         return;
701
702                 case PROP_DISPLAY_NAME:
703                         e_source_set_display_name (
704                                 E_SOURCE (object),
705                                 g_value_get_string (value));
706                         return;
707
708                 case PROP_ENABLED:
709                         e_source_set_enabled (
710                                 E_SOURCE (object),
711                                 g_value_get_boolean (value));
712                         return;
713
714                 case PROP_MAIN_CONTEXT:
715                         source_set_main_context (
716                                 E_SOURCE (object),
717                                 g_value_get_boxed (value));
718                         return;
719
720                 case PROP_PARENT:
721                         e_source_set_parent (
722                                 E_SOURCE (object),
723                                 g_value_get_string (value));
724                         return;
725         }
726
727         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
728 }
729
730 static void
731 source_get_property (GObject *object,
732                      guint property_id,
733                      GValue *value,
734                      GParamSpec *pspec)
735 {
736         switch (property_id) {
737                 case PROP_DBUS_OBJECT:
738                         g_value_take_object (
739                                 value, e_source_ref_dbus_object (
740                                 E_SOURCE (object)));
741                         return;
742
743                 case PROP_DISPLAY_NAME:
744                         g_value_take_string (
745                                 value, e_source_dup_display_name (
746                                 E_SOURCE (object)));
747                         return;
748
749                 case PROP_ENABLED:
750                         g_value_set_boolean (
751                                 value, e_source_get_enabled (
752                                 E_SOURCE (object)));
753                         return;
754
755                 case PROP_MAIN_CONTEXT:
756                         g_value_take_boxed (
757                                 value, e_source_ref_main_context (
758                                 E_SOURCE (object)));
759                         return;
760
761                 case PROP_PARENT:
762                         g_value_take_string (
763                                 value, e_source_dup_parent (
764                                 E_SOURCE (object)));
765                         return;
766
767                 case PROP_REMOVABLE:
768                         g_value_set_boolean (
769                                 value, e_source_get_removable (
770                                 E_SOURCE (object)));
771                         return;
772
773                 case PROP_UID:
774                         g_value_take_string (
775                                 value, e_source_dup_uid (
776                                 E_SOURCE (object)));
777                         return;
778
779                 case PROP_WRITABLE:
780                         g_value_set_boolean (
781                                 value, e_source_get_writable (
782                                 E_SOURCE (object)));
783                         return;
784         }
785
786         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
787 }
788
789 static void
790 source_dispose (GObject *object)
791 {
792         ESourcePrivate *priv;
793
794         priv = E_SOURCE_GET_PRIVATE (object);
795
796         if (priv->dbus_object != NULL) {
797                 EDBusObject *dbus_object;
798                 EDBusSource *dbus_source;
799
800                 dbus_object = E_DBUS_OBJECT (priv->dbus_object);
801
802                 dbus_source = e_dbus_object_get_source (dbus_object);
803                 if (dbus_source != NULL) {
804                         g_signal_handlers_disconnect_matched (
805                                 dbus_source, G_SIGNAL_MATCH_DATA,
806                                 0, 0, NULL, NULL, object);
807                         g_object_unref (dbus_source);
808                 }
809
810                 g_object_unref (priv->dbus_object);
811                 priv->dbus_object = NULL;
812         }
813
814         if (priv->main_context != NULL) {
815                 g_main_context_unref (priv->main_context);
816                 priv->main_context = NULL;
817         }
818
819         /* XXX Maybe not necessary to acquire the lock? */
820         g_mutex_lock (priv->changed_lock);
821         if (priv->changed != NULL) {
822                 g_source_destroy (priv->changed);
823                 g_source_unref (priv->changed);
824                 priv->changed = NULL;
825         }
826         g_mutex_unlock (priv->changed_lock);
827
828         g_hash_table_remove_all (priv->extensions);
829
830         /* Chain up to parent's dispose() method. */
831         G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
832 }
833
834 static void
835 source_finalize (GObject *object)
836 {
837         ESourcePrivate *priv;
838
839         priv = E_SOURCE_GET_PRIVATE (object);
840
841         g_mutex_free (priv->changed_lock);
842         g_mutex_free (priv->property_lock);
843
844         g_free (priv->display_name);
845         g_free (priv->collate_key);
846         g_free (priv->parent);
847         g_free (priv->uid);
848
849         g_key_file_free (priv->key_file);
850         g_static_rec_mutex_free (&priv->lock);
851         g_hash_table_destroy (priv->extensions);
852
853         /* Chain up to parent's finalize() method. */
854         G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
855 }
856
857 static void
858 source_notify (GObject *object,
859                GParamSpec *pspec)
860 {
861         if ((pspec->flags & E_SOURCE_PARAM_SETTING) != 0)
862                 e_source_changed (E_SOURCE (object));
863 }
864
865 static gboolean
866 source_remove_sync (ESource *source,
867                     GCancellable *cancellable,
868                     GError **error)
869 {
870         EDBusObject *dbus_object;
871         EDBusSourceRemovable *dbus_source;
872         gboolean success;
873
874         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
875
876         dbus_source = e_dbus_object_get_source_removable (dbus_object);
877
878         if (dbus_source == NULL) {
879                 g_set_error (
880                         error, G_IO_ERROR,
881                         G_IO_ERROR_PERMISSION_DENIED,
882                         _("Data source '%s' is not removable"),
883                         e_source_get_display_name (source));
884                 return FALSE;
885         }
886
887         success = e_dbus_source_removable_call_remove_sync (
888                 dbus_source, cancellable, error);
889
890         g_object_unref (dbus_source);
891
892         return success;
893 }
894
895 /* Helper for source_remove() */
896 static void
897 source_remove_thread (GSimpleAsyncResult *simple,
898                       GObject *object,
899                       GCancellable *cancellable)
900 {
901         GError *error = NULL;
902
903         e_source_remove_sync (E_SOURCE (object), cancellable, &error);
904
905         if (error != NULL)
906                 g_simple_async_result_take_error (simple, error);
907 }
908
909 static void
910 source_remove (ESource *source,
911                GCancellable *cancellable,
912                GAsyncReadyCallback callback,
913                gpointer user_data)
914 {
915         GSimpleAsyncResult *simple;
916
917         simple = g_simple_async_result_new (
918                 G_OBJECT (source), callback, user_data, source_remove);
919
920         g_simple_async_result_set_check_cancellable (simple, cancellable);
921
922         g_simple_async_result_run_in_thread (
923                 simple, source_remove_thread,
924                 G_PRIORITY_DEFAULT, cancellable);
925
926         g_object_unref (simple);
927 }
928
929 static gboolean
930 source_remove_finish (ESource *source,
931                       GAsyncResult *result,
932                       GError **error)
933 {
934         GSimpleAsyncResult *simple;
935
936         g_return_val_if_fail (
937                 g_simple_async_result_is_valid (
938                 result, G_OBJECT (source), source_remove), FALSE);
939
940         simple = G_SIMPLE_ASYNC_RESULT (result);
941
942         /* Assume success unless a GError is set. */
943         return !g_simple_async_result_propagate_error (simple, error);
944 }
945
946 static gboolean
947 source_write_sync (ESource *source,
948                    GCancellable *cancellable,
949                    GError **error)
950 {
951         EDBusObject *dbus_object;
952         EDBusSourceWritable *dbus_source;
953         gboolean success;
954         gchar *data;
955
956         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
957
958         dbus_source = e_dbus_object_get_source_writable (dbus_object);
959
960         if (dbus_source == NULL) {
961                 g_set_error (
962                         error, G_IO_ERROR,
963                         G_IO_ERROR_PERMISSION_DENIED,
964                         _("Data source '%s' is not writable"),
965                         e_source_get_display_name (source));
966                 return FALSE;
967         }
968
969         data = e_source_to_string (source, NULL);
970
971         success = e_dbus_source_writable_call_write_sync (
972                 dbus_source, data, cancellable, error);
973
974         g_free (data);
975
976         g_object_unref (dbus_source);
977
978         return success;
979 }
980
981 /* Helper for source_write() */
982 static void
983 source_write_thread (GSimpleAsyncResult *simple,
984                      GObject *object,
985                      GCancellable *cancellable)
986 {
987         GError *error = NULL;
988
989         e_source_write_sync (E_SOURCE (object), cancellable, &error);
990
991         if (error != NULL)
992                 g_simple_async_result_take_error (simple, error);
993 }
994
995 static void
996 source_write (ESource *source,
997               GCancellable *cancellable,
998               GAsyncReadyCallback callback,
999               gpointer user_data)
1000 {
1001         GSimpleAsyncResult *simple;
1002
1003         simple = g_simple_async_result_new (
1004                 G_OBJECT (source), callback, user_data, source_write);
1005
1006         g_simple_async_result_set_check_cancellable (simple, cancellable);
1007
1008         g_simple_async_result_run_in_thread (
1009                 simple, source_write_thread,
1010                 G_PRIORITY_DEFAULT, cancellable);
1011
1012         g_object_unref (simple);
1013 }
1014
1015 static gboolean
1016 source_write_finish (ESource *source,
1017                      GAsyncResult *result,
1018                      GError **error)
1019 {
1020         GSimpleAsyncResult *simple;
1021
1022         g_return_val_if_fail (
1023                 g_simple_async_result_is_valid (
1024                 result, G_OBJECT (source), source_write), FALSE);
1025
1026         simple = G_SIMPLE_ASYNC_RESULT (result);
1027
1028         /* Assume success unless a GError is set. */
1029         return !g_simple_async_result_propagate_error (simple, error);
1030 }
1031
1032 static gboolean
1033 source_initable_init (GInitable *initable,
1034                       GCancellable *cancellable,
1035                       GError **error)
1036 {
1037         ESource *source;
1038         gboolean success = TRUE;
1039
1040         source = E_SOURCE (initable);
1041
1042         /* The D-Bus object has the unique identifier (UID). */
1043         if (source->priv->dbus_object != NULL) {
1044                 EDBusObject *dbus_object;
1045                 EDBusSource *dbus_source;
1046
1047                 dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1048
1049                 /* An EDBusObject lacking an EDBusSource
1050                  * interface indicates a programmer error. */
1051                 dbus_source = e_dbus_object_get_source (dbus_object);
1052                 g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1053
1054                 /* Allow authentication prompts for a data source
1055                  * when a new client-side proxy object is created.
1056                  * The thought being if you cancel an authentication
1057                  * prompt you won't be bothered again until you start
1058                  * (or restart) a new E-D-S client app.
1059                  *
1060                  * Failure here is non-fatal, ignore errors.
1061                  *
1062                  * XXX Only GDBusProxy objects may call this.  Sources
1063                  *     created server-side can't invoke remote methods.
1064                  */
1065                 if (G_IS_DBUS_PROXY (dbus_source))
1066                         e_dbus_source_call_allow_auth_prompt_sync (
1067                                 dbus_source, cancellable, NULL);
1068
1069                 /* The UID never changes, so we can cache a copy. */
1070                 source->priv->uid = e_dbus_source_dup_uid (dbus_source);
1071
1072                 g_signal_connect (
1073                         dbus_source, "notify::data",
1074                         G_CALLBACK (source_notify_dbus_data_cb), source);
1075
1076                 success = source_parse_dbus_data (source, error);
1077
1078                 /* Avoid a spurious "changed" emission. */
1079                 g_mutex_lock (source->priv->changed_lock);
1080                 if (source->priv->changed != NULL) {
1081                         g_source_destroy (source->priv->changed);
1082                         g_source_unref (source->priv->changed);
1083                         source->priv->changed = NULL;
1084                 }
1085                 g_mutex_unlock (source->priv->changed_lock);
1086
1087                 g_object_unref (dbus_source);
1088
1089         /* No D-Bus object implies we're configuring a new source,
1090          * so generate a new unique identifier (UID) for it. */
1091         } else {
1092                 source->priv->uid = e_uid_new ();
1093         }
1094
1095         return success;
1096 }
1097
1098 static void
1099 e_source_class_init (ESourceClass *class)
1100 {
1101         GObjectClass *object_class;
1102
1103         g_type_class_add_private (class, sizeof (ESourcePrivate));
1104
1105         object_class = G_OBJECT_CLASS (class);
1106         object_class->set_property = source_set_property;
1107         object_class->get_property = source_get_property;
1108         object_class->dispose = source_dispose;
1109         object_class->finalize = source_finalize;
1110         object_class->notify = source_notify;
1111
1112         class->remove_sync = source_remove_sync;
1113         class->remove = source_remove;
1114         class->remove_finish = source_remove_finish;
1115         class->write_sync = source_write_sync;
1116         class->write = source_write;
1117         class->write_finish = source_write_finish;
1118
1119         g_object_class_install_property (
1120                 object_class,
1121                 PROP_DBUS_OBJECT,
1122                 g_param_spec_object (
1123                         "dbus-object",
1124                         "D-Bus Object",
1125                         "The D-Bus object for the data source",
1126                         E_DBUS_TYPE_OBJECT,
1127                         G_PARAM_READWRITE |
1128                         G_PARAM_CONSTRUCT_ONLY |
1129                         G_PARAM_STATIC_STRINGS));
1130
1131         g_object_class_install_property (
1132                 object_class,
1133                 PROP_DISPLAY_NAME,
1134                 g_param_spec_string (
1135                         "display-name",
1136                         "Display Name",
1137                         "The human-readable name of the data source",
1138                         _("Unnamed"),
1139                         G_PARAM_READWRITE |
1140                         G_PARAM_CONSTRUCT |
1141                         G_PARAM_STATIC_STRINGS |
1142                         E_SOURCE_PARAM_SETTING));
1143
1144         g_object_class_install_property (
1145                 object_class,
1146                 PROP_ENABLED,
1147                 g_param_spec_boolean (
1148                         "enabled",
1149                         "Enabled",
1150                         "Whether the data source is enabled",
1151                         TRUE,
1152                         G_PARAM_READWRITE |
1153                         G_PARAM_CONSTRUCT |
1154                         G_PARAM_STATIC_STRINGS |
1155                         E_SOURCE_PARAM_SETTING));
1156
1157         g_object_class_install_property (
1158                 object_class,
1159                 PROP_MAIN_CONTEXT,
1160                 g_param_spec_boxed (
1161                         "main-context",
1162                         "Main Context",
1163                         "The GMainContext used for signal emissions",
1164                         G_TYPE_MAIN_CONTEXT,
1165                         G_PARAM_READWRITE |
1166                         G_PARAM_CONSTRUCT_ONLY |
1167                         G_PARAM_STATIC_STRINGS));
1168
1169         g_object_class_install_property (
1170                 object_class,
1171                 PROP_PARENT,
1172                 g_param_spec_string (
1173                         "parent",
1174                         "Parent",
1175                         "The unique identity of the parent data source",
1176                         NULL,
1177                         G_PARAM_READWRITE |
1178                         G_PARAM_STATIC_STRINGS |
1179                         E_SOURCE_PARAM_SETTING));
1180
1181         g_object_class_install_property (
1182                 object_class,
1183                 PROP_REMOVABLE,
1184                 g_param_spec_boolean (
1185                         "removable",
1186                         "Removable",
1187                         "Whether the data source is removable",
1188                         FALSE,
1189                         G_PARAM_READABLE |
1190                         G_PARAM_STATIC_STRINGS));
1191
1192         g_object_class_install_property (
1193                 object_class,
1194                 PROP_UID,
1195                 g_param_spec_string (
1196                         "uid",
1197                         "UID",
1198                         "The unique identity of the data source",
1199                         NULL,
1200                         G_PARAM_READABLE |
1201                         G_PARAM_STATIC_STRINGS));
1202
1203         g_object_class_install_property (
1204                 object_class,
1205                 PROP_WRITABLE,
1206                 g_param_spec_boolean (
1207                         "writable",
1208                         "Writable",
1209                         "Whether the data source is writable",
1210                         FALSE,
1211                         G_PARAM_READABLE |
1212                         G_PARAM_STATIC_STRINGS));
1213
1214         /**
1215          * ESource::changed:
1216          * @source: the #ESource that received the signal
1217          *
1218          * The ::changed signal is emitted when a property in @source or
1219          * one of its extension objects changes.  A common use for this
1220          * signal is to notify a #GtkTreeModel containing data collected
1221          * from #ESource<!-- -->s that it needs to update a row.
1222          **/
1223         signals[CHANGED] = g_signal_new (
1224                 "changed",
1225                 G_TYPE_FROM_CLASS (class),
1226                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
1227                 G_STRUCT_OFFSET (ESourceClass, changed),
1228                 NULL, NULL,
1229                 g_cclosure_marshal_VOID__VOID,
1230                 G_TYPE_NONE, 0);
1231
1232         /* Register built-in ESourceExtension types. */
1233         REGISTER_TYPE (E_TYPE_SOURCE_ADDRESS_BOOK);
1234         REGISTER_TYPE (E_TYPE_SOURCE_ALARMS);
1235         REGISTER_TYPE (E_TYPE_SOURCE_AUTHENTICATION);
1236         REGISTER_TYPE (E_TYPE_SOURCE_AUTOCOMPLETE);
1237         REGISTER_TYPE (E_TYPE_SOURCE_CALENDAR);
1238         REGISTER_TYPE (E_TYPE_SOURCE_COLLECTION);
1239         REGISTER_TYPE (E_TYPE_SOURCE_GOA);
1240         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_ACCOUNT);
1241         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_COMPOSITION);
1242         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_IDENTITY);
1243         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_SIGNATURE);
1244         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_SUBMISSION);
1245         REGISTER_TYPE (E_TYPE_SOURCE_MAIL_TRANSPORT);
1246         REGISTER_TYPE (E_TYPE_SOURCE_MDN);
1247         REGISTER_TYPE (E_TYPE_SOURCE_MEMO_LIST);
1248         REGISTER_TYPE (E_TYPE_SOURCE_OFFLINE);
1249         REGISTER_TYPE (E_TYPE_SOURCE_OPENPGP);
1250         REGISTER_TYPE (E_TYPE_SOURCE_REFRESH);
1251         REGISTER_TYPE (E_TYPE_SOURCE_RESOURCE);
1252         REGISTER_TYPE (E_TYPE_SOURCE_SECURITY);
1253         REGISTER_TYPE (E_TYPE_SOURCE_SELECTABLE);
1254         REGISTER_TYPE (E_TYPE_SOURCE_SMIME);
1255         REGISTER_TYPE (E_TYPE_SOURCE_TASK_LIST);
1256         REGISTER_TYPE (E_TYPE_SOURCE_WEBDAV);
1257 }
1258
1259 static void
1260 e_source_initable_init (GInitableIface *interface)
1261 {
1262         interface->init = source_initable_init;
1263 }
1264
1265 static void
1266 e_source_init (ESource *source)
1267 {
1268         GHashTable *extensions;
1269
1270         /* Don't do this as part of class initialization because it
1271          * loads Camel modules and can screw up introspection, which
1272          * occurs at compile-time before Camel modules are installed. */
1273         e_source_camel_register_types ();
1274
1275         extensions = g_hash_table_new_full (
1276                 (GHashFunc) g_str_hash,
1277                 (GEqualFunc) g_str_equal,
1278                 (GDestroyNotify) g_free,
1279                 (GDestroyNotify) g_object_unref);
1280
1281         source->priv = E_SOURCE_GET_PRIVATE (source);
1282         source->priv->changed_lock = g_mutex_new ();
1283         source->priv->property_lock = g_mutex_new ();
1284         source->priv->key_file = g_key_file_new ();
1285         source->priv->extensions = extensions;
1286
1287         g_static_rec_mutex_init (&source->priv->lock);
1288 }
1289
1290 /**
1291  * e_source_new:
1292  * @dbus_object: (allow-none): a #GDBusObject or %NULL
1293  * @main_context: (allow-none): a #GMainContext or %NULL
1294  * @error: return location for a #GError, or %NULL
1295  *
1296  * Creates a new #ESource instance.
1297  *
1298  * The #ESource::changed signal will be emitted from @main_context if given,
1299  * or else from the thread-default #GMainContext at the time this function is
1300  * called.
1301  *
1302  * The only time the function should be called outside of #ESourceRegistry
1303  * is to create a so-called "scratch" #ESource for editing in a Properties
1304  * window or an account setup assistant.
1305  *
1306  * FIXME: Elaborate on scratch sources.
1307  *
1308  * Returns: a new #ESource, or %NULL on error
1309  *
1310  * Since: 3.6
1311  **/
1312 ESource *
1313 e_source_new (GDBusObject *dbus_object,
1314               GMainContext *main_context,
1315               GError **error)
1316 {
1317         if (dbus_object != NULL)
1318                 g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), NULL);
1319
1320         return g_initable_new (
1321                 E_TYPE_SOURCE, NULL, error,
1322                 "dbus-object", dbus_object,
1323                 "main-context", main_context,
1324                 NULL);
1325 }
1326
1327 /**
1328  * e_source_hash:
1329  * @source: an #ESource
1330  *
1331  * Generates a hash value for @source.  This function is intended for
1332  * easily hashing an #ESource to add to a #GHashTable or similar data
1333  * structure.
1334  *
1335  * Returns: a hash value for @source.
1336  *
1337  * Since: 3.6
1338  **/
1339 guint
1340 e_source_hash (ESource *source)
1341 {
1342         const gchar *uid;
1343
1344         g_return_val_if_fail (E_IS_SOURCE (source), 0);
1345
1346         uid = e_source_get_uid (source);
1347
1348         return g_str_hash (uid);
1349 }
1350
1351 /**
1352  * e_source_equal:
1353  * @source1: the first #ESource
1354  * @source2: the second #ESource
1355  *
1356  * Checks two #ESource instances for equality.  #ESource instances are
1357  * equal if their unique identifier strings are equal.
1358  *
1359  * Returns: %TRUE if @source1 and @source2 are equal
1360  *
1361  * Since: 3.6
1362  **/
1363 gboolean
1364 e_source_equal (ESource *source1,
1365                 ESource *source2)
1366 {
1367         const gchar *uid1, *uid2;
1368
1369         g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
1370         g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
1371
1372         if (source1 == source2)
1373                 return TRUE;
1374
1375         uid1 = e_source_get_uid (source1);
1376         uid2 = e_source_get_uid (source2);
1377
1378         return g_str_equal (uid1, uid2);
1379 }
1380
1381 /**
1382  * e_source_changed:
1383  * @source: an #ESource
1384  *
1385  * Emits the #ESource::changed signal from an idle callback in
1386  * @source's #ESource:main-context.
1387  *
1388  * This function is primarily intended for use by #ESourceExtension
1389  * when emitting a #GObject::notify signal on one of its properties.
1390  *
1391  * Since: 3.6
1392  **/
1393 void
1394 e_source_changed (ESource *source)
1395 {
1396         g_return_if_fail (E_IS_SOURCE (source));
1397
1398         g_mutex_lock (source->priv->changed_lock);
1399         if (source->priv->changed == NULL) {
1400                 source->priv->changed = g_idle_source_new ();
1401                 g_source_set_callback (
1402                         source->priv->changed,
1403                         source_idle_changed_cb,
1404                         source, (GDestroyNotify) NULL);
1405                 g_source_attach (
1406                         source->priv->changed,
1407                         source->priv->main_context);
1408         }
1409         g_mutex_unlock (source->priv->changed_lock);
1410 }
1411
1412 /**
1413  * e_source_get_uid:
1414  * @source: an #ESource
1415  *
1416  * Returns the unique identifier string for @source.
1417  *
1418  * Returns: the UID for @source
1419  *
1420  * Since: 3.6
1421  **/
1422 const gchar *
1423 e_source_get_uid (ESource *source)
1424 {
1425         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1426
1427         return source->priv->uid;
1428 }
1429
1430 /**
1431  * e_source_dup_uid:
1432  * @source: an #ESource
1433  *
1434  * Thread-safe variation of e_source_get_uid().
1435  * Use this function when accessing @source from multiple threads.
1436  *
1437  * The returned string should be freed with g_free() when no longer needed.
1438  *
1439  * Returns: a newly-allocated copy of #ESource:uid
1440  *
1441  * Since: 3.6
1442  **/
1443 gchar *
1444 e_source_dup_uid (ESource *source)
1445 {
1446         const gchar *protected;
1447         gchar *duplicate;
1448
1449         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1450
1451         /* Perhaps we don't need to lock the mutex since
1452          * this is a read-only property but it can't hurt. */
1453
1454         g_mutex_lock (source->priv->property_lock);
1455
1456         protected = e_source_get_uid (source);
1457         duplicate = g_strdup (protected);
1458
1459         g_mutex_unlock (source->priv->property_lock);
1460
1461         return duplicate;
1462 }
1463
1464 /**
1465  * e_source_get_parent:
1466  * @source: an #ESource
1467  *
1468  * Returns the unique identifier string of the parent #ESource.
1469  *
1470  * Returns: the UID of the parent #ESource
1471  *
1472  * Since: 3.6
1473  **/
1474 const gchar *
1475 e_source_get_parent (ESource *source)
1476 {
1477         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1478
1479         return source->priv->parent;
1480 }
1481
1482 /**
1483  * e_source_dup_parent:
1484  * @source: an #ESource
1485  *
1486  * Thread-safe variation of e_source_get_parent().
1487  * Use this function when accessing @source from multiple threads.
1488  *
1489  * The returned string should be freed with g_free() when no longer needed.
1490  *
1491  * Returns: a newly-allocated copy of #ESource:parent
1492  *
1493  * Since: 3.6
1494  **/
1495 gchar *
1496 e_source_dup_parent (ESource *source)
1497 {
1498         const gchar *protected;
1499         gchar *duplicate;
1500
1501         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1502
1503         g_mutex_lock (source->priv->property_lock);
1504
1505         protected = e_source_get_parent (source);
1506         duplicate = g_strdup (protected);
1507
1508         g_mutex_unlock (source->priv->property_lock);
1509
1510         return duplicate;
1511 }
1512
1513 /**
1514  * e_source_set_parent:
1515  * @source: an #ESource
1516  * @parent: (allow-none): the UID of the parent #ESource, or %NULL
1517  *
1518  * Identifies the parent of @source by its unique identifier string.
1519  * This can only be set prior to adding @source to an #ESourceRegistry.
1520  *
1521  * The internal copy of #ESource:parent is automatically stripped of leading
1522  * and trailing whitespace.  If the resulting string is empty, %NULL is set
1523  * instead.
1524  *
1525  * Since: 3.6
1526  **/
1527 void
1528 e_source_set_parent (ESource *source,
1529                      const gchar *parent)
1530 {
1531         g_return_if_fail (E_IS_SOURCE (source));
1532
1533         g_mutex_lock (source->priv->property_lock);
1534
1535         if (g_strcmp0 (source->priv->parent, parent) == 0) {
1536                 g_mutex_unlock (source->priv->property_lock);
1537                 return;
1538         }
1539
1540         g_free (source->priv->parent);
1541         source->priv->parent = e_util_strdup_strip (parent);
1542
1543         g_mutex_unlock (source->priv->property_lock);
1544
1545         g_object_notify (G_OBJECT (source), "parent");
1546 }
1547
1548 /**
1549  * e_source_get_enabled:
1550  * @source: an #ESource
1551  *
1552  * Returns %TRUE if @source is enabled.
1553  *
1554  * An application should try to honor this setting if at all possible,
1555  * even if it does not provide a way to change the setting through its
1556  * user interface.  Disabled data sources should generally be hidden.
1557  *
1558  * Returns: whether @source is enabled
1559  *
1560  * Since: 3.6
1561  **/
1562 gboolean
1563 e_source_get_enabled (ESource *source)
1564 {
1565         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1566
1567         return source->priv->enabled;
1568 }
1569
1570 /**
1571  * e_source_set_enabled:
1572  * @source: an #ESource
1573  * @enabled: whether to enable @source
1574  *
1575  * Enables or disables @source.
1576  *
1577  * An application should try to honor this setting if at all possible,
1578  * even if it does not provide a way to change the setting through its
1579  * user interface.  Disabled data sources should generally be hidden.
1580  *
1581  * Since: 3.6
1582  **/
1583 void
1584 e_source_set_enabled (ESource *source,
1585                       gboolean enabled)
1586 {
1587         g_return_if_fail (E_IS_SOURCE (source));
1588
1589         if ((enabled ? 1 : 0) == (source->priv->enabled ? 1 : 0))
1590                 return;
1591
1592         source->priv->enabled = enabled;
1593
1594         g_object_notify (G_OBJECT (source), "enabled");
1595 }
1596
1597 /**
1598  * e_source_get_writable:
1599  * @source: an #ESource
1600  *
1601  * Returns whether the D-Bus service will accept changes to @source.
1602  * If @source is not writable, calls to e_source_write() will fail.
1603  *
1604  * Returns: whether @source is writable
1605  *
1606  * Since: 3.6
1607  **/
1608 gboolean
1609 e_source_get_writable (ESource *source)
1610 {
1611         EDBusObject *dbus_object;
1612         EDBusSourceWritable *dbus_source;
1613
1614         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1615
1616         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1617         dbus_source = e_dbus_object_peek_source_writable (dbus_object);
1618
1619         return (dbus_source != NULL);
1620 }
1621
1622 /**
1623  * e_source_get_removable:
1624  * @source: an #ESource
1625  *
1626  * Returns whether the D-Bus service will allow @source to be removed.
1627  * If @source is not writable, calls to e_source_remove() will fail.
1628  *
1629  * Returns: whether @source is removable
1630  *
1631  * Since: 3.6
1632  **/
1633 gboolean
1634 e_source_get_removable (ESource *source)
1635 {
1636         EDBusObject *dbus_object;
1637         EDBusSourceRemovable *dbus_source;
1638
1639         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1640
1641         dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
1642         dbus_source = e_dbus_object_peek_source_removable (dbus_object);
1643
1644         return (dbus_source != NULL);
1645 }
1646
1647 /**
1648  * e_source_get_extension:
1649  * @source: an #ESource
1650  * @extension_name: an extension name
1651  *
1652  * Returns an instance of some #ESourceExtension subclass which registered
1653  * itself under @extension_name.  If no such instance exists within @source,
1654  * one will be created.  It is the caller's responsibility to know which
1655  * subclass is being returned.
1656  *
1657  * If you just want to test for the existence of an extension within @source
1658  * without creating it, use e_source_has_extension().
1659  *
1660  * Extension instances are owned by their #ESource and should not be
1661  * referenced directly.  Instead, reference the #ESource instance and
1662  * use this function to fetch the extension instance as needed.
1663  *
1664  * Returns: (type ESourceExtension) (transfer none): an instance of some
1665  * #ESourceExtension subclass
1666  *
1667  * Since: 3.6
1668  **/
1669 gpointer
1670 e_source_get_extension (ESource *source,
1671                         const gchar *extension_name)
1672 {
1673         ESourceExtension *extension;
1674         GHashTable *hash_table;
1675         GTypeClass *class;
1676
1677         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1678         g_return_val_if_fail (extension_name != NULL, NULL);
1679
1680         g_static_rec_mutex_lock (&source->priv->lock);
1681
1682         /* Check if we already have the extension. */
1683         extension = g_hash_table_lookup (
1684                 source->priv->extensions, extension_name);
1685         if (extension != NULL)
1686                 goto exit;
1687
1688         /* Find all subclasses of ESourceExtensionClass. */
1689         hash_table = source_find_extension_classes ();
1690         class = g_hash_table_lookup (hash_table, extension_name);
1691
1692         /* Create a new instance of the appropriate GType. */
1693         if (class != NULL) {
1694                 extension = g_object_new (
1695                         G_TYPE_FROM_CLASS (class),
1696                         "source", source, NULL);
1697                 source_load_from_key_file (
1698                         G_OBJECT (extension),
1699                         source->priv->key_file,
1700                         extension_name);
1701                 g_hash_table_insert (
1702                         source->priv->extensions,
1703                         g_strdup (extension_name), extension);
1704         } else {
1705                 /* XXX Tie this into a debug setting for ESources. */
1706 #ifdef DEBUG
1707                 g_critical (
1708                         "No registered GType for ESource "
1709                         "extension '%s'", extension_name);
1710 #endif
1711         }
1712
1713         g_hash_table_destroy (hash_table);
1714
1715 exit:
1716         g_static_rec_mutex_unlock (&source->priv->lock);
1717
1718         return extension;
1719 }
1720
1721 /**
1722  * e_source_has_extension:
1723  * @source: an #ESource
1724  * @extension_name: an extension name
1725  *
1726  * Checks whether @source has an #ESourceExtension with the given name.
1727  *
1728  * Returns: %TRUE if @source has such an extension, %FALSE if not
1729  *
1730  * Since: 3.6
1731  **/
1732 gboolean
1733 e_source_has_extension (ESource *source,
1734                         const gchar *extension_name)
1735 {
1736         ESourceExtension *extension;
1737
1738         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1739         g_return_val_if_fail (extension_name != NULL, FALSE);
1740
1741         g_static_rec_mutex_lock (&source->priv->lock);
1742
1743         /* Two cases to check for, either one is good enough:
1744          * 1) Our internal GKeyFile has a group named 'extension_name'.
1745          * 2) Our 'extensions' table has an entry for 'extension_name'.
1746          *
1747          * We have to check both data structures in case a new extension
1748          * not present in the GKeyFile was instantiated, but we have not
1749          * yet updated our internal GKeyFile.  A common occurrence when
1750          * editing a brand new data source.
1751          *
1752          * When checking the GKeyFile we want to actually fetch the
1753          * extension with e_source_get_extension() to make sure it's
1754          * a registered extension name and not just an arbitrary key
1755          * file group name. */
1756
1757         if (g_key_file_has_group (source->priv->key_file, extension_name)) {
1758                 extension = e_source_get_extension (source, extension_name);
1759         } else {
1760                 GHashTable *hash_table = source->priv->extensions;
1761                 extension = g_hash_table_lookup (hash_table, extension_name);
1762         }
1763
1764         g_static_rec_mutex_unlock (&source->priv->lock);
1765
1766         return (extension != NULL);
1767 }
1768
1769 /**
1770  * e_source_ref_dbus_object:
1771  * @source: an #ESource
1772  *
1773  * Returns the #GDBusObject that was passed to e_source_new().
1774  *
1775  * The returned #GDBusObject is referenced for thread-safety and must be
1776  * unreferenced with g_object_unref() when finished with it.
1777  *
1778  * Returns: (transfer full): the #GDBusObject for @source, or %NULL
1779  *
1780  * Since: 3.6
1781  **/
1782 GDBusObject *
1783 e_source_ref_dbus_object (ESource *source)
1784 {
1785         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1786
1787         if (source->priv->dbus_object == NULL)
1788                 return NULL;
1789
1790         return g_object_ref (source->priv->dbus_object);
1791 }
1792
1793 /**
1794  * e_source_ref_main_context:
1795  * @source: an #ESource
1796  *
1797  * Returns the #GMainContext from which #ESource::changed signals are
1798  * emitted.
1799  *
1800  * The returned #GMainContext is referenced for thread-safety and must be
1801  * unreferenced with g_main_context_unref() when finished with it.
1802  *
1803  * Returns: (transfer full): the #GMainContext for signal emissions
1804  *
1805  * Since: 3.6
1806  **/
1807 GMainContext *
1808 e_source_ref_main_context (ESource *source)
1809 {
1810         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1811
1812         return g_main_context_ref (source->priv->main_context);
1813 }
1814
1815 /**
1816  * e_source_get_display_name:
1817  * @source: an #ESource
1818  *
1819  * Returns the display name for @source.  Use the display name to
1820  * represent the #ESource in a user interface.
1821  *
1822  * Returns: the display name for @source
1823  *
1824  * Since: 3.6
1825  **/
1826 const gchar *
1827 e_source_get_display_name (ESource *source)
1828 {
1829         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1830
1831         return source->priv->display_name;
1832 }
1833
1834 /**
1835  * e_source_dup_display_name:
1836  * @source: an #ESource
1837  *
1838  * Thread-safe variation of e_source_get_display_name().
1839  * Use this function when accessing @source from multiple threads.
1840  *
1841  * The returned string should be freed with g_free() when no longer needed.
1842  *
1843  * Returns: a newly-allocated copy of #ESource:display-name
1844  *
1845  * Since: 3.6
1846  **/
1847 gchar *
1848 e_source_dup_display_name (ESource *source)
1849 {
1850         const gchar *protected;
1851         gchar *duplicate;
1852
1853         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1854
1855         g_mutex_lock (source->priv->property_lock);
1856
1857         protected = e_source_get_display_name (source);
1858         duplicate = g_strdup (protected);
1859
1860         g_mutex_unlock (source->priv->property_lock);
1861
1862         return duplicate;
1863 }
1864
1865 /**
1866  * e_source_set_display_name:
1867  * @source: an #ESource
1868  * @display_name: a display name
1869  *
1870  * Sets the display name for @source.  The @display_name argument must be a
1871  * valid UTF-8 string.  Use the display name to represent the #ESource in a
1872  * user interface.
1873  *
1874  * The internal copy of @display_name is automatically stripped of leading
1875  * and trailing whitespace.
1876  *
1877  * Since: 3.6
1878  **/
1879 void
1880 e_source_set_display_name (ESource *source,
1881                            const gchar *display_name)
1882 {
1883         g_return_if_fail (E_IS_SOURCE (source));
1884         g_return_if_fail (display_name != NULL);
1885         g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
1886
1887         g_mutex_lock (source->priv->property_lock);
1888
1889         if (g_strcmp0 (source->priv->display_name, display_name) == 0) {
1890                 g_mutex_unlock (source->priv->property_lock);
1891                 return;
1892         }
1893
1894         g_free (source->priv->display_name);
1895         source->priv->display_name = g_strdup (display_name);
1896
1897         /* Strip leading and trailing whitespace. */
1898         g_strstrip (source->priv->display_name);
1899
1900         /* This is used in e_source_compare_by_display_name(). */
1901         g_free (source->priv->collate_key);
1902         source->priv->collate_key = g_utf8_collate_key (display_name, -1);
1903
1904         g_mutex_unlock (source->priv->property_lock);
1905
1906         g_object_notify (G_OBJECT (source), "display-name");
1907 }
1908
1909 /**
1910  * e_source_compare_by_display_name:
1911  * @source1: the first #ESource
1912  * @source2: the second #ESource
1913  *
1914  * Compares two #ESource instances by their display names.  Useful for
1915  * ordering sources in a user interface.
1916  *
1917  * Returns: a negative value if @source1 compares before @source2, zero if
1918  *          they compare equal, or a positive value if @source1 compares
1919  *          after @source2
1920  *
1921  * Since: 3.6
1922  **/
1923 gint
1924 e_source_compare_by_display_name (ESource *source1,
1925                                   ESource *source2)
1926 {
1927         return g_strcmp0 (
1928                 source1->priv->collate_key,
1929                 source2->priv->collate_key);
1930 }
1931
1932 /**
1933  * e_source_to_string:
1934  * @source: an #ESource
1935  * @length: (allow-none): return location for the length of the returned
1936  *          string, or %NULL
1937  *
1938  * Outputs the current contents of @source as a key file string.
1939  * Free the returned string with g_free().
1940  *
1941  * Returns: a newly-allocated string
1942  *
1943  * Since: 3.6
1944  **/
1945 gchar *
1946 e_source_to_string (ESource *source,
1947                     gsize *length)
1948 {
1949         GHashTableIter iter;
1950         GKeyFile *key_file;
1951         gpointer group_name;
1952         gpointer extension;
1953         gchar *data;
1954
1955         g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1956
1957         g_static_rec_mutex_lock (&source->priv->lock);
1958
1959         key_file = source->priv->key_file;
1960
1961         source_save_to_key_file (
1962                 G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
1963
1964         g_hash_table_iter_init (&iter, source->priv->extensions);
1965         while (g_hash_table_iter_next (&iter, &group_name, &extension))
1966                 source_save_to_key_file (extension, key_file, group_name);
1967
1968         data = g_key_file_to_data (key_file, length, NULL);
1969
1970         g_static_rec_mutex_unlock (&source->priv->lock);
1971
1972         return data;
1973 }
1974
1975 /**
1976  * e_source_parameter_to_key:
1977  * @param_name: a #GParamSpec name
1978  *
1979  * Converts a #GParamSpec name (e.g. "foo-bar" or "foo_bar")
1980  * to "CamelCase" for use as a #GKeyFile key (e.g. "FooBar").
1981  *
1982  * This function is made public only to aid in account migration.
1983  * Applications should not need to use this.
1984  *
1985  * Since: 3.6
1986  **/
1987 gchar *
1988 e_source_parameter_to_key (const gchar *param_name)
1989 {
1990         gboolean uppercase = TRUE;
1991         gchar *key, *cp;
1992         gint ii;
1993
1994         g_return_val_if_fail (param_name != NULL, NULL);
1995
1996         key = cp = g_malloc0 (strlen (param_name) + 1);
1997
1998         for (ii = 0; param_name[ii] != '\0'; ii++) {
1999                 if (g_ascii_isalnum (param_name[ii]) && uppercase) {
2000                         *cp++ = g_ascii_toupper (param_name[ii]);
2001                         uppercase = FALSE;
2002                 } else if (param_name[ii] == '-' || param_name[ii] == '_')
2003                         uppercase = TRUE;
2004                 else
2005                         *cp++ = param_name[ii];
2006         }
2007
2008         return key;
2009 }
2010
2011 /**
2012  * e_source_remove_sync:
2013  * @source: the #ESource to be removed
2014  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2015  * @error: return location for a #GError, or %NULL
2016  *
2017  * Requests the D-Bus service to delete the key files for @source and all of
2018  * its descendants and broadcast their removal to all clients.  If an error
2019  * occurs, the functon will set @error and return %FALSE.
2020  *
2021  * Returns: %TRUE on success, %FALSE on failure
2022  *
2023  * Since: 3.6
2024  **/
2025 gboolean
2026 e_source_remove_sync (ESource *source,
2027                       GCancellable *cancellable,
2028                       GError **error)
2029 {
2030         ESourceClass *class;
2031
2032         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2033
2034         class = E_SOURCE_GET_CLASS (source);
2035         g_return_val_if_fail (class->remove_sync != NULL, FALSE);
2036
2037         return class->remove_sync (source, cancellable, error);
2038 }
2039
2040 /**
2041  * e_source_remove:
2042  * @source: the #ESource to be removed
2043  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2044  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2045  *            is satisfied
2046  * @user_data: (closure): data to pass to the callback function
2047  *
2048  * Asynchronously requests the D-Bus service to delete the key files for
2049  * @source all of its descendants and broadcast their removal to all clients.
2050  *
2051  * When the operation is finished, @callback will be called.  You can then
2052  * call e_source_remove_finish() to get the result of the operation.
2053  *
2054  * Since: 3.6
2055  **/
2056 void
2057 e_source_remove (ESource *source,
2058                  GCancellable *cancellable,
2059                  GAsyncReadyCallback callback,
2060                  gpointer user_data)
2061 {
2062         ESourceClass *class;
2063
2064         g_return_if_fail (E_IS_SOURCE (source));
2065
2066         class = E_SOURCE_GET_CLASS (source);
2067         g_return_if_fail (class->remove != NULL);
2068
2069         class->remove (source, cancellable, callback, user_data);
2070 }
2071
2072 /**
2073  * e_source_remove_finish:
2074  * @source: the #ESource to be removed
2075  * @result: a #GAsyncResult
2076  * @error: return location for a #GError, or %NULL
2077  *
2078  * Finishes the operation started with e_source_remove().  If an
2079  * error occured, the function will set @error and return %FALSE.
2080  *
2081  * Returns: %TRUE on success, %FALSE of failure
2082  *
2083  * Since: 3.6
2084  **/
2085 gboolean
2086 e_source_remove_finish (ESource *source,
2087                         GAsyncResult *result,
2088                         GError **error)
2089 {
2090         ESourceClass *class;
2091
2092         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2093         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2094
2095         class = E_SOURCE_GET_CLASS (source);
2096         g_return_val_if_fail (class->remove_finish != NULL, FALSE);
2097
2098         return class->remove_finish (source, result, error);
2099 }
2100
2101 /**
2102  * e_source_write_sync:
2103  * @source: a writable #ESource
2104  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2105  * @error: return location for a #GError, or %NULL
2106  *
2107  * Submits the current contents of @source to the D-Bus service to be
2108  * written to disk and broadcast to other clients.  This can only be
2109  * called on #ESource:writable data sources.
2110  *
2111  * Returns: %TRUE on success, %FALSE on failure
2112  *
2113  * Since: 3.6
2114  **/
2115 gboolean
2116 e_source_write_sync (ESource *source,
2117                      GCancellable *cancellable,
2118                      GError **error)
2119 {
2120         ESourceClass *class;
2121
2122         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2123
2124         class = E_SOURCE_GET_CLASS (source);
2125         g_return_val_if_fail (class->write_sync != NULL, FALSE);
2126
2127         return class->write_sync (source, cancellable, error);
2128 }
2129
2130 /**
2131  * e_source_write:
2132  * @source: a writable #ESource
2133  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
2134  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
2135  *            is satisfied
2136  * @user_data: (closure): data to pass to the callback function
2137  *
2138  * Asynchronously submits the current contents of @source to the D-Bus
2139  * service to be written to disk and broadcast to other clients.  This
2140  * can only be called on #ESource:writable data sources.
2141  *
2142  * When the operation is finished, @callback will be called.  You can then
2143  * call e_source_write_finish() to get the result of the operation.
2144  *
2145  * Since: 3.6
2146  **/
2147 void
2148 e_source_write (ESource *source,
2149                 GCancellable *cancellable,
2150                 GAsyncReadyCallback callback,
2151                 gpointer user_data)
2152 {
2153         ESourceClass *class;
2154
2155         g_return_if_fail (E_IS_SOURCE (source));
2156
2157         class = E_SOURCE_GET_CLASS (source);
2158         g_return_if_fail (class->write != NULL);
2159
2160         class->write (source, cancellable, callback, user_data);
2161 }
2162
2163 /**
2164  * e_source_write_finish:
2165  * @source: a writable #ESource
2166  * @result: a #GAsyncResult
2167  * @error: return location for a #GError, or %NULL
2168  *
2169  * Finishes the operation started with e_source_write().  If an
2170  * error occurred, the function will set @error and return %FALSE.
2171  *
2172  * Returns: %TRUE on success, %FALSE on failure
2173  *
2174  * Since: 3.6
2175  **/
2176 gboolean
2177 e_source_write_finish (ESource *source,
2178                        GAsyncResult *result,
2179                        GError **error)
2180 {
2181         ESourceClass *class;
2182
2183         g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2184         g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2185
2186         class = E_SOURCE_GET_CLASS (source);
2187         g_return_val_if_fail (class->write_finish != NULL, FALSE);
2188
2189         return class->write_finish (source, result, error);
2190 }
2191