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