1 /*
2  * e-source.c
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 /**
19  * SECTION: e-source
20  * @include: libedataserver/libedataserver.h
21  * @short_description: Hierarchical data sources
22  *
23  * An #ESource (or "data source") is a description of a file or network
24  * location where data can be obtained (such as a mail account), or a
25  * description of a resource at that location (such as a mail folder).
26  *
27  * In more concrete terms, it's an interface for a key file.  All such
28  * key files have a main group named [Data Source].  The keys in a
29  * [Data Source] group map to #GObject properties in an #ESource.
30  *
31  * Additional groups in the key file are referred to as "extensions".
32  * #ESourceExtension serves as the base class for writing interfaces
33  * for these additional key file groups.  The keys in one of these
34  * key file groups map to #GObject properties in some custom subclass
35  * of #ESourceExtension which was written specifically for that key
36  * file group.  For example, a key file might include a group named
37  * [Calendar], whose keys map to #GObject properties in an extension
38  * class named #ESourceCalendar.
39  *
40  * Each #ESource contains an internal dictionary of extension objects,
41  * accessible by their key file group name.  e_source_get_extension()
42  * can look up extension objects by name.
43  *
44  * An #ESource is identified by a unique identifier string, or "UID",
45  * which is also the basename of the corresponding key file.  Additional
46  * files related to the #ESource, such as cache files, are usually kept
47  * in a directory named after the UID of the #ESource.  Similarly, the
48  * password for an account described by an #ESource is kept in GNOME
49  * Keyring under the UID of the #ESource.  This makes finding these
50  * additional resources simple.
51  *
52  * Several extensions for common information such as authentication
53  * details are built into libedataserver (#ESourceAuthentication, for
54  * example).  Backend modules may also define their own extensions for
55  * information and settings unique to the backend.  #ESourceExtension
56  * subclasses written for specific backends are generally not available
57  * to applications and shared libraries.  This is by design, to try and
58  * keep backend-specific knowledge from creeping into places it doesn't
59  * belong.
60  *
61  * As of 3.12, an #ESource with an #ESourceProxy extension can serve as a
62  * #GProxyResolver.  Calling g_proxy_resolver_is_supported() on an #ESource
63  * will reflect this constraint.  Attempting a proxy lookup operation on an
64  * #ESource for which g_proxy_resolver_is_supported() returns %FALSE will
65  * fail with %G_IO_ERROR_NOT_SUPPORTED.
66  **/
67 
68 #include "evolution-data-server-config.h"
69 
70 #include <string.h>
71 #include <glib/gi18n-lib.h>
72 
73 /* Private D-Bus classes. */
74 #include "e-dbus-source.h"
75 
76 #include "e-data-server-util.h"
77 #include "e-oauth2-services.h"
78 #include "e-secret-store.h"
79 #include "e-source-enumtypes.h"
80 #include "e-source-extension.h"
81 #include "e-source-registry.h"
82 #include "e-uid.h"
83 
84 /* built-in extension types */
85 #include "e-source-address-book.h"
86 #include "e-source-alarms.h"
87 #include "e-source-authentication.h"
88 #include "e-source-autocomplete.h"
89 #include "e-source-autoconfig.h"
90 #include "e-source-calendar.h"
91 #include "e-source-camel.h"
92 #include "e-source-collection.h"
93 #include "e-source-contacts.h"
94 #include "e-source-goa.h"
95 #include "e-source-ldap.h"
96 #include "e-source-local.h"
97 #include "e-source-mail-account.h"
98 #include "e-source-mail-composition.h"
99 #include "e-source-mail-identity.h"
100 #include "e-source-mail-signature.h"
101 #include "e-source-mail-submission.h"
102 #include "e-source-mail-transport.h"
103 #include "e-source-mdn.h"
104 #include "e-source-memo-list.h"
105 #include "e-source-offline.h"
106 #include "e-source-openpgp.h"
107 #include "e-source-proxy.h"
108 #include "e-source-refresh.h"
109 #include "e-source-resource.h"
110 #include "e-source-revision-guards.h"
111 #include "e-source-security.h"
112 #include "e-source-selectable.h"
113 #include "e-source-smime.h"
114 #include "e-source-task-list.h"
115 #include "e-source-uoa.h"
116 #include "e-source-weather.h"
117 #include "e-source-webdav.h"
118 
119 #include "e-source.h"
120 
121 #define PRIMARY_GROUP_NAME	"Data Source"
122 
123 typedef struct _AsyncContext AsyncContext;
124 typedef struct _RemoveContext RemoveContext;
125 
126 struct _ESourcePrivate {
127 	GDBusObject *dbus_object;
128 	GMainContext *main_context;
129 
130 	GSource *changed;
131 	GMutex changed_lock;
132 	guint ignore_changed_signal;
133 
134 	GSource *connection_status_change;
135 	GMutex connection_status_change_lock;
136 	ESourceConnectionStatus connection_status;
137 
138 	GMutex property_lock;
139 
140 	gchar *display_name;
141 	gchar *collate_key;
142 	gchar *parent;
143 	gchar *uid;
144 
145 	/* The lock guards the key file and hash table. */
146 
147 	GKeyFile *key_file;
148 	GRecMutex lock;
149 	GHashTable *extensions;
150 
151 	gboolean enabled;
152 	gboolean initialized;
153 };
154 
155 struct _AsyncContext {
156 	ESource *scratch_source;
157 	gchar *access_token;
158 	gint expires_in;
159 	gchar *password;
160 	gboolean permanently;
161 };
162 
163 /* Used in e_source_remove_sync() */
164 struct _RemoveContext {
165 	GMainContext *main_context;
166 	GMainLoop *main_loop;
167 };
168 
169 enum {
170 	PROP_0,
171 	PROP_DBUS_OBJECT,
172 	PROP_DISPLAY_NAME,
173 	PROP_ENABLED,
174 	PROP_MAIN_CONTEXT,
175 	PROP_PARENT,
176 	PROP_REMOTE_CREATABLE,
177 	PROP_REMOTE_DELETABLE,
178 	PROP_REMOVABLE,
179 	PROP_UID,
180 	PROP_WRITABLE,
181 	PROP_CONNECTION_STATUS
182 };
183 
184 enum {
185 	CHANGED,
186 	CREDENTIALS_REQUIRED,
187 	AUTHENTICATE,
188 	LAST_SIGNAL
189 };
190 
191 static guint signals[LAST_SIGNAL];
192 
193 /* Forward Declarations */
194 static void	e_source_initable_init	(GInitableIface *iface);
195 static void	e_source_proxy_resolver_init
196 					(GProxyResolverInterface *iface);
197 
198 /* Private function shared only with ESourceRegistry. */
199 void		__e_source_private_replace_dbus_object
200 						(ESource *source,
201 						 GDBusObject *dbus_object);
202 
G_DEFINE_TYPE_WITH_CODE(ESource,e_source,G_TYPE_OBJECT,G_ADD_PRIVATE (ESource)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_source_initable_init)G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,e_source_proxy_resolver_init))203 G_DEFINE_TYPE_WITH_CODE (
204 	ESource,
205 	e_source,
206 	G_TYPE_OBJECT,
207 	G_ADD_PRIVATE (ESource)
208 	G_IMPLEMENT_INTERFACE (
209 		G_TYPE_INITABLE,
210 		e_source_initable_init)
211 	G_IMPLEMENT_INTERFACE (
212 		G_TYPE_PROXY_RESOLVER,
213 		e_source_proxy_resolver_init))
214 
215 static void
216 async_context_free (AsyncContext *async_context)
217 {
218 	if (async_context->scratch_source != NULL)
219 		g_object_unref (async_context->scratch_source);
220 
221 	g_free (async_context->access_token);
222 	g_free (async_context->password);
223 
224 	g_slice_free (AsyncContext, async_context);
225 }
226 
227 static RemoveContext *
remove_context_new(void)228 remove_context_new (void)
229 {
230 	RemoveContext *remove_context;
231 
232 	remove_context = g_slice_new0 (RemoveContext);
233 
234 	remove_context->main_context = g_main_context_new ();
235 
236 	remove_context->main_loop = g_main_loop_new (
237 		remove_context->main_context, FALSE);
238 
239 	return remove_context;
240 }
241 
242 static void
remove_context_free(RemoveContext * remove_context)243 remove_context_free (RemoveContext *remove_context)
244 {
245 	g_main_loop_unref (remove_context->main_loop);
246 	g_main_context_unref (remove_context->main_context);
247 
248 	g_slice_free (RemoveContext, remove_context);
249 }
250 
251 static void
source_find_extension_classes_rec(GType parent_type,GHashTable * hash_table)252 source_find_extension_classes_rec (GType parent_type,
253                                    GHashTable *hash_table)
254 {
255 	GType *children;
256 	guint n_children, ii;
257 
258 	children = g_type_children (parent_type, &n_children);
259 
260 	for (ii = 0; ii < n_children; ii++) {
261 		GType type = children[ii];
262 		ESourceExtensionClass *class;
263 		gpointer key;
264 
265 		/* Recurse over the child's children. */
266 		source_find_extension_classes_rec (type, hash_table);
267 
268 		/* Skip abstract types. */
269 		if (G_TYPE_IS_ABSTRACT (type))
270 			continue;
271 
272 		class = g_type_class_ref (type);
273 		key = (gpointer) class->name;
274 
275 		if (key != NULL)
276 			g_hash_table_insert (hash_table, key, class);
277 		else
278 			g_type_class_unref (class);
279 	}
280 
281 	g_free (children);
282 }
283 
284 static GHashTable *
source_find_extension_classes(void)285 source_find_extension_classes (void)
286 {
287 	GHashTable *hash_table;
288 
289 	hash_table = g_hash_table_new_full (
290 		(GHashFunc) g_str_hash,
291 		(GEqualFunc) g_str_equal,
292 		(GDestroyNotify) NULL,
293 		(GDestroyNotify) g_type_class_unref);
294 
295 	source_find_extension_classes_rec (
296 		E_TYPE_SOURCE_EXTENSION, hash_table);
297 
298 	return hash_table;
299 }
300 
301 static void
source_localized_hack(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * new_value)302 source_localized_hack (GKeyFile *key_file,
303                        const gchar *group_name,
304                        const gchar *key,
305                        const gchar *new_value)
306 {
307 	const gchar * const *language_names;
308 	gint ii;
309 
310 	/* XXX If we're changing a string key that has translations,
311 	 *     set "key[$CURRENT_LOCALE]" (if available) to the new
312 	 *     value so g_key_file_get_locale_string() will pick it
313 	 *     up.  This is not a perfect solution however.  When a
314 	 *     different locale is used the value may revert to its
315 	 *     original localized string.  Good enough for now. */
316 
317 	language_names = g_get_language_names ();
318 
319 	for (ii = 0; language_names[ii] != NULL; ii++) {
320 		gboolean has_localized_key;
321 		gchar *localized_key;
322 
323 		localized_key = g_strdup_printf (
324 			"%s[%s]", key, language_names[ii]);
325 		has_localized_key = g_key_file_has_key (
326 			key_file, group_name, localized_key, NULL);
327 
328 		if (has_localized_key)
329 			g_key_file_set_string (
330 				key_file, group_name,
331 				localized_key, new_value);
332 
333 		g_free (localized_key);
334 
335 		if (has_localized_key)
336 			return;
337 	}
338 
339 	g_key_file_set_string (key_file, group_name, key, new_value);
340 }
341 
342 static gboolean
source_check_values_differ(GType g_type,const GValue * value,const GValue * value2)343 source_check_values_differ (GType g_type,
344                             const GValue *value,
345                             const GValue *value2)
346 {
347 	gboolean differ = TRUE;
348 	GValue *value1;
349 
350 	g_return_val_if_fail (value != NULL, TRUE);
351 	g_return_val_if_fail (value2 != NULL, TRUE);
352 
353 	value1 = g_slice_new0 (GValue);
354 	g_value_init (value1, g_type);
355 	g_value_copy (value2, value1);
356 
357 	if (g_value_transform (value, value1)) {
358 		#define check_type(name,get) G_STMT_START { \
359 			if (G_VALUE_HOLDS_ ## name (value1)) { \
360 				differ = g_value_get_ ## get (value1) != g_value_get_ ## get (value2); \
361 				break; \
362 			} } G_STMT_END
363 
364 		do {
365 			check_type (BOOLEAN, boolean);
366 			check_type (CHAR, schar);
367 			check_type (DOUBLE, double);
368 			check_type (ENUM, enum);
369 			check_type (FLAGS, flags);
370 			check_type (FLOAT, float);
371 			check_type (GTYPE, gtype);
372 			check_type (INT, int);
373 			check_type (INT64, int64);
374 			check_type (LONG, long);
375 			check_type (POINTER, pointer);
376 			check_type (UCHAR, uchar);
377 			check_type (UINT, uint);
378 			check_type (UINT64, uint64);
379 			check_type (ULONG, ulong);
380 
381 			if (G_VALUE_HOLDS_STRING (value1)) {
382 				differ = g_strcmp0 (g_value_get_string (value1), g_value_get_string (value2)) != 0;
383 				break;
384 			}
385 
386 			if (G_VALUE_HOLDS_VARIANT (value1)) {
387 				GVariant *variant1, *variant2;
388 
389 				variant1 = g_value_get_variant (value1);
390 				variant2 = g_value_get_variant (value2);
391 				differ = g_variant_compare (variant1, variant2) != 0;
392 				break;
393 			}
394 		} while (FALSE);
395 
396 		#undef check_type
397 	}
398 
399 	g_value_unset (value1);
400 	g_slice_free (GValue, value1);
401 
402 	return differ;
403 }
404 
405 static void
source_set_key_file_from_property(GObject * object,GParamSpec * pspec,GKeyFile * key_file,const gchar * group_name)406 source_set_key_file_from_property (GObject *object,
407                                    GParamSpec *pspec,
408                                    GKeyFile *key_file,
409                                    const gchar *group_name)
410 {
411 	GValue *pvalue;
412 	GValue *svalue;
413 	gchar *key;
414 
415 	pvalue = g_slice_new0 (GValue);
416 	g_value_init (pvalue, pspec->value_type);
417 	g_object_get_property (object, pspec->name, pvalue);
418 
419 	svalue = g_slice_new0 (GValue);
420 	g_value_init (svalue, G_TYPE_STRING);
421 
422 	key = e_source_parameter_to_key (pspec->name);
423 
424 	/* For the most part we can just transform any supported
425 	 * property type to a string, with a couple exceptions. */
426 
427 	/* Transforming a boolean GValue to a string results in
428 	 * "TRUE" or "FALSE" (all uppercase), but GKeyFile only
429 	 * recognizes "true" or "false" (all lowercase).  So we
430 	 * have to use g_key_file_set_boolean(). */
431 	if (G_VALUE_HOLDS_BOOLEAN (pvalue)) {
432 		gboolean v_boolean = g_value_get_boolean (pvalue);
433 		g_key_file_set_boolean (key_file, group_name, key, v_boolean);
434 
435 	/* Store UIN64 in hexa */
436 	} else if (G_VALUE_HOLDS_UINT64 (pvalue)) {
437 		gchar *v_str;
438 
439 		v_str = g_strdup_printf (
440 			"%016" G_GINT64_MODIFIER "X",
441 			g_value_get_uint64 (pvalue));
442 		g_key_file_set_string (key_file, group_name, key, v_str);
443 		g_free (v_str);
444 
445 	/* String GValues may contain characters that need escaping. */
446 	} else if (G_VALUE_HOLDS_STRING (pvalue)) {
447 		const gchar *v_string = g_value_get_string (pvalue);
448 
449 		if (v_string == NULL)
450 			v_string = "";
451 
452 		/* Special case for localized "DisplayName" keys. */
453 		source_localized_hack (key_file, group_name, key, v_string);
454 
455 	/* Transforming an enum GValue to a string results in
456 	 * the GEnumValue name.  We want the shorter nickname. */
457 	} else if (G_VALUE_HOLDS_ENUM (pvalue)) {
458 		GParamSpecEnum *enum_pspec;
459 		GEnumClass *enum_class;
460 		GEnumValue *enum_value;
461 		gint value;
462 
463 		enum_pspec = G_PARAM_SPEC_ENUM (pspec);
464 		enum_class = enum_pspec->enum_class;
465 
466 		value = g_value_get_enum (pvalue);
467 		enum_value = g_enum_get_value (enum_class, value);
468 
469 		if (enum_value == NULL) {
470 			value = enum_pspec->default_value;
471 			enum_value = g_enum_get_value (enum_class, value);
472 		}
473 
474 		if (enum_value != NULL)
475 			g_key_file_set_string (
476 				key_file, group_name, key,
477 				enum_value->value_nick);
478 
479 	} else if (G_VALUE_HOLDS (pvalue, G_TYPE_STRV)) {
480 		const gchar **strv = g_value_get_boxed (pvalue);
481 		guint length = 0;
482 
483 		if (strv != NULL)
484 			length = g_strv_length ((gchar **) strv);
485 		g_key_file_set_string_list (
486 			key_file, group_name, key, strv, length);
487 
488 	/* For GValues holding a GFile object we save the URI. */
489 	} else if (G_VALUE_HOLDS (pvalue, G_TYPE_FILE)) {
490 		GFile *file = g_value_get_object (pvalue);
491 		gchar *uri = NULL;
492 
493 		if (file != NULL)
494 			uri = g_file_get_uri (file);
495 		g_key_file_set_string (
496 			key_file, group_name, key,
497 			(uri != NULL) ? uri : "");
498 		g_free (uri);
499 
500 	} else if (g_value_transform (pvalue, svalue)) {
501 		const gchar *value = g_value_get_string (svalue);
502 		g_key_file_set_value (key_file, group_name, key, value);
503 	}
504 
505 	g_free (key);
506 	g_value_unset (pvalue);
507 	g_value_unset (svalue);
508 	g_slice_free (GValue, pvalue);
509 	g_slice_free (GValue, svalue);
510 }
511 
512 static void
source_set_property_from_key_file(GObject * object,GParamSpec * pspec,GKeyFile * key_file,const gchar * group_name)513 source_set_property_from_key_file (GObject *object,
514                                    GParamSpec *pspec,
515                                    GKeyFile *key_file,
516                                    const gchar *group_name)
517 {
518 	gchar *key;
519 	GValue *value;
520 	GError *local_error = NULL;
521 
522 	value = g_slice_new0 (GValue);
523 	key = e_source_parameter_to_key (pspec->name);
524 
525 	if (G_IS_PARAM_SPEC_CHAR (pspec) ||
526 	    G_IS_PARAM_SPEC_UCHAR (pspec) ||
527 	    G_IS_PARAM_SPEC_INT (pspec) ||
528 	    G_IS_PARAM_SPEC_UINT (pspec) ||
529 	    G_IS_PARAM_SPEC_LONG (pspec) ||
530 	    G_IS_PARAM_SPEC_ULONG (pspec)) {
531 		gint v_int;
532 
533 		v_int = g_key_file_get_integer (
534 			key_file, group_name, key, &local_error);
535 		if (local_error == NULL) {
536 			g_value_init (value, G_TYPE_INT);
537 			g_value_set_int (value, v_int);
538 		}
539 
540 	} else if (G_IS_PARAM_SPEC_INT64 (pspec)) {
541 		gint64 v_int64;
542 
543 		v_int64 = g_key_file_get_int64 (
544 			key_file, group_name, key, &local_error);
545 		if (local_error == NULL) {
546 			g_value_init (value, G_TYPE_INT64);
547 			g_value_set_int64 (value, v_int64);
548 		}
549 
550 	} else if (G_IS_PARAM_SPEC_UINT64 (pspec)) {
551 		guint64 v_uint64;
552 		gchar *v_str;
553 
554 		v_str = g_key_file_get_string (
555 			key_file, group_name, key, &local_error);
556 		if (local_error == NULL) {
557 			v_uint64 = g_ascii_strtoull (v_str, NULL, 16);
558 
559 			g_value_init (value, G_TYPE_UINT64);
560 			g_value_set_uint64 (value, v_uint64);
561 		}
562 
563 		g_free (v_str);
564 
565 	} else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
566 		gboolean v_boolean;
567 
568 		v_boolean = g_key_file_get_boolean (
569 			key_file, group_name, key, &local_error);
570 		if (local_error == NULL) {
571 			g_value_init (value, G_TYPE_BOOLEAN);
572 			g_value_set_boolean (value, v_boolean);
573 		}
574 
575 	} else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
576 		gchar *nick;
577 
578 		nick = g_key_file_get_string (
579 			key_file, group_name, key, &local_error);
580 		if (local_error == NULL) {
581 			GParamSpecEnum *enum_pspec;
582 			GEnumValue *enum_value;
583 
584 			enum_pspec = G_PARAM_SPEC_ENUM (pspec);
585 			enum_value = g_enum_get_value_by_nick (
586 				enum_pspec->enum_class, nick);
587 			if (enum_value != NULL) {
588 				g_value_init (value, pspec->value_type);
589 				g_value_set_enum (value, enum_value->value);
590 			}
591 			g_free (nick);
592 		}
593 
594 	} else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
595 		   G_IS_PARAM_SPEC_DOUBLE (pspec)) {
596 		gdouble v_double;
597 
598 		v_double = g_key_file_get_double (
599 			key_file, group_name, key, &local_error);
600 		if (local_error == NULL) {
601 			g_value_init (value, G_TYPE_DOUBLE);
602 			g_value_set_double (value, v_double);
603 		}
604 
605 	} else if (G_IS_PARAM_SPEC_STRING (pspec)) {
606 		gchar *v_string;
607 
608 		/* Get the localized string if present. */
609 		v_string = g_key_file_get_locale_string (
610 			key_file, group_name, key, NULL, &local_error);
611 		if (local_error == NULL) {
612 			g_value_init (value, G_TYPE_STRING);
613 			g_value_take_string (value, v_string);
614 		}
615 
616 	} else if (g_type_is_a (pspec->value_type, G_TYPE_STRV)) {
617 		gchar **strv;
618 
619 		strv = g_key_file_get_string_list (
620 			key_file, group_name, key, NULL, &local_error);
621 		if (local_error == NULL) {
622 			g_value_init (value, G_TYPE_STRV);
623 			g_value_take_boxed (value, strv);
624 		}
625 
626 	} else if (g_type_is_a (pspec->value_type, G_TYPE_FILE)) {
627 		gchar *uri;
628 
629 		/* Create the GFile from the URI string. */
630 		uri = g_key_file_get_locale_string (
631 			key_file, group_name, key, NULL, &local_error);
632 		if (local_error == NULL) {
633 			GFile *file = NULL;
634 			if (uri != NULL && *uri != '\0')
635 				file = g_file_new_for_uri (uri);
636 			g_value_init (value, pspec->value_type);
637 			g_value_take_object (value, file);
638 			g_free (uri);
639 		}
640 
641 	} else {
642 		g_warning (
643 			"No GKeyFile-to-GValue converter defined "
644 			"for type '%s'", G_PARAM_SPEC_TYPE_NAME (pspec));
645 	}
646 
647 	/* If a value could not be retrieved from the key
648 	 * file, restore the property to its default value. */
649 	if (local_error != NULL) {
650 		g_value_init (value, pspec->value_type);
651 		g_param_value_set_default (pspec, value);
652 		g_error_free (local_error);
653 	}
654 
655 	if (G_IS_VALUE (value)) {
656 		GValue *cvalue;
657 
658 		cvalue = g_slice_new0 (GValue);
659 		g_value_init (cvalue, pspec->value_type);
660 		g_object_get_property (object, pspec->name, cvalue);
661 
662 		/* This is because the g_object_set_property() invokes "notify" signal
663 		 * on the set property, even if the value did not change, which creates
664 		 * false notifications, which can cause UI or background activities
665 		 * without any real reason (especially with the ''enabled' property load). */
666 		if (!G_IS_VALUE (cvalue) || source_check_values_differ (pspec->value_type, value, cvalue))
667 			g_object_set_property (object, pspec->name, value);
668 
669 		if (G_IS_VALUE (cvalue))
670 			g_value_unset (cvalue);
671 		g_slice_free (GValue, cvalue);
672 
673 		g_value_unset (value);
674 	}
675 
676 	g_slice_free (GValue, value);
677 	g_free (key);
678 }
679 
680 static void
source_load_from_key_file(GObject * object,GKeyFile * key_file,const gchar * group_name)681 source_load_from_key_file (GObject *object,
682                            GKeyFile *key_file,
683                            const gchar *group_name)
684 {
685 	GObjectClass *class;
686 	GParamSpec **properties;
687 	guint n_properties, ii;
688 
689 	class = G_OBJECT_GET_CLASS (object);
690 	properties = g_object_class_list_properties (class, &n_properties);
691 
692 	g_object_freeze_notify (object);
693 
694 	for (ii = 0; ii < n_properties; ii++) {
695 		if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
696 			source_set_property_from_key_file (
697 				object, properties[ii], key_file, group_name);
698 		}
699 	}
700 
701 	g_object_thaw_notify (object);
702 
703 	g_free (properties);
704 }
705 
706 static void
source_save_to_key_file(GObject * object,GKeyFile * key_file,const gchar * group_name)707 source_save_to_key_file (GObject *object,
708                          GKeyFile *key_file,
709                          const gchar *group_name)
710 {
711 	GObjectClass *class;
712 	GParamSpec **properties;
713 	guint n_properties, ii;
714 
715 	class = G_OBJECT_GET_CLASS (object);
716 	properties = g_object_class_list_properties (class, &n_properties);
717 
718 	for (ii = 0; ii < n_properties; ii++) {
719 		if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
720 			source_set_key_file_from_property (
721 				object, properties[ii], key_file, group_name);
722 		}
723 	}
724 
725 	g_free (properties);
726 }
727 
728 static gboolean
source_parse_dbus_data(ESource * source,GError ** error)729 source_parse_dbus_data (ESource *source,
730                         GError **error)
731 {
732 	GHashTableIter iter;
733 	EDBusObject *dbus_object;
734 	EDBusSource *dbus_source;
735 	GKeyFile *key_file;
736 	gpointer group_name;
737 	gpointer extension;
738 	gchar *data;
739 	gboolean success;
740 
741 	if (!source->priv->dbus_object)
742 		return FALSE;
743 
744 	dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
745 
746 	dbus_source = e_dbus_object_get_source (dbus_object);
747 	data = e_dbus_source_dup_data (dbus_source);
748 	g_object_unref (dbus_source);
749 
750 	g_return_val_if_fail (data != NULL, FALSE);
751 
752 	key_file = source->priv->key_file;
753 
754 	success = g_key_file_load_from_data (
755 		key_file, data, strlen (data),
756 		G_KEY_FILE_KEEP_COMMENTS |
757 		G_KEY_FILE_KEEP_TRANSLATIONS,
758 		error);
759 
760 	g_free (data);
761 	data = NULL;
762 
763 	if (!success)
764 		return FALSE;
765 
766 	/* Make sure the key file has a [Data Source] group. */
767 	if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
768 		g_set_error (
769 			error, G_KEY_FILE_ERROR,
770 			G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
771 			_("Source file is missing a [%s] group"),
772 			PRIMARY_GROUP_NAME);
773 		return FALSE;
774 	}
775 
776 	/* Load key file values from the [Data Source] group and from
777 	 * any other groups for which an extension object has already
778 	 * been created.  Note that not all the extension classes may
779 	 * be registered at this point, so avoid attempting to create
780 	 * new extension objects here.  Extension objects are created
781 	 * on-demand in e_source_get_extension(). */
782 
783 	source_load_from_key_file (
784 		G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
785 
786 	g_hash_table_iter_init (&iter, source->priv->extensions);
787 	while (g_hash_table_iter_next (&iter, &group_name, &extension))
788 		source_load_from_key_file (extension, key_file, group_name);
789 
790 	return TRUE;
791 }
792 
793 static void
source_notify_dbus_data_cb(EDBusSource * dbus_source,GParamSpec * pspec,ESource * source)794 source_notify_dbus_data_cb (EDBusSource *dbus_source,
795                             GParamSpec *pspec,
796                             ESource *source)
797 {
798 	GError *local_error = NULL;
799 
800 	g_rec_mutex_lock (&source->priv->lock);
801 
802 	/* Since the source data came from a GKeyFile structure on the
803 	 * server-side, this should never fail.  But we'll print error
804 	 * messages to the terminal just in case. */
805 	source_parse_dbus_data (source, &local_error);
806 
807 	if (local_error != NULL) {
808 		g_warning ("%s", local_error->message);
809 		g_error_free (local_error);
810 	}
811 
812 	g_rec_mutex_unlock (&source->priv->lock);
813 }
814 
815 static gboolean
source_update_connection_status_internal(ESource * source,EDBusSource * dbus_source)816 source_update_connection_status_internal (ESource *source,
817 					  EDBusSource *dbus_source)
818 {
819 	ESourceConnectionStatus connection_status_value;
820 	gchar *connection_status;
821 	gboolean changed = FALSE;
822 
823 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
824 	g_return_val_if_fail (dbus_source != NULL, FALSE);
825 
826 	connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
827 	connection_status = e_dbus_source_dup_connection_status (dbus_source);
828 
829 	if (connection_status) {
830 		GEnumClass *enum_class;
831 		GEnumValue *enum_value;
832 
833 		enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
834 		enum_value = g_enum_get_value_by_nick (enum_class, connection_status);
835 
836 		if (enum_value) {
837 			connection_status_value = enum_value->value;
838 		} else if (!*connection_status) {
839 			connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
840 		} else {
841 			g_warning ("%s: Unknown connection status: '%s'", G_STRFUNC, connection_status);
842 		}
843 
844 		g_type_class_unref (enum_class);
845 		g_free (connection_status);
846 	}
847 
848 	if (source->priv->connection_status != connection_status_value) {
849 		source->priv->connection_status = connection_status_value;
850 		changed = TRUE;
851 	}
852 
853 	return changed;
854 }
855 
856 static void
source_update_connection_status(ESource * source)857 source_update_connection_status (ESource *source)
858 {
859 	EDBusObject *dbus_object;
860 	EDBusSource *dbus_source;
861 	gboolean changed = FALSE;
862 
863 	g_return_if_fail (E_IS_SOURCE (source));
864 
865 	g_mutex_lock (&source->priv->connection_status_change_lock);
866 	g_clear_pointer (&source->priv->connection_status_change, g_source_unref);
867 	g_mutex_unlock (&source->priv->connection_status_change_lock);
868 
869 	g_object_freeze_notify (G_OBJECT (source));
870 	g_mutex_lock (&source->priv->property_lock);
871 
872 	if (source->priv->dbus_object) {
873 		dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
874 
875 		dbus_source = e_dbus_object_get_source (dbus_object);
876 		changed = source_update_connection_status_internal (source, dbus_source);
877 		g_object_unref (dbus_source);
878 	}
879 
880 	if (changed)
881 		g_object_notify (G_OBJECT (source), "connection-status");
882 
883 	g_mutex_unlock (&source->priv->property_lock);
884 	g_object_thaw_notify (G_OBJECT (source));
885 }
886 
887 static gboolean
source_idle_connection_status_change_cb(gpointer user_data)888 source_idle_connection_status_change_cb (gpointer user_data)
889 {
890 	ESource *source;
891 
892 	if (g_source_is_destroyed (g_main_current_source ()))
893 		return FALSE;
894 
895 	source = E_SOURCE (user_data);
896 
897 	source_update_connection_status (source);
898 
899 	return FALSE;
900 }
901 
902 static void
source_notify_dbus_connection_status_cb(EDBusSource * dbus_source,GParamSpec * pspec,ESource * source)903 source_notify_dbus_connection_status_cb (EDBusSource *dbus_source,
904 					 GParamSpec *pspec,
905 					 ESource *source)
906 {
907 	g_mutex_lock (&source->priv->connection_status_change_lock);
908 	if (source->priv->connection_status_change == NULL &&
909 	    source->priv->initialized) {
910 		source->priv->connection_status_change = g_idle_source_new ();
911 		g_source_set_callback (
912 			source->priv->connection_status_change,
913 			source_idle_connection_status_change_cb,
914 			g_object_ref (source), g_object_unref);
915 		g_source_attach (
916 			source->priv->connection_status_change,
917 			source->priv->main_context);
918 	}
919 	g_mutex_unlock (&source->priv->connection_status_change_lock);
920 }
921 
922 static ESourceCredentialsReason
source_credentials_reason_from_text(const gchar * arg_reason)923 source_credentials_reason_from_text (const gchar *arg_reason)
924 {
925 	ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
926 
927 	if (arg_reason && *arg_reason) {
928 		GEnumClass *enum_class;
929 		GEnumValue *enum_value;
930 
931 		enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
932 		enum_value = g_enum_get_value_by_nick (enum_class, arg_reason);
933 
934 		if (enum_value) {
935 			reason = enum_value->value;
936 		} else {
937 			g_warning ("%s: Unknown reason enum: '%s'", G_STRFUNC, arg_reason);
938 		}
939 
940 		g_type_class_unref (enum_class);
941 	}
942 
943 	return reason;
944 }
945 
946 static GTlsCertificateFlags
source_certificate_errors_from_text(const gchar * arg_certificate_errors)947 source_certificate_errors_from_text (const gchar *arg_certificate_errors)
948 {
949 	GTlsCertificateFlags certificate_errors = 0;
950 
951 	if (arg_certificate_errors && *arg_certificate_errors) {
952 		GFlagsClass *flags_class;
953 		gchar **flags_strv;
954 		gsize ii;
955 
956 		flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
957 		flags_strv = g_strsplit (arg_certificate_errors, ":", -1);
958 		for (ii = 0; flags_strv[ii] != NULL; ii++) {
959 			GFlagsValue *flags_value;
960 
961 			flags_value = g_flags_get_value_by_nick (flags_class, flags_strv[ii]);
962 			if (flags_value != NULL) {
963 				certificate_errors |= flags_value->value;
964 			} else {
965 				g_warning ("%s: Unknown flag: '%s'", G_STRFUNC, flags_strv[ii]);
966 			}
967 		}
968 		g_strfreev (flags_strv);
969 		g_type_class_unref (flags_class);
970 	}
971 
972 	return certificate_errors;
973 }
974 
975 static void
source_dbus_credentials_required_cb(EDBusSource * dbus_source,const gchar * arg_reason,const gchar * arg_certificate_pem,const gchar * arg_certificate_errors,const gchar * arg_dbus_error_name,const gchar * arg_dbus_error_message,ESource * source)976 source_dbus_credentials_required_cb (EDBusSource *dbus_source,
977 				     const gchar *arg_reason,
978 				     const gchar *arg_certificate_pem,
979 				     const gchar *arg_certificate_errors,
980 				     const gchar *arg_dbus_error_name,
981 				     const gchar *arg_dbus_error_message,
982 				     ESource *source)
983 {
984 	ESourceCredentialsReason reason;
985 	GTlsCertificateFlags certificate_errors;
986 	GError *op_error = NULL;
987 
988 	g_return_if_fail (E_IS_SOURCE (source));
989 	g_return_if_fail (arg_reason != NULL);
990 	g_return_if_fail (arg_certificate_pem != NULL);
991 	g_return_if_fail (arg_certificate_errors != NULL);
992 	g_return_if_fail (arg_dbus_error_name != NULL);
993 	g_return_if_fail (arg_dbus_error_message != NULL);
994 
995 	reason = source_credentials_reason_from_text (arg_reason);
996 	certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
997 
998 	if (*arg_dbus_error_name) {
999 		op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
1000 		g_dbus_error_strip_remote_error (op_error);
1001 	}
1002 
1003 	/* This is delivered in the GDBus thread */
1004 	e_source_emit_credentials_required (source, reason, arg_certificate_pem, certificate_errors, op_error);
1005 
1006 	g_clear_error (&op_error);
1007 }
1008 
1009 static gboolean
source_dbus_authenticate_cb(EDBusSource * dbus_interface,const gchar * const * arg_credentials,ESource * source)1010 source_dbus_authenticate_cb (EDBusSource *dbus_interface,
1011 			     const gchar *const *arg_credentials,
1012 			     ESource *source)
1013 {
1014 	ENamedParameters *credentials;
1015 
1016 	credentials = e_named_parameters_new_strv (arg_credentials);
1017 
1018 	/* This is delivered in the GDBus thread */
1019 	g_signal_emit (source, signals[AUTHENTICATE], 0, credentials);
1020 
1021 	e_named_parameters_free (credentials);
1022 
1023 	return TRUE;
1024 }
1025 
1026 
1027 static gboolean
source_idle_changed_cb(gpointer user_data)1028 source_idle_changed_cb (gpointer user_data)
1029 {
1030 	ESource *source = E_SOURCE (user_data);
1031 
1032 	if (g_source_is_destroyed (g_main_current_source ()))
1033 		return FALSE;
1034 
1035 	g_mutex_lock (&source->priv->changed_lock);
1036 	g_clear_pointer (&source->priv->changed, g_source_unref);
1037 	g_mutex_unlock (&source->priv->changed_lock);
1038 
1039 	g_signal_emit (source, signals[CHANGED], 0);
1040 
1041 	return FALSE;
1042 }
1043 
1044 static void
source_set_dbus_object(ESource * source,EDBusObject * dbus_object)1045 source_set_dbus_object (ESource *source,
1046                         EDBusObject *dbus_object)
1047 {
1048 	/* D-Bus object will be NULL when configuring a new source. */
1049 	if (dbus_object == NULL)
1050 		return;
1051 
1052 	g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
1053 	g_return_if_fail (source->priv->dbus_object == NULL);
1054 
1055 	source->priv->dbus_object = g_object_ref (dbus_object);
1056 }
1057 
1058 static void
source_set_main_context(ESource * source,GMainContext * main_context)1059 source_set_main_context (ESource *source,
1060                          GMainContext *main_context)
1061 {
1062 	g_return_if_fail (source->priv->main_context == NULL);
1063 
1064 	source->priv->main_context =
1065 		(main_context != NULL) ?
1066 		g_main_context_ref (main_context) :
1067 		g_main_context_ref_thread_default ();
1068 }
1069 
1070 static void
source_set_uid(ESource * source,const gchar * uid)1071 source_set_uid (ESource *source,
1072                 const gchar *uid)
1073 {
1074 	/* The "uid" argument will usually be NULL unless called
1075 	 * from e_source_new_with_uid().  If NULL, we'll pick up
1076 	 * a UID in source_initable_init(). */
1077 
1078 	g_return_if_fail (source->priv->uid == NULL);
1079 
1080 	source->priv->uid = g_strdup (uid);
1081 }
1082 
1083 static void
source_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1084 source_set_property (GObject *object,
1085                      guint property_id,
1086                      const GValue *value,
1087                      GParamSpec *pspec)
1088 {
1089 	switch (property_id) {
1090 		case PROP_DBUS_OBJECT:
1091 			source_set_dbus_object (
1092 				E_SOURCE (object),
1093 				g_value_get_object (value));
1094 			return;
1095 
1096 		case PROP_DISPLAY_NAME:
1097 			e_source_set_display_name (
1098 				E_SOURCE (object),
1099 				g_value_get_string (value));
1100 			return;
1101 
1102 		case PROP_ENABLED:
1103 			e_source_set_enabled (
1104 				E_SOURCE (object),
1105 				g_value_get_boolean (value));
1106 			return;
1107 
1108 		case PROP_MAIN_CONTEXT:
1109 			source_set_main_context (
1110 				E_SOURCE (object),
1111 				g_value_get_boxed (value));
1112 			return;
1113 
1114 		case PROP_PARENT:
1115 			e_source_set_parent (
1116 				E_SOURCE (object),
1117 				g_value_get_string (value));
1118 			return;
1119 
1120 		case PROP_UID:
1121 			source_set_uid (
1122 				E_SOURCE (object),
1123 				g_value_get_string (value));
1124 			return;
1125 
1126 		case PROP_CONNECTION_STATUS:
1127 			e_source_set_connection_status (E_SOURCE (object),
1128 				g_value_get_enum (value));
1129 			return;
1130 	}
1131 
1132 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1133 }
1134 
1135 static void
source_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)1136 source_get_property (GObject *object,
1137                      guint property_id,
1138                      GValue *value,
1139                      GParamSpec *pspec)
1140 {
1141 	switch (property_id) {
1142 		case PROP_DBUS_OBJECT:
1143 			g_value_take_object (
1144 				value, e_source_ref_dbus_object (
1145 				E_SOURCE (object)));
1146 			return;
1147 
1148 		case PROP_DISPLAY_NAME:
1149 			g_value_take_string (
1150 				value, e_source_dup_display_name (
1151 				E_SOURCE (object)));
1152 			return;
1153 
1154 		case PROP_ENABLED:
1155 			g_value_set_boolean (
1156 				value, e_source_get_enabled (
1157 				E_SOURCE (object)));
1158 			return;
1159 
1160 		case PROP_MAIN_CONTEXT:
1161 			g_value_take_boxed (
1162 				value, e_source_ref_main_context (
1163 				E_SOURCE (object)));
1164 			return;
1165 
1166 		case PROP_PARENT:
1167 			g_value_take_string (
1168 				value, e_source_dup_parent (
1169 				E_SOURCE (object)));
1170 			return;
1171 
1172 		case PROP_REMOTE_CREATABLE:
1173 			g_value_set_boolean (
1174 				value, e_source_get_remote_creatable (
1175 				E_SOURCE (object)));
1176 			return;
1177 
1178 		case PROP_REMOTE_DELETABLE:
1179 			g_value_set_boolean (
1180 				value, e_source_get_remote_deletable (
1181 				E_SOURCE (object)));
1182 			return;
1183 
1184 		case PROP_REMOVABLE:
1185 			g_value_set_boolean (
1186 				value, e_source_get_removable (
1187 				E_SOURCE (object)));
1188 			return;
1189 
1190 		case PROP_UID:
1191 			g_value_take_string (
1192 				value, e_source_dup_uid (
1193 				E_SOURCE (object)));
1194 			return;
1195 
1196 		case PROP_WRITABLE:
1197 			g_value_set_boolean (
1198 				value, e_source_get_writable (
1199 				E_SOURCE (object)));
1200 			return;
1201 
1202 		case PROP_CONNECTION_STATUS:
1203 			g_value_set_enum (value,
1204 				e_source_get_connection_status (E_SOURCE (object)));
1205 			return;
1206 	}
1207 
1208 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1209 }
1210 
1211 static void
source_dispose(GObject * object)1212 source_dispose (GObject *object)
1213 {
1214 	ESourcePrivate *priv;
1215 
1216 	priv = E_SOURCE (object)->priv;
1217 
1218 	/* Lock & unlock to make sure any pending operations in other threads
1219 	   which use this lock are already done */
1220 	g_rec_mutex_lock (&priv->lock);
1221 	g_rec_mutex_unlock (&priv->lock);
1222 
1223 	g_mutex_lock (&priv->property_lock);
1224 
1225 	if (priv->dbus_object != NULL) {
1226 		EDBusObject *dbus_object;
1227 		EDBusSource *dbus_source;
1228 
1229 		dbus_object = E_DBUS_OBJECT (priv->dbus_object);
1230 
1231 		dbus_source = e_dbus_object_get_source (dbus_object);
1232 		if (dbus_source != NULL) {
1233 			g_signal_handlers_disconnect_matched (
1234 				dbus_source, G_SIGNAL_MATCH_DATA,
1235 				0, 0, NULL, NULL, object);
1236 			g_object_unref (dbus_source);
1237 		}
1238 
1239 		g_object_unref (priv->dbus_object);
1240 		priv->dbus_object = NULL;
1241 	}
1242 
1243 	g_mutex_unlock (&priv->property_lock);
1244 
1245 	g_clear_pointer (&priv->main_context, g_main_context_unref);
1246 
1247 	/* XXX Maybe not necessary to acquire the lock? */
1248 	g_mutex_lock (&priv->changed_lock);
1249 	if (priv->changed != NULL) {
1250 		g_source_destroy (priv->changed);
1251 		g_source_unref (priv->changed);
1252 		priv->changed = NULL;
1253 	}
1254 	g_mutex_unlock (&priv->changed_lock);
1255 
1256 	g_mutex_lock (&priv->connection_status_change_lock);
1257 	if (priv->connection_status_change != NULL) {
1258 		g_source_destroy (priv->connection_status_change);
1259 		g_source_unref (priv->connection_status_change);
1260 		priv->connection_status_change = NULL;
1261 	}
1262 	g_mutex_unlock (&priv->connection_status_change_lock);
1263 
1264 	g_hash_table_remove_all (priv->extensions);
1265 
1266 	/* Chain up to parent's dispose() method. */
1267 	G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
1268 }
1269 
1270 static void
source_finalize(GObject * object)1271 source_finalize (GObject *object)
1272 {
1273 	ESourcePrivate *priv;
1274 
1275 	priv = E_SOURCE (object)->priv;
1276 
1277 	g_mutex_clear (&priv->changed_lock);
1278 	g_mutex_clear (&priv->connection_status_change_lock);
1279 	g_mutex_clear (&priv->property_lock);
1280 
1281 	g_free (priv->display_name);
1282 	g_free (priv->collate_key);
1283 	g_free (priv->parent);
1284 	g_free (priv->uid);
1285 
1286 	g_key_file_free (priv->key_file);
1287 	g_rec_mutex_clear (&priv->lock);
1288 	g_hash_table_destroy (priv->extensions);
1289 
1290 	/* Chain up to parent's finalize() method. */
1291 	G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
1292 }
1293 
1294 static void
source_notify(GObject * object,GParamSpec * pspec)1295 source_notify (GObject *object,
1296                GParamSpec *pspec)
1297 {
1298 	if ((pspec->flags & E_SOURCE_PARAM_SETTING) != 0)
1299 		e_source_changed (E_SOURCE (object));
1300 }
1301 
1302 /* Helper for source_remove_sync() */
1303 static gboolean
source_remove_main_loop_quit_cb(gpointer user_data)1304 source_remove_main_loop_quit_cb (gpointer user_data)
1305 {
1306 	GMainLoop *main_loop = user_data;
1307 
1308 	g_main_loop_quit (main_loop);
1309 
1310 	return FALSE;
1311 }
1312 
1313 /* Helper for e_source_remove_sync() */
1314 static void
source_remove_notify_dbus_object_cb(ESource * source,GParamSpec * pspec,RemoveContext * remove_context)1315 source_remove_notify_dbus_object_cb (ESource *source,
1316                                      GParamSpec *pspec,
1317                                      RemoveContext *remove_context)
1318 {
1319 	GDBusObject *dbus_object;
1320 
1321 	dbus_object = e_source_ref_dbus_object (source);
1322 
1323 	/* The GDBusObject will be NULL once the ESourceRegistry
1324 	 * receives an "object-removed" signal for this ESource. */
1325 	if (dbus_object == NULL) {
1326 		GSource *idle_source;
1327 
1328 		idle_source = g_idle_source_new ();
1329 		g_source_set_callback (
1330 			idle_source,
1331 			source_remove_main_loop_quit_cb,
1332 			g_main_loop_ref (remove_context->main_loop),
1333 			(GDestroyNotify) g_main_loop_unref);
1334 		g_source_attach (idle_source, remove_context->main_context);
1335 		g_source_unref (idle_source);
1336 	}
1337 
1338 	g_clear_object (&dbus_object);
1339 }
1340 
1341 static gboolean
source_remove_sync(ESource * source,GCancellable * cancellable,GError ** error)1342 source_remove_sync (ESource *source,
1343                     GCancellable *cancellable,
1344                     GError **error)
1345 {
1346 	EDBusSourceRemovable *dbus_interface = NULL;
1347 	GDBusObject *dbus_object;
1348 	RemoveContext *remove_context;
1349 	gulong notify_dbus_object_id;
1350 	GError *local_error = NULL;
1351 
1352 	dbus_object = e_source_ref_dbus_object (source);
1353 	if (dbus_object != NULL) {
1354 		dbus_interface =
1355 			e_dbus_object_get_source_removable (
1356 			E_DBUS_OBJECT (dbus_object));
1357 		g_object_unref (dbus_object);
1358 	}
1359 
1360 	if (dbus_interface == NULL) {
1361 		g_set_error (
1362 			error, G_IO_ERROR,
1363 			G_IO_ERROR_PERMISSION_DENIED,
1364 			_("Data source “%s” is not removable"),
1365 			e_source_get_display_name (source));
1366 		return FALSE;
1367 	}
1368 
1369 	remove_context = remove_context_new ();
1370 	g_main_context_push_thread_default (remove_context->main_context);
1371 
1372 	notify_dbus_object_id = g_signal_connect (
1373 		source, "notify::dbus-object",
1374 		G_CALLBACK (source_remove_notify_dbus_object_cb),
1375 		remove_context);
1376 
1377 	e_dbus_source_removable_call_remove_sync (
1378 		dbus_interface, cancellable, &local_error);
1379 
1380 	/* Wait for the ESourceRegistry to remove our GDBusObject while
1381 	 * handling an "object-removed" signal from the registry service.
1382 	 * But also set a short timeout to avoid getting deadlocked here. */
1383 	if (local_error == NULL) {
1384 		GSource *timeout_source;
1385 
1386 		timeout_source = g_timeout_source_new_seconds (2);
1387 		g_source_set_callback (
1388 			timeout_source,
1389 			source_remove_main_loop_quit_cb,
1390 			g_main_loop_ref (remove_context->main_loop),
1391 			(GDestroyNotify) g_main_loop_unref);
1392 		g_source_attach (timeout_source, remove_context->main_context);
1393 		g_source_unref (timeout_source);
1394 
1395 		g_main_loop_run (remove_context->main_loop);
1396 	}
1397 
1398 	g_signal_handler_disconnect (source, notify_dbus_object_id);
1399 
1400 	g_main_context_pop_thread_default (remove_context->main_context);
1401 	remove_context_free (remove_context);
1402 
1403 	g_object_unref (dbus_interface);
1404 
1405 	if (local_error != NULL) {
1406 		g_dbus_error_strip_remote_error (local_error);
1407 		g_propagate_error (error, local_error);
1408 		return FALSE;
1409 	}
1410 
1411 	return TRUE;
1412 }
1413 
1414 /* Helper for source_remove() */
1415 static void
source_remove_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1416 source_remove_thread (GSimpleAsyncResult *simple,
1417                       GObject *object,
1418                       GCancellable *cancellable)
1419 {
1420 	GError *local_error = NULL;
1421 
1422 	e_source_remove_sync (E_SOURCE (object), cancellable, &local_error);
1423 
1424 	if (local_error != NULL)
1425 		g_simple_async_result_take_error (simple, local_error);
1426 }
1427 
1428 static void
source_remove(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1429 source_remove (ESource *source,
1430                GCancellable *cancellable,
1431                GAsyncReadyCallback callback,
1432                gpointer user_data)
1433 {
1434 	GSimpleAsyncResult *simple;
1435 
1436 	simple = g_simple_async_result_new (
1437 		G_OBJECT (source), callback, user_data, source_remove);
1438 
1439 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1440 
1441 	g_simple_async_result_run_in_thread (
1442 		simple, source_remove_thread,
1443 		G_PRIORITY_DEFAULT, cancellable);
1444 
1445 	g_object_unref (simple);
1446 }
1447 
1448 static gboolean
source_remove_finish(ESource * source,GAsyncResult * result,GError ** error)1449 source_remove_finish (ESource *source,
1450                       GAsyncResult *result,
1451                       GError **error)
1452 {
1453 	GSimpleAsyncResult *simple;
1454 
1455 	g_return_val_if_fail (
1456 		g_simple_async_result_is_valid (
1457 		result, G_OBJECT (source), source_remove), FALSE);
1458 
1459 	simple = G_SIMPLE_ASYNC_RESULT (result);
1460 
1461 	/* Assume success unless a GError is set. */
1462 	return !g_simple_async_result_propagate_error (simple, error);
1463 }
1464 
1465 static gboolean
source_write_sync(ESource * source,GCancellable * cancellable,GError ** error)1466 source_write_sync (ESource *source,
1467                    GCancellable *cancellable,
1468                    GError **error)
1469 {
1470 	EDBusSourceWritable *dbus_interface = NULL;
1471 	GDBusObject *dbus_object;
1472 	gchar *data;
1473 	GError *local_error = NULL;
1474 
1475 	dbus_object = e_source_ref_dbus_object (source);
1476 	if (dbus_object != NULL) {
1477 		dbus_interface =
1478 			e_dbus_object_get_source_writable (
1479 			E_DBUS_OBJECT (dbus_object));
1480 		g_object_unref (dbus_object);
1481 	}
1482 
1483 	if (dbus_interface == NULL) {
1484 		g_set_error (
1485 			error, G_IO_ERROR,
1486 			G_IO_ERROR_PERMISSION_DENIED,
1487 			_("Data source “%s” is not writable"),
1488 			e_source_get_display_name (source));
1489 		return FALSE;
1490 	}
1491 
1492 	data = e_source_to_string (source, NULL);
1493 
1494 	e_dbus_source_writable_call_write_sync (
1495 		dbus_interface, data, cancellable, &local_error);
1496 
1497 	g_free (data);
1498 
1499 	g_object_unref (dbus_interface);
1500 
1501 	if (local_error != NULL) {
1502 		g_dbus_error_strip_remote_error (local_error);
1503 		g_propagate_error (error, local_error);
1504 		return FALSE;
1505 	}
1506 
1507 	return TRUE;
1508 }
1509 
1510 /* Helper for source_write() */
1511 static void
source_write_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1512 source_write_thread (GSimpleAsyncResult *simple,
1513                      GObject *object,
1514                      GCancellable *cancellable)
1515 {
1516 	GError *local_error = NULL;
1517 
1518 	e_source_write_sync (E_SOURCE (object), cancellable, &local_error);
1519 
1520 	if (local_error != NULL)
1521 		g_simple_async_result_take_error (simple, local_error);
1522 }
1523 
1524 static void
source_write(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1525 source_write (ESource *source,
1526               GCancellable *cancellable,
1527               GAsyncReadyCallback callback,
1528               gpointer user_data)
1529 {
1530 	GSimpleAsyncResult *simple;
1531 
1532 	simple = g_simple_async_result_new (
1533 		G_OBJECT (source), callback, user_data, source_write);
1534 
1535 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1536 
1537 	g_simple_async_result_run_in_thread (
1538 		simple, source_write_thread,
1539 		G_PRIORITY_DEFAULT, cancellable);
1540 
1541 	g_object_unref (simple);
1542 }
1543 
1544 static gboolean
source_write_finish(ESource * source,GAsyncResult * result,GError ** error)1545 source_write_finish (ESource *source,
1546                      GAsyncResult *result,
1547                      GError **error)
1548 {
1549 	GSimpleAsyncResult *simple;
1550 
1551 	g_return_val_if_fail (
1552 		g_simple_async_result_is_valid (
1553 		result, G_OBJECT (source), source_write), FALSE);
1554 
1555 	simple = G_SIMPLE_ASYNC_RESULT (result);
1556 
1557 	/* Assume success unless a GError is set. */
1558 	return !g_simple_async_result_propagate_error (simple, error);
1559 }
1560 
1561 static gboolean
source_remote_create_sync(ESource * source,ESource * scratch_source,GCancellable * cancellable,GError ** error)1562 source_remote_create_sync (ESource *source,
1563                            ESource *scratch_source,
1564                            GCancellable *cancellable,
1565                            GError **error)
1566 {
1567 	EDBusSourceRemoteCreatable *dbus_interface = NULL;
1568 	GDBusObject *dbus_object;
1569 	gchar *uid, *data;
1570 	GError *local_error = NULL;
1571 
1572 	dbus_object = e_source_ref_dbus_object (source);
1573 	if (dbus_object != NULL) {
1574 		dbus_interface =
1575 			e_dbus_object_get_source_remote_creatable (
1576 			E_DBUS_OBJECT (dbus_object));
1577 		g_object_unref (dbus_object);
1578 	}
1579 
1580 	if (dbus_interface == NULL) {
1581 		g_set_error (
1582 			error, G_IO_ERROR,
1583 			G_IO_ERROR_NOT_SUPPORTED,
1584 			_("Data source “%s” does not "
1585 			"support creating remote resources"),
1586 			e_source_get_display_name (source));
1587 		return FALSE;
1588 	}
1589 
1590 	uid = e_source_dup_uid (scratch_source);
1591 	data = e_source_to_string (scratch_source, NULL);
1592 
1593 	e_dbus_source_remote_creatable_call_create_sync (
1594 		dbus_interface, uid, data, cancellable, &local_error);
1595 
1596 	g_free (data);
1597 	g_free (uid);
1598 
1599 	g_object_unref (dbus_interface);
1600 
1601 	if (local_error != NULL) {
1602 		g_dbus_error_strip_remote_error (local_error);
1603 		g_propagate_error (error, local_error);
1604 		return FALSE;
1605 	}
1606 
1607 	return TRUE;
1608 }
1609 
1610 /* Helper for source_remote_create() */
1611 static void
source_remote_create_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1612 source_remote_create_thread (GSimpleAsyncResult *simple,
1613                              GObject *object,
1614                              GCancellable *cancellable)
1615 {
1616 	AsyncContext *async_context;
1617 	GError *local_error = NULL;
1618 
1619 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
1620 
1621 	e_source_remote_create_sync (
1622 		E_SOURCE (object),
1623 		async_context->scratch_source,
1624 		cancellable, &local_error);
1625 
1626 	if (local_error != NULL)
1627 		g_simple_async_result_take_error (simple, local_error);
1628 }
1629 
1630 static void
source_remote_create(ESource * source,ESource * scratch_source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1631 source_remote_create (ESource *source,
1632                       ESource *scratch_source,
1633                       GCancellable *cancellable,
1634                       GAsyncReadyCallback callback,
1635                       gpointer user_data)
1636 {
1637 	GSimpleAsyncResult *simple;
1638 	AsyncContext *async_context;
1639 
1640 	async_context = g_slice_new0 (AsyncContext);
1641 	async_context->scratch_source = g_object_ref (scratch_source);
1642 
1643 	simple = g_simple_async_result_new (
1644 		G_OBJECT (source), callback,
1645 		user_data, source_remote_create);
1646 
1647 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1648 
1649 	g_simple_async_result_set_op_res_gpointer (
1650 		simple, async_context, (GDestroyNotify) async_context_free);
1651 
1652 	g_simple_async_result_run_in_thread (
1653 		simple, source_remote_create_thread,
1654 		G_PRIORITY_DEFAULT, cancellable);
1655 
1656 	g_object_unref (simple);
1657 }
1658 
1659 static gboolean
source_remote_create_finish(ESource * source,GAsyncResult * result,GError ** error)1660 source_remote_create_finish (ESource *source,
1661                              GAsyncResult *result,
1662                              GError **error)
1663 {
1664 	GSimpleAsyncResult *simple;
1665 
1666 	g_return_val_if_fail (
1667 		g_simple_async_result_is_valid (
1668 		result, G_OBJECT (source), source_remote_create), FALSE);
1669 
1670 	simple = G_SIMPLE_ASYNC_RESULT (result);
1671 
1672 	/* Assume success unless a GError is set. */
1673 	return !g_simple_async_result_propagate_error (simple, error);
1674 }
1675 
1676 static gboolean
source_remote_delete_sync(ESource * source,GCancellable * cancellable,GError ** error)1677 source_remote_delete_sync (ESource *source,
1678                            GCancellable *cancellable,
1679                            GError **error)
1680 {
1681 	EDBusSourceRemoteDeletable *dbus_interface = NULL;
1682 	GDBusObject *dbus_object;
1683 	GError *local_error = NULL;
1684 
1685 	dbus_object = e_source_ref_dbus_object (source);
1686 	if (dbus_object != NULL) {
1687 		dbus_interface =
1688 			e_dbus_object_get_source_remote_deletable (
1689 			E_DBUS_OBJECT (dbus_object));
1690 		g_object_unref (dbus_object);
1691 	}
1692 
1693 	if (dbus_interface == NULL) {
1694 		g_set_error (
1695 			error, G_IO_ERROR,
1696 			G_IO_ERROR_NOT_SUPPORTED,
1697 			_("Data source “%s” does not "
1698 			"support deleting remote resources"),
1699 			e_source_get_display_name (source));
1700 		return FALSE;
1701 	}
1702 
1703 	e_dbus_source_remote_deletable_call_delete_sync (
1704 		dbus_interface, cancellable, &local_error);
1705 
1706 	g_object_unref (dbus_interface);
1707 
1708 	if (local_error != NULL) {
1709 		g_dbus_error_strip_remote_error (local_error);
1710 		g_propagate_error (error, local_error);
1711 		return FALSE;
1712 	}
1713 
1714 	return TRUE;
1715 }
1716 
1717 /* Helper for source_remote_delete() */
1718 static void
source_remote_delete_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1719 source_remote_delete_thread (GSimpleAsyncResult *simple,
1720                              GObject *object,
1721                              GCancellable *cancellable)
1722 {
1723 	GError *local_error = NULL;
1724 
1725 	e_source_remote_delete_sync (
1726 		E_SOURCE (object), cancellable, &local_error);
1727 
1728 	if (local_error != NULL)
1729 		g_simple_async_result_take_error (simple, local_error);
1730 }
1731 
1732 static void
source_remote_delete(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1733 source_remote_delete (ESource *source,
1734                       GCancellable *cancellable,
1735                       GAsyncReadyCallback callback,
1736                       gpointer user_data)
1737 {
1738 	GSimpleAsyncResult *simple;
1739 
1740 	simple = g_simple_async_result_new (
1741 		G_OBJECT (source), callback,
1742 		user_data, source_remote_delete);
1743 
1744 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1745 
1746 	g_simple_async_result_run_in_thread (
1747 		simple, source_remote_delete_thread,
1748 		G_PRIORITY_DEFAULT, cancellable);
1749 
1750 	g_object_unref (simple);
1751 }
1752 
1753 static gboolean
source_remote_delete_finish(ESource * source,GAsyncResult * result,GError ** error)1754 source_remote_delete_finish (ESource *source,
1755                              GAsyncResult *result,
1756                              GError **error)
1757 {
1758 	GSimpleAsyncResult *simple;
1759 
1760 	g_return_val_if_fail (
1761 		g_simple_async_result_is_valid (
1762 		result, G_OBJECT (source), source_remote_delete), FALSE);
1763 
1764 	simple = G_SIMPLE_ASYNC_RESULT (result);
1765 
1766 	/* Assume success unless a GError is set. */
1767 	return !g_simple_async_result_propagate_error (simple, error);
1768 }
1769 
1770 static gboolean
source_get_oauth2_access_token_sync(ESource * source,GCancellable * cancellable,gchar ** out_access_token,gint * out_expires_in,GError ** error)1771 source_get_oauth2_access_token_sync (ESource *source,
1772                                      GCancellable *cancellable,
1773                                      gchar **out_access_token,
1774                                      gint *out_expires_in,
1775                                      GError **error)
1776 {
1777 	EDBusSourceOAuth2Support *dbus_interface = NULL;
1778 	GDBusObject *dbus_object;
1779 	GError *local_error = NULL;
1780 
1781 	dbus_object = e_source_ref_dbus_object (source);
1782 	if (dbus_object != NULL) {
1783 		dbus_interface =
1784 			e_dbus_object_get_source_oauth2_support (
1785 			E_DBUS_OBJECT (dbus_object));
1786 		g_object_unref (dbus_object);
1787 	}
1788 
1789 	if (!dbus_interface) {
1790 		ESourceRegistry *registry;
1791 
1792 		registry = e_source_registry_new_sync (NULL, NULL);
1793 
1794 		if (registry) {
1795 			EOAuth2Services *oauth2_services;
1796 			EOAuth2Service *service = NULL;
1797 
1798 			oauth2_services = e_source_registry_get_oauth2_services (registry);
1799 
1800 			if (oauth2_services)
1801 				service = e_oauth2_services_find (oauth2_services, source);
1802 
1803 			if (service) {
1804 				EOAuth2ServiceRefSourceFunc ref_source;
1805 				gboolean success;
1806 
1807 				ref_source = (EOAuth2ServiceRefSourceFunc) e_source_registry_ref_source;
1808 
1809 				success = e_oauth2_service_get_access_token_sync (service, source, ref_source, registry,
1810 					out_access_token, out_expires_in, cancellable, error);
1811 
1812 				g_clear_object (&service);
1813 				g_object_unref (registry);
1814 
1815 				return success;
1816 			}
1817 
1818 			g_object_unref (registry);
1819 		}
1820 	}
1821 
1822 	if (dbus_interface == NULL) {
1823 		g_set_error (
1824 			error, G_IO_ERROR,
1825 			G_IO_ERROR_NOT_SUPPORTED,
1826 			_("Data source “%s” does not "
1827 			"support OAuth 2.0 authentication"),
1828 			e_source_get_display_name (source));
1829 		return FALSE;
1830 	}
1831 
1832 	e_dbus_source_oauth2_support_call_get_access_token_sync (
1833 		dbus_interface, out_access_token,
1834 		out_expires_in, cancellable, &local_error);
1835 
1836 	g_object_unref (dbus_interface);
1837 
1838 	if (local_error != NULL) {
1839 		g_dbus_error_strip_remote_error (local_error);
1840 		g_propagate_error (error, local_error);
1841 		return FALSE;
1842 	}
1843 
1844 	return TRUE;
1845 }
1846 
1847 /* Helper for source_get_oauth2_access_token() */
1848 static void
source_get_oauth2_access_token_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1849 source_get_oauth2_access_token_thread (GSimpleAsyncResult *simple,
1850                                        GObject *object,
1851                                        GCancellable *cancellable)
1852 {
1853 	AsyncContext *async_context;
1854 	GError *local_error = NULL;
1855 
1856 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
1857 
1858 	e_source_get_oauth2_access_token_sync (
1859 		E_SOURCE (object), cancellable,
1860 		&async_context->access_token,
1861 		&async_context->expires_in,
1862 		&local_error);
1863 
1864 	if (local_error != NULL)
1865 		g_simple_async_result_take_error (simple, local_error);
1866 }
1867 
1868 static void
source_get_oauth2_access_token(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1869 source_get_oauth2_access_token (ESource *source,
1870                                 GCancellable *cancellable,
1871                                 GAsyncReadyCallback callback,
1872                                 gpointer user_data)
1873 {
1874 	GSimpleAsyncResult *simple;
1875 	AsyncContext *async_context;
1876 
1877 	async_context = g_slice_new0 (AsyncContext);
1878 
1879 	simple = g_simple_async_result_new (
1880 		G_OBJECT (source), callback, user_data,
1881 		source_get_oauth2_access_token);
1882 
1883 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1884 
1885 	g_simple_async_result_set_op_res_gpointer (
1886 		simple, async_context, (GDestroyNotify) async_context_free);
1887 
1888 	g_simple_async_result_run_in_thread (
1889 		simple, source_get_oauth2_access_token_thread,
1890 		G_PRIORITY_DEFAULT, cancellable);
1891 
1892 	g_object_unref (simple);
1893 }
1894 
1895 static gboolean
source_get_oauth2_access_token_finish(ESource * source,GAsyncResult * result,gchar ** out_access_token,gint * out_expires_in,GError ** error)1896 source_get_oauth2_access_token_finish (ESource *source,
1897                                        GAsyncResult *result,
1898                                        gchar **out_access_token,
1899                                        gint *out_expires_in,
1900                                        GError **error)
1901 {
1902 	GSimpleAsyncResult *simple;
1903 	AsyncContext *async_context;
1904 
1905 	g_return_val_if_fail (
1906 		g_simple_async_result_is_valid (
1907 		result, G_OBJECT (source),
1908 		source_get_oauth2_access_token), FALSE);
1909 
1910 	simple = G_SIMPLE_ASYNC_RESULT (result);
1911 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
1912 
1913 	if (g_simple_async_result_propagate_error (simple, error))
1914 		return FALSE;
1915 
1916 	g_return_val_if_fail (async_context->access_token != NULL, FALSE);
1917 
1918 	if (out_access_token != NULL) {
1919 		*out_access_token = async_context->access_token;
1920 		async_context->access_token = NULL;
1921 	}
1922 
1923 	if (out_expires_in != NULL)
1924 		*out_expires_in = async_context->expires_in;
1925 
1926 	return TRUE;
1927 }
1928 
1929 
1930 static gboolean
source_invoke_credentials_required_impl(ESource * source,gpointer dbus_source,const gchar * arg_reason,const gchar * arg_certificate_pem,const gchar * arg_certificate_errors,const gchar * arg_dbus_error_name,const gchar * arg_dbus_error_message,GCancellable * cancellable,GError ** error)1931 source_invoke_credentials_required_impl (ESource *source,
1932 					 gpointer dbus_source, /* EDBusSource * */
1933 					 const gchar *arg_reason,
1934 					 const gchar *arg_certificate_pem,
1935 					 const gchar *arg_certificate_errors,
1936 					 const gchar *arg_dbus_error_name,
1937 					 const gchar *arg_dbus_error_message,
1938 					 GCancellable *cancellable,
1939 					 GError **error)
1940 {
1941 	g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1942 
1943 	return e_dbus_source_call_invoke_credentials_required_sync (dbus_source,
1944 		arg_reason ? arg_reason : "",
1945 		arg_certificate_pem ? arg_certificate_pem : "",
1946 		arg_certificate_errors ? arg_certificate_errors : "",
1947 		arg_dbus_error_name ? arg_dbus_error_name : "",
1948 		arg_dbus_error_message ? arg_dbus_error_message : "",
1949 		cancellable, error);
1950 }
1951 
1952 static gboolean
source_invoke_authenticate_impl(ESource * source,gpointer dbus_source,const gchar * const * arg_credentials,GCancellable * cancellable,GError ** error)1953 source_invoke_authenticate_impl (ESource *source,
1954 				 gpointer dbus_source, /* EDBusSource * */
1955 				 const gchar * const *arg_credentials,
1956 				 GCancellable *cancellable,
1957 				 GError **error)
1958 {
1959 	g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1960 
1961 	return e_dbus_source_call_invoke_authenticate_sync (dbus_source, arg_credentials, cancellable, error);
1962 }
1963 
1964 static gboolean
source_unset_last_credentials_required_arguments_impl(ESource * source,GCancellable * cancellable,GError ** error)1965 source_unset_last_credentials_required_arguments_impl (ESource *source,
1966 						       GCancellable *cancellable,
1967 						       GError **error)
1968 {
1969 	GDBusObject *dbus_object;
1970 	EDBusSource *dbus_source = NULL;
1971 	gboolean success;
1972 	GError *local_error = NULL;
1973 
1974 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1975 
1976 	dbus_object = e_source_ref_dbus_object (source);
1977 	if (dbus_object != NULL) {
1978 		dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1979 		g_object_unref (dbus_object);
1980 	}
1981 
1982 	if (!dbus_source)
1983 		return FALSE;
1984 
1985 	success = e_dbus_source_call_unset_last_credentials_required_arguments_sync (dbus_source, cancellable, &local_error);
1986 
1987 	g_object_unref (dbus_source);
1988 
1989 	if (local_error != NULL) {
1990 		g_dbus_error_strip_remote_error (local_error);
1991 		g_propagate_error (error, local_error);
1992 		return FALSE;
1993 	}
1994 
1995 	return success;
1996 }
1997 
1998 static void
source_connect_dbus_source(ESource * source)1999 source_connect_dbus_source (ESource *source)
2000 {
2001 	EDBusObject *dbus_object;
2002 	EDBusSource *dbus_source;
2003 
2004 	g_return_if_fail (E_IS_SOURCE (source));
2005 
2006 	if (!source->priv->dbus_object)
2007 		return;
2008 
2009 	dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
2010 
2011 	/* An EDBusObject lacking an EDBusSource
2012 	 * interface indicates a programmer error. */
2013 	dbus_source = e_dbus_object_get_source (dbus_object);
2014 	g_return_if_fail (E_DBUS_IS_SOURCE (dbus_source));
2015 
2016 	g_signal_connect_object (
2017 		dbus_source, "notify::data",
2018 		G_CALLBACK (source_notify_dbus_data_cb), source, 0);
2019 	g_signal_connect_object (
2020 		dbus_source, "notify::connection-status",
2021 		G_CALLBACK (source_notify_dbus_connection_status_cb), source, 0);
2022 	g_signal_connect_object (
2023 		dbus_source, "credentials-required",
2024 		G_CALLBACK (source_dbus_credentials_required_cb), source, 0);
2025 	g_signal_connect_object (
2026 		dbus_source, "authenticate",
2027 		G_CALLBACK (source_dbus_authenticate_cb), source, 0);
2028 
2029 	g_clear_object (&dbus_source);
2030 }
2031 
2032 static gboolean
source_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)2033 source_initable_init (GInitable *initable,
2034                       GCancellable *cancellable,
2035                       GError **error)
2036 {
2037 	ESource *source;
2038 	gboolean success = TRUE;
2039 
2040 	source = E_SOURCE (initable);
2041 
2042 	/* The D-Bus object has the unique identifier (UID). */
2043 	if (source->priv->dbus_object != NULL) {
2044 		EDBusObject *dbus_object;
2045 		EDBusSource *dbus_source;
2046 
2047 		dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
2048 
2049 		/* An EDBusObject lacking an EDBusSource
2050 		 * interface indicates a programmer error. */
2051 		dbus_source = e_dbus_object_get_source (dbus_object);
2052 		g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
2053 
2054 		/* The UID never changes, so we can cache a copy.
2055 		 *
2056 		 * XXX Note, EServerSideSource may have already set this
2057 		 *     by way of the "uid" construct-only property, hence
2058 		 *     the g_free() call.  Not a problem, we'll just free
2059 		 *     our UID string and set it to the same value again. */
2060 		g_free (source->priv->uid);
2061 		source->priv->uid = e_dbus_source_dup_uid (dbus_source);
2062 
2063 		source_update_connection_status_internal (source, dbus_source);
2064 		source_connect_dbus_source (source);
2065 
2066 		success = source_parse_dbus_data (source, error);
2067 
2068 		g_object_unref (dbus_source);
2069 
2070 	/* No D-Bus object implies we're configuring a new source,
2071 	 * so generate a new unique identifier (UID) unless one was
2072 	 * explicitly provided through e_source_new_with_uid(). */
2073 	} else if (source->priv->uid == NULL) {
2074 		source->priv->uid = e_util_generate_uid ();
2075 	}
2076 
2077 	source->priv->initialized = TRUE;
2078 
2079 	return success;
2080 }
2081 
2082 static gboolean
source_proxy_resolver_is_supported(GProxyResolver * resolver)2083 source_proxy_resolver_is_supported (GProxyResolver *resolver)
2084 {
2085 	return e_source_has_extension (
2086 		E_SOURCE (resolver), E_SOURCE_EXTENSION_PROXY);
2087 }
2088 
2089 static gchar **
source_proxy_resolver_lookup(GProxyResolver * resolver,const gchar * uri,GCancellable * cancellable,GError ** error)2090 source_proxy_resolver_lookup (GProxyResolver *resolver,
2091                               const gchar *uri,
2092                               GCancellable *cancellable,
2093                               GError **error)
2094 {
2095 	return e_source_proxy_lookup_sync (
2096 		E_SOURCE (resolver), uri, cancellable, error);
2097 }
2098 
2099 /* Helper for source_proxy_resolver_lookup_async() */
2100 static void
source_proxy_resolver_lookup_ready_cb(GObject * object,GAsyncResult * result,gpointer user_data)2101 source_proxy_resolver_lookup_ready_cb (GObject *object,
2102                                        GAsyncResult *result,
2103                                        gpointer user_data)
2104 {
2105 	GSimpleAsyncResult *simple;
2106 	gchar **proxies;
2107 	GError *local_error = NULL;
2108 
2109 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
2110 
2111 	proxies = e_source_proxy_lookup_finish (
2112 		E_SOURCE (object), result, &local_error);
2113 
2114 	/* Sanity check. */
2115 	g_return_if_fail (
2116 		((proxies != NULL) && (local_error == NULL)) ||
2117 		((proxies == NULL) && (local_error != NULL)));
2118 
2119 	if (proxies != NULL) {
2120 		g_simple_async_result_set_op_res_gpointer (
2121 			simple, proxies, (GDestroyNotify) g_strfreev);
2122 	} else {
2123 		g_simple_async_result_take_error (simple, local_error);
2124 	}
2125 
2126 	g_simple_async_result_complete (simple);
2127 
2128 	g_object_unref (simple);
2129 }
2130 
2131 static void
source_proxy_resolver_lookup_async(GProxyResolver * resolver,const gchar * uri,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2132 source_proxy_resolver_lookup_async (GProxyResolver *resolver,
2133                                     const gchar *uri,
2134                                     GCancellable *cancellable,
2135                                     GAsyncReadyCallback callback,
2136                                     gpointer user_data)
2137 {
2138 	GSimpleAsyncResult *simple;
2139 
2140 	simple = g_simple_async_result_new (
2141 		G_OBJECT (resolver), callback, user_data,
2142 		source_proxy_resolver_lookup_async);
2143 
2144 	g_simple_async_result_set_check_cancellable (simple, cancellable);
2145 
2146 	e_source_proxy_lookup (
2147 		E_SOURCE (resolver), uri, cancellable,
2148 		source_proxy_resolver_lookup_ready_cb,
2149 		g_object_ref (simple));
2150 
2151 	g_object_unref (simple);
2152 }
2153 
2154 static gchar **
source_proxy_resolver_lookup_finish(GProxyResolver * resolver,GAsyncResult * result,GError ** error)2155 source_proxy_resolver_lookup_finish (GProxyResolver *resolver,
2156                                      GAsyncResult *result,
2157                                      GError **error)
2158 {
2159 	GSimpleAsyncResult *simple;
2160 	gchar **proxies;
2161 
2162 	g_return_val_if_fail (
2163 		g_simple_async_result_is_valid (
2164 		result, G_OBJECT (resolver),
2165 		source_proxy_resolver_lookup_async), NULL);
2166 
2167 	simple = G_SIMPLE_ASYNC_RESULT (result);
2168 
2169 	if (g_simple_async_result_propagate_error (simple, error))
2170 		return NULL;
2171 
2172 	proxies = g_simple_async_result_get_op_res_gpointer (simple);
2173 
2174 	return g_strdupv (proxies);
2175 }
2176 
2177 static void
e_source_class_init(ESourceClass * class)2178 e_source_class_init (ESourceClass *class)
2179 {
2180 	GObjectClass *object_class;
2181 
2182 	object_class = G_OBJECT_CLASS (class);
2183 	object_class->set_property = source_set_property;
2184 	object_class->get_property = source_get_property;
2185 	object_class->dispose = source_dispose;
2186 	object_class->finalize = source_finalize;
2187 	object_class->notify = source_notify;
2188 
2189 	class->remove_sync = source_remove_sync;
2190 	class->remove = source_remove;
2191 	class->remove_finish = source_remove_finish;
2192 	class->write_sync = source_write_sync;
2193 	class->write = source_write;
2194 	class->write_finish = source_write_finish;
2195 	class->remote_create_sync = source_remote_create_sync;
2196 	class->remote_create = source_remote_create;
2197 	class->remote_create_finish = source_remote_create_finish;
2198 	class->remote_delete_sync = source_remote_delete_sync;
2199 	class->remote_delete = source_remote_delete;
2200 	class->remote_delete_finish = source_remote_delete_finish;
2201 	class->get_oauth2_access_token_sync = source_get_oauth2_access_token_sync;
2202 	class->get_oauth2_access_token = source_get_oauth2_access_token;
2203 	class->get_oauth2_access_token_finish = source_get_oauth2_access_token_finish;
2204 	class->invoke_credentials_required_impl = source_invoke_credentials_required_impl;
2205 	class->invoke_authenticate_impl = source_invoke_authenticate_impl;
2206 	class->unset_last_credentials_required_arguments_impl = source_unset_last_credentials_required_arguments_impl;
2207 
2208 	g_object_class_install_property (
2209 		object_class,
2210 		PROP_DBUS_OBJECT,
2211 		g_param_spec_object (
2212 			"dbus-object",
2213 			"D-Bus Object",
2214 			"The D-Bus object for the data source",
2215 			E_DBUS_TYPE_OBJECT,
2216 			G_PARAM_READWRITE |
2217 			G_PARAM_CONSTRUCT_ONLY |
2218 			G_PARAM_STATIC_STRINGS));
2219 
2220 	g_object_class_install_property (
2221 		object_class,
2222 		PROP_DISPLAY_NAME,
2223 		g_param_spec_string (
2224 			"display-name",
2225 			"Display Name",
2226 			"The human-readable name of the data source",
2227 			_("Unnamed"),
2228 			G_PARAM_READWRITE |
2229 			G_PARAM_CONSTRUCT |
2230 			G_PARAM_EXPLICIT_NOTIFY |
2231 			G_PARAM_STATIC_STRINGS |
2232 			E_SOURCE_PARAM_SETTING));
2233 
2234 	g_object_class_install_property (
2235 		object_class,
2236 		PROP_ENABLED,
2237 		g_param_spec_boolean (
2238 			"enabled",
2239 			"Enabled",
2240 			"Whether the data source is enabled",
2241 			TRUE,
2242 			G_PARAM_READWRITE |
2243 			G_PARAM_CONSTRUCT |
2244 			G_PARAM_EXPLICIT_NOTIFY |
2245 			G_PARAM_STATIC_STRINGS |
2246 			E_SOURCE_PARAM_SETTING));
2247 
2248 	g_object_class_install_property (
2249 		object_class,
2250 		PROP_MAIN_CONTEXT,
2251 		g_param_spec_boxed (
2252 			"main-context",
2253 			"Main Context",
2254 			"The main loop context on "
2255 			"which to attach event sources",
2256 			G_TYPE_MAIN_CONTEXT,
2257 			G_PARAM_READWRITE |
2258 			G_PARAM_CONSTRUCT_ONLY |
2259 			G_PARAM_STATIC_STRINGS));
2260 
2261 	g_object_class_install_property (
2262 		object_class,
2263 		PROP_PARENT,
2264 		g_param_spec_string (
2265 			"parent",
2266 			"Parent",
2267 			"The unique identity of the parent data source",
2268 			NULL,
2269 			G_PARAM_READWRITE |
2270 			G_PARAM_EXPLICIT_NOTIFY |
2271 			G_PARAM_STATIC_STRINGS |
2272 			E_SOURCE_PARAM_SETTING));
2273 
2274 	g_object_class_install_property (
2275 		object_class,
2276 		PROP_REMOTE_CREATABLE,
2277 		g_param_spec_boolean (
2278 			"remote-creatable",
2279 			"Remote Creatable",
2280 			"Whether the data source "
2281 			"can create remote resources",
2282 			FALSE,
2283 			G_PARAM_READABLE |
2284 			G_PARAM_STATIC_STRINGS));
2285 
2286 	g_object_class_install_property (
2287 		object_class,
2288 		PROP_REMOTE_DELETABLE,
2289 		g_param_spec_boolean (
2290 			"remote-deletable",
2291 			"Remote Deletable",
2292 			"Whether the data source "
2293 			"can delete remote resources",
2294 			FALSE,
2295 			G_PARAM_READABLE |
2296 			G_PARAM_STATIC_STRINGS));
2297 
2298 	g_object_class_install_property (
2299 		object_class,
2300 		PROP_REMOVABLE,
2301 		g_param_spec_boolean (
2302 			"removable",
2303 			"Removable",
2304 			"Whether the data source is removable",
2305 			FALSE,
2306 			G_PARAM_READABLE |
2307 			G_PARAM_STATIC_STRINGS));
2308 
2309 	g_object_class_install_property (
2310 		object_class,
2311 		PROP_UID,
2312 		g_param_spec_string (
2313 			"uid",
2314 			"UID",
2315 			"The unique identity of the data source",
2316 			NULL,
2317 			G_PARAM_READWRITE |
2318 			G_PARAM_CONSTRUCT_ONLY |
2319 			G_PARAM_STATIC_STRINGS));
2320 
2321 	g_object_class_install_property (
2322 		object_class,
2323 		PROP_WRITABLE,
2324 		g_param_spec_boolean (
2325 			"writable",
2326 			"Writable",
2327 			"Whether the data source is writable",
2328 			FALSE,
2329 			G_PARAM_READABLE |
2330 			G_PARAM_STATIC_STRINGS));
2331 
2332 	g_object_class_install_property (
2333 		object_class,
2334 		PROP_CONNECTION_STATUS,
2335 		g_param_spec_enum (
2336 			"connection-status",
2337 			"Connection Status",
2338 			"Connection status of the source",
2339 			E_TYPE_SOURCE_CONNECTION_STATUS,
2340 			E_SOURCE_CONNECTION_STATUS_DISCONNECTED,
2341 			G_PARAM_READABLE |
2342 			G_PARAM_STATIC_STRINGS));
2343 
2344 	/**
2345 	 * ESource::changed:
2346 	 * @source: the #ESource that received the signal
2347 	 *
2348 	 * The ::changed signal is emitted when a property in @source or
2349 	 * one of its extension objects changes.  A common use for this
2350 	 * signal is to notify a #GtkTreeModel containing data collected
2351 	 * from #ESource<!-- -->s that it needs to update a row.
2352 	 **/
2353 	signals[CHANGED] = g_signal_new (
2354 		"changed",
2355 		G_TYPE_FROM_CLASS (class),
2356 		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2357 		G_STRUCT_OFFSET (ESourceClass, changed),
2358 		NULL, NULL, NULL,
2359 		G_TYPE_NONE, 0);
2360 
2361 	/**
2362 	 * ESource::credentials-required:
2363 	 * @source: the #ESource that received the signal
2364 	 * @reason: an #ESourceCredentialsReason indicating why the credentials are requested
2365 	 * @certificate_pem: PEM-encoded secure connection certificate for failed SSL/TLS checks
2366 	 * @certificate_errors: what failed with the SSL/TLS certificate
2367 	 * @error: a text description of the error, if any
2368 	 *
2369 	 * The ::credentials-required signal is emitted when the @source
2370 	 * requires credentials to connect to (possibly remote)
2371 	 * data store. The credentials can be passed to the backend using
2372 	 * e_source_invoke_authenticate() function.
2373 	 **/
2374 	signals[CREDENTIALS_REQUIRED] = g_signal_new (
2375 		"credentials-required",
2376 		G_TYPE_FROM_CLASS (class),
2377 		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2378 		G_STRUCT_OFFSET (ESourceClass, credentials_required),
2379 		NULL, NULL, NULL,
2380 		G_TYPE_NONE, 4,
2381 		E_TYPE_SOURCE_CREDENTIALS_REASON,
2382 		G_TYPE_STRING,
2383 		G_TYPE_TLS_CERTIFICATE_FLAGS,
2384 		G_TYPE_ERROR);
2385 
2386 	/**
2387 	 * ESource::authenticate
2388 	 * @source: the #ESource that received the signal
2389 	 * @credentials: an #ENamedParameters with provided credentials
2390 	 *
2391 	 * Let's the backend know provided credentials to use to login
2392 	 * to (possibly remote) data store.
2393 	 **/
2394 	signals[AUTHENTICATE] = g_signal_new (
2395 		"authenticate",
2396 		G_TYPE_FROM_CLASS (class),
2397 		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
2398 		G_STRUCT_OFFSET (ESourceClass, authenticate),
2399 		NULL, NULL, NULL,
2400 		G_TYPE_NONE, 1, E_TYPE_NAMED_PARAMETERS);
2401 
2402 	/* Register built-in ESourceExtension types. */
2403 	g_type_ensure (E_TYPE_SOURCE_ADDRESS_BOOK);
2404 	g_type_ensure (E_TYPE_SOURCE_ALARMS);
2405 	g_type_ensure (E_TYPE_SOURCE_AUTHENTICATION);
2406 	g_type_ensure (E_TYPE_SOURCE_AUTOCOMPLETE);
2407 	g_type_ensure (E_TYPE_SOURCE_AUTOCONFIG);
2408 	g_type_ensure (E_TYPE_SOURCE_CALENDAR);
2409 	g_type_ensure (E_TYPE_SOURCE_COLLECTION);
2410 	g_type_ensure (E_TYPE_SOURCE_CONTACTS);
2411 	g_type_ensure (E_TYPE_SOURCE_GOA);
2412 	g_type_ensure (E_TYPE_SOURCE_LDAP);
2413 	g_type_ensure (E_TYPE_SOURCE_LOCAL);
2414 	g_type_ensure (E_TYPE_SOURCE_MAIL_ACCOUNT);
2415 	g_type_ensure (E_TYPE_SOURCE_MAIL_COMPOSITION);
2416 	g_type_ensure (E_TYPE_SOURCE_MAIL_IDENTITY);
2417 	g_type_ensure (E_TYPE_SOURCE_MAIL_SIGNATURE);
2418 	g_type_ensure (E_TYPE_SOURCE_MAIL_SUBMISSION);
2419 	g_type_ensure (E_TYPE_SOURCE_MAIL_TRANSPORT);
2420 	g_type_ensure (E_TYPE_SOURCE_MDN);
2421 	g_type_ensure (E_TYPE_SOURCE_MEMO_LIST);
2422 	g_type_ensure (E_TYPE_SOURCE_OFFLINE);
2423 	g_type_ensure (E_TYPE_SOURCE_OPENPGP);
2424 	g_type_ensure (E_TYPE_SOURCE_PROXY);
2425 	g_type_ensure (E_TYPE_SOURCE_REFRESH);
2426 	g_type_ensure (E_TYPE_SOURCE_RESOURCE);
2427 	g_type_ensure (E_TYPE_SOURCE_REVISION_GUARDS);
2428 	g_type_ensure (E_TYPE_SOURCE_SECURITY);
2429 	g_type_ensure (E_TYPE_SOURCE_SELECTABLE);
2430 	g_type_ensure (E_TYPE_SOURCE_SMIME);
2431 	g_type_ensure (E_TYPE_SOURCE_TASK_LIST);
2432 	g_type_ensure (E_TYPE_SOURCE_UOA);
2433 	g_type_ensure (E_TYPE_SOURCE_WEATHER);
2434 	g_type_ensure (E_TYPE_SOURCE_WEBDAV);
2435 }
2436 
2437 static void
e_source_initable_init(GInitableIface * iface)2438 e_source_initable_init (GInitableIface *iface)
2439 {
2440 	iface->init = source_initable_init;
2441 }
2442 
2443 static void
e_source_proxy_resolver_init(GProxyResolverInterface * iface)2444 e_source_proxy_resolver_init (GProxyResolverInterface *iface)
2445 {
2446 	iface->is_supported = source_proxy_resolver_is_supported;
2447 	iface->lookup = source_proxy_resolver_lookup;
2448 	iface->lookup_async = source_proxy_resolver_lookup_async;
2449 	iface->lookup_finish = source_proxy_resolver_lookup_finish;
2450 }
2451 
2452 static void
e_source_init(ESource * source)2453 e_source_init (ESource *source)
2454 {
2455 	GHashTable *extensions;
2456 
2457 	/* Don't do this as part of class initialization because it
2458 	 * loads Camel modules and can screw up introspection, which
2459 	 * occurs at compile-time before Camel modules are installed. */
2460 	e_source_camel_register_types ();
2461 
2462 	extensions = g_hash_table_new_full (
2463 		(GHashFunc) g_str_hash,
2464 		(GEqualFunc) g_str_equal,
2465 		(GDestroyNotify) g_free,
2466 		(GDestroyNotify) g_object_unref);
2467 
2468 	source->priv = e_source_get_instance_private (source);
2469 	g_mutex_init (&source->priv->changed_lock);
2470 	g_mutex_init (&source->priv->connection_status_change_lock);
2471 	g_mutex_init (&source->priv->property_lock);
2472 	source->priv->key_file = g_key_file_new ();
2473 	source->priv->extensions = extensions;
2474 	source->priv->connection_status = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
2475 
2476 	g_rec_mutex_init (&source->priv->lock);
2477 }
2478 
2479 void
__e_source_private_replace_dbus_object(ESource * source,GDBusObject * dbus_object)2480 __e_source_private_replace_dbus_object (ESource *source,
2481                                         GDBusObject *dbus_object)
2482 {
2483 	/* XXX This function is only ever called by ESourceRegistry
2484 	 *     either when the registry service reported an ESource
2485 	 *     removal, or while recovering from a registry service
2486 	 *     restart.  In the first case the GDBusObject is NULL,
2487 	 *     in the second case the GDBusObject is an equivalent
2488 	 *     proxy for the newly-started registry service. */
2489 
2490 	g_return_if_fail (E_IS_SOURCE (source));
2491 
2492 	if (dbus_object != NULL) {
2493 		g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
2494 		dbus_object = g_object_ref (dbus_object);
2495 	}
2496 
2497 	g_mutex_lock (&source->priv->property_lock);
2498 
2499 	if (source->priv->dbus_object) {
2500 		EDBusSource *dbus_source;
2501 
2502 		dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (source->priv->dbus_object));
2503 
2504 		if (dbus_source) {
2505 			g_signal_handlers_disconnect_by_data (dbus_source, source),
2506 			g_object_unref (dbus_source);
2507 		}
2508 	}
2509 
2510 	g_clear_object (&source->priv->dbus_object);
2511 	source->priv->dbus_object = dbus_object;
2512 
2513 	g_mutex_unlock (&source->priv->property_lock);
2514 
2515 	source_connect_dbus_source (source);
2516 	source_update_connection_status (source);
2517 
2518 	g_object_notify (G_OBJECT (source), "dbus-object");
2519 }
2520 
2521 /**
2522  * e_source_new:
2523  * @dbus_object: (nullable): a #GDBusObject or %NULL
2524  * @main_context: (nullable): a #GMainContext or %NULL
2525  * @error: return location for a #GError, or %NULL
2526  *
2527  * Creates a new #ESource instance.
2528  *
2529  * The #ESource::changed signal will be emitted from @main_context if given,
2530  * or else from the thread-default #GMainContext at the time this function is
2531  * called.
2532  *
2533  * The only time the function should be called outside of #ESourceRegistry
2534  * is to create a so-called "scratch" #ESource for editing in a Properties
2535  * window or an account setup assistant.
2536  *
2537  * FIXME: Elaborate on scratch sources.
2538  *
2539  * Returns: a new #ESource, or %NULL on error
2540  *
2541  * Since: 3.6
2542  **/
2543 ESource *
e_source_new(GDBusObject * dbus_object,GMainContext * main_context,GError ** error)2544 e_source_new (GDBusObject *dbus_object,
2545               GMainContext *main_context,
2546               GError **error)
2547 {
2548 	if (dbus_object != NULL)
2549 		g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), NULL);
2550 
2551 	return g_initable_new (
2552 		E_TYPE_SOURCE, NULL, error,
2553 		"dbus-object", dbus_object,
2554 		"main-context", main_context,
2555 		NULL);
2556 }
2557 
2558 /**
2559  * e_source_new_with_uid:
2560  * @uid: a new unique identifier string
2561  * @main_context: (nullable): a #GMainContext or %NULL
2562  * @error: return location for a #GError, or %NULL
2563  *
2564  * Creates a new "scratch" #ESource with a predetermined unique identifier.
2565  *
2566  * The #ESource::changed signal will be emitted from @main_context if given,
2567  * or else from the thread-default #GMainContext at the time this function is
2568  * called.
2569  *
2570  * Returns: a new scratch #ESource, or %NULL on error
2571  *
2572  * Since: 3.6
2573  **/
2574 ESource *
e_source_new_with_uid(const gchar * uid,GMainContext * main_context,GError ** error)2575 e_source_new_with_uid (const gchar *uid,
2576                        GMainContext *main_context,
2577                        GError **error)
2578 {
2579 	g_return_val_if_fail (uid != NULL, NULL);
2580 
2581 	return g_initable_new (
2582 		E_TYPE_SOURCE, NULL, error,
2583 		"main-context", main_context,
2584 		"uid", uid, NULL);
2585 }
2586 
2587 /**
2588  * e_source_hash:
2589  * @source: an #ESource
2590  *
2591  * Generates a hash value for @source.  This function is intended for
2592  * easily hashing an #ESource to add to a #GHashTable or similar data
2593  * structure.
2594  *
2595  * Returns: a hash value for @source.
2596  *
2597  * Since: 3.6
2598  **/
2599 guint
e_source_hash(ESource * source)2600 e_source_hash (ESource *source)
2601 {
2602 	const gchar *uid;
2603 
2604 	g_return_val_if_fail (E_IS_SOURCE (source), 0);
2605 
2606 	uid = e_source_get_uid (source);
2607 
2608 	return g_str_hash (uid);
2609 }
2610 
2611 /**
2612  * e_source_equal:
2613  * @source1: the first #ESource
2614  * @source2: the second #ESource
2615  *
2616  * Checks two #ESource instances for equality.  #ESource instances are
2617  * equal if their unique identifier strings are equal.
2618  *
2619  * Returns: %TRUE if @source1 and @source2 are equal
2620  *
2621  * Since: 3.6
2622  **/
2623 gboolean
e_source_equal(ESource * source1,ESource * source2)2624 e_source_equal (ESource *source1,
2625                 ESource *source2)
2626 {
2627 	const gchar *uid1, *uid2;
2628 
2629 	g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
2630 	g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
2631 
2632 	if (source1 == source2)
2633 		return TRUE;
2634 
2635 	uid1 = e_source_get_uid (source1);
2636 	uid2 = e_source_get_uid (source2);
2637 
2638 	return g_str_equal (uid1, uid2);
2639 }
2640 
2641 /**
2642  * e_source_changed:
2643  * @source: an #ESource
2644  *
2645  * Emits the #ESource::changed signal from an idle callback in
2646  * @source's #ESource:main-context.
2647  *
2648  * This function is primarily intended for use by #ESourceExtension
2649  * when emitting a #GObject::notify signal on one of its properties.
2650  *
2651  * Since: 3.6
2652  **/
2653 void
e_source_changed(ESource * source)2654 e_source_changed (ESource *source)
2655 {
2656 	g_return_if_fail (E_IS_SOURCE (source));
2657 
2658 	g_mutex_lock (&source->priv->changed_lock);
2659 	if (!source->priv->ignore_changed_signal &&
2660 	    source->priv->initialized &&
2661 	    source->priv->changed == NULL) {
2662 		source->priv->changed = g_idle_source_new ();
2663 		g_source_set_callback (
2664 			source->priv->changed,
2665 			source_idle_changed_cb,
2666 			g_object_ref (source), g_object_unref);
2667 		g_source_attach (
2668 			source->priv->changed,
2669 			source->priv->main_context);
2670 	}
2671 	g_mutex_unlock (&source->priv->changed_lock);
2672 }
2673 
2674 /**
2675  * e_source_get_uid:
2676  * @source: an #ESource
2677  *
2678  * Returns the unique identifier string for @source.
2679  *
2680  * Returns: the UID for @source
2681  *
2682  * Since: 3.6
2683  **/
2684 const gchar *
e_source_get_uid(ESource * source)2685 e_source_get_uid (ESource *source)
2686 {
2687 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2688 
2689 	return source->priv->uid;
2690 }
2691 
2692 /**
2693  * e_source_dup_uid:
2694  * @source: an #ESource
2695  *
2696  * Thread-safe variation of e_source_get_uid().
2697  * Use this function when accessing @source from multiple threads.
2698  *
2699  * The returned string should be freed with g_free() when no longer needed.
2700  *
2701  * Returns: a newly-allocated copy of #ESource:uid
2702  *
2703  * Since: 3.6
2704  **/
2705 gchar *
e_source_dup_uid(ESource * source)2706 e_source_dup_uid (ESource *source)
2707 {
2708 	const gchar *protected;
2709 	gchar *duplicate;
2710 
2711 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2712 
2713 	/* Perhaps we don't need to lock the mutex since
2714 	 * this is a read-only property but it can't hurt. */
2715 
2716 	g_mutex_lock (&source->priv->property_lock);
2717 
2718 	protected = e_source_get_uid (source);
2719 	duplicate = g_strdup (protected);
2720 
2721 	g_mutex_unlock (&source->priv->property_lock);
2722 
2723 	return duplicate;
2724 }
2725 
2726 /**
2727  * e_source_get_parent:
2728  * @source: an #ESource
2729  *
2730  * Returns the unique identifier string of the parent #ESource.
2731  *
2732  * Returns: (nullable): the UID of the parent #ESource
2733  *
2734  * Since: 3.6
2735  **/
2736 const gchar *
e_source_get_parent(ESource * source)2737 e_source_get_parent (ESource *source)
2738 {
2739 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2740 
2741 	return source->priv->parent;
2742 }
2743 
2744 /**
2745  * e_source_dup_parent:
2746  * @source: an #ESource
2747  *
2748  * Thread-safe variation of e_source_get_parent().
2749  * Use this function when accessing @source from multiple threads.
2750  *
2751  * The returned string should be freed with g_free() when no longer needed.
2752  *
2753  * Returns: (nullable): a newly-allocated copy of #ESource:parent
2754  *
2755  * Since: 3.6
2756  **/
2757 gchar *
e_source_dup_parent(ESource * source)2758 e_source_dup_parent (ESource *source)
2759 {
2760 	const gchar *protected;
2761 	gchar *duplicate;
2762 
2763 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
2764 
2765 	g_mutex_lock (&source->priv->property_lock);
2766 
2767 	protected = e_source_get_parent (source);
2768 	duplicate = g_strdup (protected);
2769 
2770 	g_mutex_unlock (&source->priv->property_lock);
2771 
2772 	return duplicate;
2773 }
2774 
2775 /**
2776  * e_source_set_parent:
2777  * @source: an #ESource
2778  * @parent: (nullable): the UID of the parent #ESource, or %NULL
2779  *
2780  * Identifies the parent of @source by its unique identifier string.
2781  * This can only be set prior to adding @source to an #ESourceRegistry.
2782  *
2783  * The internal copy of #ESource:parent is automatically stripped of leading
2784  * and trailing whitespace.  If the resulting string is empty, %NULL is set
2785  * instead.
2786  *
2787  * Since: 3.6
2788  **/
2789 void
e_source_set_parent(ESource * source,const gchar * parent)2790 e_source_set_parent (ESource *source,
2791                      const gchar *parent)
2792 {
2793 	g_return_if_fail (E_IS_SOURCE (source));
2794 
2795 	g_mutex_lock (&source->priv->property_lock);
2796 
2797 	if (e_util_strcmp0 (source->priv->parent, parent) == 0) {
2798 		g_mutex_unlock (&source->priv->property_lock);
2799 		return;
2800 	}
2801 
2802 	g_free (source->priv->parent);
2803 	source->priv->parent = e_util_strdup_strip (parent);
2804 
2805 	g_mutex_unlock (&source->priv->property_lock);
2806 
2807 	g_object_notify (G_OBJECT (source), "parent");
2808 }
2809 
2810 /**
2811  * e_source_get_enabled:
2812  * @source: an #ESource
2813  *
2814  * Returns %TRUE if @source is enabled.
2815  *
2816  * An application should try to honor this setting if at all possible,
2817  * even if it does not provide a way to change the setting through its
2818  * user interface.  Disabled data sources should generally be hidden.
2819  *
2820  * <note><para>
2821  *   This function does not take into account @source's ancestors in the
2822  *   #ESource hierarchy, each of which have their own enabled state.  If
2823  *   any of @source's ancestors are disabled, then @source itself should
2824  *   be treated as disabled.  Use e_source_registry_check_enabled() to
2825  *   easily check for this.
2826  * </para></note>
2827  *
2828  * Returns: whether @source is enabled
2829  *
2830  * Since: 3.6
2831  **/
2832 gboolean
e_source_get_enabled(ESource * source)2833 e_source_get_enabled (ESource *source)
2834 {
2835 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2836 
2837 	return source->priv->enabled;
2838 }
2839 
2840 /**
2841  * e_source_set_enabled:
2842  * @source: an #ESource
2843  * @enabled: whether to enable @source
2844  *
2845  * Enables or disables @source.
2846  *
2847  * An application should try to honor this setting if at all possible,
2848  * even if it does not provide a way to change the setting through its
2849  * user interface.  Disabled data sources should generally be hidden.
2850  *
2851  * Since: 3.6
2852  **/
2853 void
e_source_set_enabled(ESource * source,gboolean enabled)2854 e_source_set_enabled (ESource *source,
2855                       gboolean enabled)
2856 {
2857 	g_return_if_fail (E_IS_SOURCE (source));
2858 
2859 	if (source->priv->enabled == enabled)
2860 		return;
2861 
2862 	source->priv->enabled = enabled;
2863 
2864 	g_object_notify (G_OBJECT (source), "enabled");
2865 }
2866 
2867 /**
2868  * e_source_get_writable:
2869  * @source: an #ESource
2870  *
2871  * Returns whether the D-Bus service will accept changes to @source.
2872  * If @source is not writable, calls to e_source_write() will fail.
2873  *
2874  * Returns: whether @source is writable
2875  *
2876  * Since: 3.6
2877  **/
2878 gboolean
e_source_get_writable(ESource * source)2879 e_source_get_writable (ESource *source)
2880 {
2881 	GDBusObject *dbus_object;
2882 	gboolean writable = FALSE;
2883 
2884 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2885 
2886 	dbus_object = e_source_ref_dbus_object (source);
2887 	if (dbus_object != NULL) {
2888 		EDBusSourceWritable *dbus_interface;
2889 
2890 		dbus_interface =
2891 			e_dbus_object_peek_source_writable (
2892 			E_DBUS_OBJECT (dbus_object));
2893 		writable = (dbus_interface != NULL);
2894 		g_object_unref (dbus_object);
2895 	}
2896 
2897 	return writable;
2898 }
2899 
2900 /**
2901  * e_source_get_removable:
2902  * @source: an #ESource
2903  *
2904  * Returns whether the D-Bus service will allow @source to be removed.
2905  * If @source is not writable, calls to e_source_remove() will fail.
2906  *
2907  * Returns: whether @source is removable
2908  *
2909  * Since: 3.6
2910  **/
2911 gboolean
e_source_get_removable(ESource * source)2912 e_source_get_removable (ESource *source)
2913 {
2914 	GDBusObject *dbus_object;
2915 	gboolean removable = FALSE;
2916 
2917 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2918 
2919 	dbus_object = e_source_ref_dbus_object (source);
2920 	if (dbus_object != NULL) {
2921 		EDBusSourceRemovable *dbus_interface;
2922 
2923 		dbus_interface =
2924 			e_dbus_object_peek_source_removable (
2925 			E_DBUS_OBJECT (dbus_object));
2926 		removable = (dbus_interface != NULL);
2927 		g_object_unref (dbus_object);
2928 	}
2929 
2930 	return removable;
2931 }
2932 
2933 /**
2934  * e_source_get_remote_creatable:
2935  * @source: an #ESource
2936  *
2937  * Returns whether new resources can be created on a remote server by
2938  * calling e_source_remote_create() on @source.
2939  *
2940  * Generally this is only %TRUE if @source has an #ESourceCollection
2941  * extension, which means there is an #ECollectionBackend in the D-Bus
2942  * service that can handle create requests.  If @source does not have
2943  * this capability, calls to e_source_remote_create() will fail.
2944  *
2945  * Returns: whether @source can create remote resources
2946  *
2947  * Since: 3.6
2948  **/
2949 gboolean
e_source_get_remote_creatable(ESource * source)2950 e_source_get_remote_creatable (ESource *source)
2951 {
2952 	GDBusObject *dbus_object;
2953 	gboolean remote_creatable = FALSE;
2954 
2955 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2956 
2957 	dbus_object = e_source_ref_dbus_object (source);
2958 	if (dbus_object != NULL) {
2959 		EDBusSourceRemoteCreatable *dbus_interface;
2960 
2961 		dbus_interface =
2962 			e_dbus_object_peek_source_remote_creatable (
2963 			E_DBUS_OBJECT (dbus_object));
2964 		remote_creatable = (dbus_interface != NULL);
2965 		g_object_unref (dbus_object);
2966 	}
2967 
2968 	return remote_creatable;
2969 }
2970 
2971 /**
2972  * e_source_get_remote_deletable:
2973  * @source: an #ESource
2974  *
2975  * Returns whether the resource represented by @source can be deleted
2976  * from a remote server by calling e_source_remote_delete().
2977  *
2978  * Generally this is only %TRUE if @source is a child of an #ESource
2979  * which has an #ESourceCollection extension, which means there is an
2980  * #ECollectionBackend in the D-Bus service that can handle delete
2981  * requests.  If @source does not have this capability, calls to
2982  * e_source_remote_delete() will fail.
2983  *
2984  * Returns: whether @source can delete remote resources
2985  *
2986  * Since: 3.6
2987  **/
2988 gboolean
e_source_get_remote_deletable(ESource * source)2989 e_source_get_remote_deletable (ESource *source)
2990 {
2991 	GDBusObject *dbus_object;
2992 	gboolean remote_deletable = FALSE;
2993 
2994 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
2995 
2996 	dbus_object = e_source_ref_dbus_object (source);
2997 	if (dbus_object != NULL) {
2998 		EDBusSourceRemoteDeletable *dbus_interface;
2999 
3000 		dbus_interface =
3001 			e_dbus_object_peek_source_remote_deletable (
3002 			E_DBUS_OBJECT (dbus_object));
3003 		remote_deletable = (dbus_interface != NULL);
3004 		g_object_unref (dbus_object);
3005 	}
3006 
3007 	return remote_deletable;
3008 }
3009 
3010 /**
3011  * e_source_get_extension:
3012  * @source: an #ESource
3013  * @extension_name: an extension name
3014  *
3015  * Returns an instance of some #ESourceExtension subclass which registered
3016  * itself under @extension_name.  If no such instance exists within @source,
3017  * one will be created.  It is the caller's responsibility to know which
3018  * subclass is being returned.
3019  *
3020  * If you just want to test for the existence of an extension within @source
3021  * without creating it, use e_source_has_extension().
3022  *
3023  * Extension instances are owned by their #ESource and should not be
3024  * referenced directly.  Instead, reference the #ESource instance and
3025  * use this function to fetch the extension instance as needed.
3026  *
3027  * Returns: (type ESourceExtension) (transfer none): an instance of some
3028  * #ESourceExtension subclass
3029  *
3030  * Since: 3.6
3031  **/
3032 gpointer
e_source_get_extension(ESource * source,const gchar * extension_name)3033 e_source_get_extension (ESource *source,
3034                         const gchar *extension_name)
3035 {
3036 	ESourceExtension *extension;
3037 	GHashTable *hash_table;
3038 	GTypeClass *class;
3039 
3040 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3041 	g_return_val_if_fail (extension_name != NULL, NULL);
3042 
3043 	g_rec_mutex_lock (&source->priv->lock);
3044 
3045 	/* Check if we already have the extension. */
3046 	extension = g_hash_table_lookup (
3047 		source->priv->extensions, extension_name);
3048 	if (extension != NULL)
3049 		goto exit;
3050 
3051 	/* Find all subclasses of ESourceExtensionClass. */
3052 	hash_table = source_find_extension_classes ();
3053 	class = g_hash_table_lookup (hash_table, extension_name);
3054 
3055 	/* Create a new instance of the appropriate GType. */
3056 	if (class != NULL) {
3057 		g_mutex_lock (&source->priv->changed_lock);
3058 		source->priv->ignore_changed_signal++;
3059 		g_mutex_unlock (&source->priv->changed_lock);
3060 
3061 		extension = g_object_new (
3062 			G_TYPE_FROM_CLASS (class),
3063 			"source", source, NULL);
3064 		source_load_from_key_file (
3065 			G_OBJECT (extension),
3066 			source->priv->key_file,
3067 			extension_name);
3068 		g_hash_table_insert (
3069 			source->priv->extensions,
3070 			g_strdup (extension_name), extension);
3071 
3072 		g_mutex_lock (&source->priv->changed_lock);
3073 		source->priv->ignore_changed_signal--;
3074 		g_mutex_unlock (&source->priv->changed_lock);
3075 	} else {
3076 		/* XXX Tie this into a debug setting for ESources. */
3077 #ifdef DEBUG
3078 		g_critical (
3079 			"No registered GType for ESource "
3080 			"extension '%s'", extension_name);
3081 #endif
3082 	}
3083 
3084 	g_hash_table_destroy (hash_table);
3085 
3086 exit:
3087 	g_rec_mutex_unlock (&source->priv->lock);
3088 
3089 	return extension;
3090 }
3091 
3092 /**
3093  * e_source_has_extension:
3094  * @source: an #ESource
3095  * @extension_name: an extension name
3096  *
3097  * Checks whether @source has an #ESourceExtension with the given name.
3098  *
3099  * Returns: %TRUE if @source has such an extension, %FALSE if not
3100  *
3101  * Since: 3.6
3102  **/
3103 gboolean
e_source_has_extension(ESource * source,const gchar * extension_name)3104 e_source_has_extension (ESource *source,
3105                         const gchar *extension_name)
3106 {
3107 	ESourceExtension *extension;
3108 
3109 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3110 	g_return_val_if_fail (extension_name != NULL, FALSE);
3111 
3112 	g_rec_mutex_lock (&source->priv->lock);
3113 
3114 	/* Two cases to check for, either one is good enough:
3115 	 * 1) Our internal GKeyFile has a group named 'extension_name'.
3116 	 * 2) Our 'extensions' table has an entry for 'extension_name'.
3117 	 *
3118 	 * We have to check both data structures in case a new extension
3119 	 * not present in the GKeyFile was instantiated, but we have not
3120 	 * yet updated our internal GKeyFile.  A common occurrence when
3121 	 * editing a brand new data source.
3122 	 *
3123 	 * When checking the GKeyFile we want to actually fetch the
3124 	 * extension with e_source_get_extension() to make sure it's
3125 	 * a registered extension name and not just an arbitrary key
3126 	 * file group name. */
3127 
3128 	if (g_key_file_has_group (source->priv->key_file, extension_name)) {
3129 		extension = e_source_get_extension (source, extension_name);
3130 	} else {
3131 		GHashTable *hash_table = source->priv->extensions;
3132 		extension = g_hash_table_lookup (hash_table, extension_name);
3133 	}
3134 
3135 	g_rec_mutex_unlock (&source->priv->lock);
3136 
3137 	return (extension != NULL);
3138 }
3139 
3140 /**
3141  * e_source_ref_dbus_object:
3142  * @source: an #ESource
3143  *
3144  * Returns the #GDBusObject that was passed to e_source_new().
3145  *
3146  * The returned #GDBusObject is referenced for thread-safety and must be
3147  * unreferenced with g_object_unref() when finished with it.
3148  *
3149  * Returns: (transfer full) (nullable): the #GDBusObject for @source, or %NULL
3150  *
3151  * Since: 3.6
3152  **/
3153 GDBusObject *
e_source_ref_dbus_object(ESource * source)3154 e_source_ref_dbus_object (ESource *source)
3155 {
3156 	GDBusObject *dbus_object = NULL;
3157 
3158 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3159 
3160 	g_mutex_lock (&source->priv->property_lock);
3161 
3162 	if (source->priv->dbus_object != NULL)
3163 		dbus_object = g_object_ref (source->priv->dbus_object);
3164 
3165 	g_mutex_unlock (&source->priv->property_lock);
3166 
3167 	return dbus_object;
3168 }
3169 
3170 /**
3171  * e_source_ref_main_context:
3172  * @source: an #ESource
3173  *
3174  * Returns the #GMainContext on which event sources for @source are to
3175  * be attached.
3176  *
3177  * The returned #GMainContext is referenced for thread-safety and must be
3178  * unreferenced with g_main_context_unref() when finished with it.
3179  *
3180  * Returns: (transfer full): a #GMainContext
3181  *
3182  * Since: 3.6
3183  **/
3184 GMainContext *
e_source_ref_main_context(ESource * source)3185 e_source_ref_main_context (ESource *source)
3186 {
3187 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3188 
3189 	return g_main_context_ref (source->priv->main_context);
3190 }
3191 
3192 /**
3193  * e_source_get_display_name:
3194  * @source: an #ESource
3195  *
3196  * Returns the display name for @source.  Use the display name to
3197  * represent the #ESource in a user interface.
3198  *
3199  * Returns: the display name for @source
3200  *
3201  * Since: 3.6
3202  **/
3203 const gchar *
e_source_get_display_name(ESource * source)3204 e_source_get_display_name (ESource *source)
3205 {
3206 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3207 
3208 	return source->priv->display_name;
3209 }
3210 
3211 /**
3212  * e_source_dup_display_name:
3213  * @source: an #ESource
3214  *
3215  * Thread-safe variation of e_source_get_display_name().
3216  * Use this function when accessing @source from multiple threads.
3217  *
3218  * The returned string should be freed with g_free() when no longer needed.
3219  *
3220  * Returns: a newly-allocated copy of #ESource:display-name
3221  *
3222  * Since: 3.6
3223  **/
3224 gchar *
e_source_dup_display_name(ESource * source)3225 e_source_dup_display_name (ESource *source)
3226 {
3227 	const gchar *protected;
3228 	gchar *duplicate;
3229 
3230 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3231 
3232 	g_mutex_lock (&source->priv->property_lock);
3233 
3234 	protected = e_source_get_display_name (source);
3235 	duplicate = g_strdup (protected);
3236 
3237 	g_mutex_unlock (&source->priv->property_lock);
3238 
3239 	return duplicate;
3240 }
3241 
3242 /**
3243  * e_source_set_display_name:
3244  * @source: an #ESource
3245  * @display_name: a display name
3246  *
3247  * Sets the display name for @source.  The @display_name argument must be a
3248  * valid UTF-8 string.  Use the display name to represent the #ESource in a
3249  * user interface.
3250  *
3251  * The internal copy of @display_name is automatically stripped of leading
3252  * and trailing whitespace.
3253  *
3254  * Since: 3.6
3255  **/
3256 void
e_source_set_display_name(ESource * source,const gchar * display_name)3257 e_source_set_display_name (ESource *source,
3258                            const gchar *display_name)
3259 {
3260 	g_return_if_fail (E_IS_SOURCE (source));
3261 	g_return_if_fail (display_name != NULL);
3262 	g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
3263 
3264 	g_mutex_lock (&source->priv->property_lock);
3265 
3266 	if (g_strcmp0 (source->priv->display_name, display_name) == 0) {
3267 		g_mutex_unlock (&source->priv->property_lock);
3268 		return;
3269 	}
3270 
3271 	g_free (source->priv->display_name);
3272 	source->priv->display_name = g_strdup (display_name);
3273 
3274 	/* Strip leading and trailing whitespace. */
3275 	g_strstrip (source->priv->display_name);
3276 
3277 	/* This is used in e_source_compare_by_display_name(). */
3278 	g_free (source->priv->collate_key);
3279 	source->priv->collate_key = g_utf8_collate_key (display_name, -1);
3280 
3281 	g_mutex_unlock (&source->priv->property_lock);
3282 
3283 	g_object_notify (G_OBJECT (source), "display-name");
3284 }
3285 
3286 /**
3287  * e_source_dup_secret_label:
3288  * @source: an #ESource
3289  *
3290  * Creates a label string based on @source's #ESource:display-name for use
3291  * with #SecretItem.
3292  *
3293  * Returns: a newly-allocated secret label
3294  *
3295  * Since: 3.12
3296  **/
3297 gchar *
e_source_dup_secret_label(ESource * source)3298 e_source_dup_secret_label (ESource *source)
3299 {
3300 	gchar *display_name;
3301 	gchar *backend_name = NULL;
3302 	const gchar *type = NULL;
3303 	const gchar *parent;
3304 	GString *secret_label;
3305 
3306 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3307 
3308 	display_name = e_source_dup_display_name (source);
3309 
3310 	if (display_name == NULL || *display_name == '\0') {
3311 		g_free (display_name);
3312 		display_name = e_source_dup_uid (source);
3313 	}
3314 
3315 	#define update_backend_name(ext) G_STMT_START { \
3316 			ESourceBackend *backend_extension; \
3317 			backend_extension = e_source_get_extension (source, ext); \
3318 			g_free (backend_name); \
3319 			backend_name = e_source_backend_dup_backend_name (backend_extension); \
3320 		} G_STMT_END
3321 
3322 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
3323 		type = "Addressbook";
3324 		update_backend_name (E_SOURCE_EXTENSION_ADDRESS_BOOK);
3325 	}
3326 
3327 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
3328 		if (!type) {
3329 			type = "Calendar";
3330 			update_backend_name (E_SOURCE_EXTENSION_CALENDAR);
3331 		} else
3332 			type = "";
3333 	}
3334 
3335 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
3336 		if (!type) {
3337 			type = "Mail Account";
3338 			update_backend_name (E_SOURCE_EXTENSION_MAIL_ACCOUNT);
3339 		} else
3340 			type = "";
3341 	}
3342 
3343 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
3344 		if (!type) {
3345 			type = "Mail Transport";
3346 			update_backend_name (E_SOURCE_EXTENSION_MAIL_TRANSPORT);
3347 		} else
3348 			type = "";
3349 	}
3350 
3351 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
3352 		if (!type) {
3353 			type = "Memo List";
3354 			update_backend_name (E_SOURCE_EXTENSION_MEMO_LIST);
3355 		} else
3356 			type = "";
3357 	}
3358 
3359 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
3360 		if (!type) {
3361 			type = "Task List";
3362 			update_backend_name (E_SOURCE_EXTENSION_TASK_LIST);
3363 		} else
3364 			type = "";
3365 	}
3366 
3367 	if (e_source_has_extension (source, E_SOURCE_EXTENSION_COLLECTION)) {
3368 		if (!type) {
3369 			type = "Collection";
3370 			update_backend_name (E_SOURCE_EXTENSION_COLLECTION);
3371 		} else
3372 			type = "";
3373 	}
3374 
3375 	if (!type || !*type) {
3376 		g_free (backend_name);
3377 		backend_name = NULL;
3378 		type = NULL;
3379 	}
3380 
3381 	if (backend_name && !*backend_name) {
3382 		g_free (backend_name);
3383 		backend_name = NULL;
3384 	}
3385 
3386 	secret_label = g_string_new (NULL);
3387 
3388 	if (type && backend_name)
3389 		g_string_append_printf (secret_label, "Evolution Data Source \"%s\" (%s - %s) ", display_name, type, backend_name);
3390 	else if (type)
3391 		g_string_append_printf (secret_label, "Evolution Data Source \"%s\" (%s)", display_name, type);
3392 	else
3393 		g_string_append_printf (secret_label, "Evolution Data Source \"%s\"", display_name);
3394 
3395 	g_free (backend_name);
3396 	g_free (display_name);
3397 
3398 	parent = e_source_get_parent (source);
3399 	if (parent && *parent)
3400 		g_string_append_printf (secret_label, " of %s", parent);
3401 
3402 	return g_string_free (secret_label, FALSE);
3403 }
3404 
3405 /**
3406  * e_source_compare_by_display_name:
3407  * @source1: the first #ESource
3408  * @source2: the second #ESource
3409  *
3410  * Compares two #ESource instances by their display names.  Useful for
3411  * ordering sources in a user interface.
3412  *
3413  * Returns: a negative value if @source1 compares before @source2, zero if
3414  *          they compare equal, or a positive value if @source1 compares
3415  *          after @source2
3416  *
3417  * Since: 3.6
3418  **/
3419 gint
e_source_compare_by_display_name(ESource * source1,ESource * source2)3420 e_source_compare_by_display_name (ESource *source1,
3421                                   ESource *source2)
3422 {
3423 	gint res;
3424 
3425 	res = g_strcmp0 (
3426 		source1->priv->collate_key,
3427 		source2->priv->collate_key);
3428 
3429 	if (res == 0)
3430 		res = g_strcmp0 (source1->priv->uid, source2->priv->uid);
3431 
3432 	return res;
3433 }
3434 
3435 /**
3436  * e_source_to_string:
3437  * @source: an #ESource
3438  * @length: (optional) (out): return location for the length of the returned
3439  *          string, or %NULL
3440  *
3441  * Outputs the current contents of @source as a key file string.
3442  * Free the returned string with g_free().
3443  *
3444  * Returns: a newly-allocated string
3445  *
3446  * Since: 3.6
3447  **/
3448 gchar *
e_source_to_string(ESource * source,gsize * length)3449 e_source_to_string (ESource *source,
3450                     gsize *length)
3451 {
3452 	GHashTableIter iter;
3453 	GKeyFile *key_file;
3454 	gpointer group_name;
3455 	gpointer extension;
3456 	gchar *data;
3457 
3458 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3459 
3460 	g_rec_mutex_lock (&source->priv->lock);
3461 
3462 	key_file = source->priv->key_file;
3463 
3464 	source_save_to_key_file (
3465 		G_OBJECT (source), key_file, PRIMARY_GROUP_NAME);
3466 
3467 	g_hash_table_iter_init (&iter, source->priv->extensions);
3468 	while (g_hash_table_iter_next (&iter, &group_name, &extension))
3469 		source_save_to_key_file (extension, key_file, group_name);
3470 
3471 	data = g_key_file_to_data (key_file, length, NULL);
3472 
3473 	g_rec_mutex_unlock (&source->priv->lock);
3474 
3475 	return data;
3476 }
3477 
3478 /**
3479  * e_source_parameter_to_key:
3480  * @param_name: a #GParamSpec name
3481  *
3482  * Converts a #GParamSpec name (e.g. "foo-bar" or "foo_bar")
3483  * to "CamelCase" for use as a #GKeyFile key (e.g. "FooBar").
3484  *
3485  * This function is made public only to aid in account migration.
3486  * Applications should not need to use this.
3487  *
3488  * Since: 3.6
3489  **/
3490 gchar *
e_source_parameter_to_key(const gchar * param_name)3491 e_source_parameter_to_key (const gchar *param_name)
3492 {
3493 	gboolean uppercase = TRUE;
3494 	gchar *key, *cp;
3495 	gint ii;
3496 
3497 	g_return_val_if_fail (param_name != NULL, NULL);
3498 
3499 	key = cp = g_malloc0 (strlen (param_name) + 1);
3500 
3501 	for (ii = 0; param_name[ii] != '\0'; ii++) {
3502 		if (g_ascii_isalnum (param_name[ii]) && uppercase) {
3503 			*cp++ = g_ascii_toupper (param_name[ii]);
3504 			uppercase = FALSE;
3505 		} else if (param_name[ii] == '-' || param_name[ii] == '_')
3506 			uppercase = TRUE;
3507 		else
3508 			*cp++ = param_name[ii];
3509 	}
3510 
3511 	return key;
3512 }
3513 
3514 /**
3515  * e_source_get_connection_status:
3516  * @source: an #ESource
3517  *
3518  * Obtain current connection status of the @source.
3519  *
3520  * Returns: Current connection status of the @source.
3521  *
3522  * Since: 3.16
3523  **/
3524 ESourceConnectionStatus
e_source_get_connection_status(ESource * source)3525 e_source_get_connection_status (ESource *source)
3526 {
3527 	g_return_val_if_fail (E_IS_SOURCE (source), E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
3528 
3529 	return source->priv->connection_status;
3530 }
3531 
3532 /**
3533  * e_source_set_connection_status:
3534  * @source: an #ESource
3535  * @connection_status: one of the #ESourceConnectionStatus
3536  *
3537  * Set's current connection status of the @source.
3538  *
3539  * Since: 3.16
3540  **/
3541 void
e_source_set_connection_status(ESource * source,ESourceConnectionStatus connection_status)3542 e_source_set_connection_status (ESource *source,
3543 				ESourceConnectionStatus connection_status)
3544 {
3545 	GEnumClass *enum_class;
3546 	GEnumValue *enum_value;
3547 
3548 	g_return_if_fail (E_IS_SOURCE (source));
3549 
3550 	if (source->priv->connection_status == connection_status)
3551 		return;
3552 
3553 	source->priv->connection_status = connection_status;
3554 
3555 	enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
3556 	enum_value = g_enum_get_value (enum_class, connection_status);
3557 
3558 	if (enum_value) {
3559 		GDBusObject *dbus_object;
3560 		EDBusSource *dbus_source;
3561 
3562 		dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
3563 		if (dbus_object) {
3564 			dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
3565 			if (dbus_source) {
3566 				e_dbus_source_set_connection_status (dbus_source, enum_value->value_nick);
3567 				g_object_unref (dbus_source);
3568 			}
3569 
3570 			g_object_unref (dbus_object);
3571 		}
3572 	} else {
3573 		g_warning ("%s: Unknown connection status: %x", G_STRFUNC, connection_status);
3574 	}
3575 
3576 	g_type_class_unref (enum_class);
3577 
3578 	g_object_notify (G_OBJECT (source), "connection-status");
3579 }
3580 
3581 /**
3582  * e_source_remove_sync:
3583  * @source: the #ESource to be removed
3584  * @cancellable: optional #GCancellable object, or %NULL
3585  * @error: return location for a #GError, or %NULL
3586  *
3587  * Requests the D-Bus service to delete the key files for @source and all of
3588  * its descendants and broadcast their removal to all clients.  The @source
3589  * must be #ESource:removable.
3590  *
3591  * If an error occurs, the functon will set @error and return %FALSE.
3592  *
3593  * Returns: %TRUE on success, %FALSE on error
3594  *
3595  * Since: 3.6
3596  **/
3597 gboolean
e_source_remove_sync(ESource * source,GCancellable * cancellable,GError ** error)3598 e_source_remove_sync (ESource *source,
3599                       GCancellable *cancellable,
3600                       GError **error)
3601 {
3602 	ESourceClass *class;
3603 
3604 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3605 
3606 	class = E_SOURCE_GET_CLASS (source);
3607 	g_return_val_if_fail (class != NULL, FALSE);
3608 	g_return_val_if_fail (class->remove_sync != NULL, FALSE);
3609 
3610 	return class->remove_sync (source, cancellable, error);
3611 }
3612 
3613 /**
3614  * e_source_remove:
3615  * @source: the #ESource to be removed
3616  * @cancellable: optional #GCancellable object, or %NULL
3617  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3618  * @user_data: data to pass to the callback function
3619  *
3620  * Asynchronously requests the D-Bus service to delete the key files for
3621  * @source and all of its descendants and broadcast their removal to all
3622  * clients.  The @source must be #ESource:removable.
3623  *
3624  * When the operation is finished, @callback will be called.  You can then
3625  * call e_source_remove_finish() to get the result of the operation.
3626  *
3627  * Since: 3.6
3628  **/
3629 void
e_source_remove(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3630 e_source_remove (ESource *source,
3631                  GCancellable *cancellable,
3632                  GAsyncReadyCallback callback,
3633                  gpointer user_data)
3634 {
3635 	ESourceClass *class;
3636 
3637 	g_return_if_fail (E_IS_SOURCE (source));
3638 
3639 	class = E_SOURCE_GET_CLASS (source);
3640 	g_return_if_fail (class != NULL);
3641 	g_return_if_fail (class->remove != NULL);
3642 
3643 	class->remove (source, cancellable, callback, user_data);
3644 }
3645 
3646 /**
3647  * e_source_remove_finish:
3648  * @source: the #ESource to be removed
3649  * @result: a #GAsyncResult
3650  * @error: return location for a #GError, or %NULL
3651  *
3652  * Finishes the operation started with e_source_remove().  If an
3653  * error occurred, the function will set @error and return %FALSE.
3654  *
3655  * Returns: %TRUE on success, %FALSE of failure
3656  *
3657  * Since: 3.6
3658  **/
3659 gboolean
e_source_remove_finish(ESource * source,GAsyncResult * result,GError ** error)3660 e_source_remove_finish (ESource *source,
3661                         GAsyncResult *result,
3662                         GError **error)
3663 {
3664 	ESourceClass *class;
3665 
3666 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3667 	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3668 
3669 	class = E_SOURCE_GET_CLASS (source);
3670 	g_return_val_if_fail (class != NULL, FALSE);
3671 	g_return_val_if_fail (class->remove_finish != NULL, FALSE);
3672 
3673 	return class->remove_finish (source, result, error);
3674 }
3675 
3676 /**
3677  * e_source_write_sync:
3678  * @source: a writable #ESource
3679  * @cancellable: optional #GCancellable object, or %NULL
3680  * @error: return location for a #GError, or %NULL
3681  *
3682  * Submits the current contents of @source to the D-Bus service to be
3683  * written to disk and broadcast to other clients.  The @source must
3684  * be #ESource:writable.
3685  *
3686  * If an error occurs, the functon will set @error and return %FALSE.
3687  *
3688  * Returns: %TRUE on success, %FALSE on error
3689  *
3690  * Since: 3.6
3691  **/
3692 gboolean
e_source_write_sync(ESource * source,GCancellable * cancellable,GError ** error)3693 e_source_write_sync (ESource *source,
3694                      GCancellable *cancellable,
3695                      GError **error)
3696 {
3697 	ESourceClass *class;
3698 
3699 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3700 
3701 	class = E_SOURCE_GET_CLASS (source);
3702 	g_return_val_if_fail (class != NULL, FALSE);
3703 	g_return_val_if_fail (class->write_sync != NULL, FALSE);
3704 
3705 	return class->write_sync (source, cancellable, error);
3706 }
3707 
3708 /**
3709  * e_source_write:
3710  * @source: a writable #ESource
3711  * @cancellable: optional #GCancellable object, or %NULL
3712  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3713  * @user_data: data to pass to the callback function
3714  *
3715  * Asynchronously submits the current contents of @source to the D-Bus
3716  * service to be written to disk and broadcast to other clients.  The
3717  * @source must be #ESource:writable.
3718  *
3719  * When the operation is finished, @callback will be called.  You can then
3720  * call e_source_write_finish() to get the result of the operation.
3721  *
3722  * Since: 3.6
3723  **/
3724 void
e_source_write(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3725 e_source_write (ESource *source,
3726                 GCancellable *cancellable,
3727                 GAsyncReadyCallback callback,
3728                 gpointer user_data)
3729 {
3730 	ESourceClass *class;
3731 
3732 	g_return_if_fail (E_IS_SOURCE (source));
3733 
3734 	class = E_SOURCE_GET_CLASS (source);
3735 	g_return_if_fail (class != NULL);
3736 	g_return_if_fail (class->write != NULL);
3737 
3738 	class->write (source, cancellable, callback, user_data);
3739 }
3740 
3741 /**
3742  * e_source_write_finish:
3743  * @source: a writable #ESource
3744  * @result: a #GAsyncResult
3745  * @error: return location for a #GError, or %NULL
3746  *
3747  * Finishes the operation started with e_source_write().  If an
3748  * error occurred, the function will set @error and return %FALSE.
3749  *
3750  * Returns: %TRUE on success, %FALSE on error
3751  *
3752  * Since: 3.6
3753  **/
3754 gboolean
e_source_write_finish(ESource * source,GAsyncResult * result,GError ** error)3755 e_source_write_finish (ESource *source,
3756                        GAsyncResult *result,
3757                        GError **error)
3758 {
3759 	ESourceClass *class;
3760 
3761 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3762 	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3763 
3764 	class = E_SOURCE_GET_CLASS (source);
3765 	g_return_val_if_fail (class != NULL, FALSE);
3766 	g_return_val_if_fail (class->write_finish != NULL, FALSE);
3767 
3768 	return class->write_finish (source, result, error);
3769 }
3770 
3771 /**
3772  * e_source_remote_create_sync:
3773  * @source: an #ESource
3774  * @scratch_source: an #ESource describing the resource to create
3775  * @cancellable: optional #GCancellable object, or %NULL
3776  * @error: return location for a #GError, or %NULL
3777  *
3778  * Creates a new remote resource by picking out relevant details from
3779  * @scratch_source.  The @scratch_source must be an #ESource with no
3780  * #GDBusObject.  The @source must be #ESource:remote-creatable.
3781  *
3782  * The details required to create the resource vary by #ECollectionBackend,
3783  * but in most cases the @scratch_source need only define the resource type
3784  * (address book, calendar, etc.), a display name for the resource, and
3785  * possibly a server-side path or ID for the resource.
3786  *
3787  * If an error occurs, the function will set @error and return %FALSE.
3788  *
3789  * Returns: %TRUE on success, %FALSE on error
3790  *
3791  * Since: 3.6
3792  **/
3793 gboolean
e_source_remote_create_sync(ESource * source,ESource * scratch_source,GCancellable * cancellable,GError ** error)3794 e_source_remote_create_sync (ESource *source,
3795                              ESource *scratch_source,
3796                              GCancellable *cancellable,
3797                              GError **error)
3798 {
3799 	ESourceClass *class;
3800 
3801 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3802 	g_return_val_if_fail (E_IS_SOURCE (scratch_source), FALSE);
3803 
3804 	class = E_SOURCE_GET_CLASS (source);
3805 	g_return_val_if_fail (class != NULL, FALSE);
3806 	g_return_val_if_fail (class->remote_create_sync != NULL, FALSE);
3807 
3808 	return class->remote_create_sync (
3809 		source, scratch_source, cancellable, error);
3810 }
3811 
3812 /**
3813  * e_source_remote_create:
3814  * @source: an #ESource
3815  * @scratch_source: an #ESource describing the resource to create
3816  * @cancellable: optional #GCancellable object, or %NULL
3817  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3818  * @user_data: data to pass to the callback function
3819  *
3820  * Asynchronously creates a new remote resource by picking out relevant
3821  * details from @scratch_source.  The @scratch_source must be an #ESource
3822  * with no #GDBusObject.  The @source must be #ESource:remote-creatable.
3823  *
3824  * The details required to create the resource vary by #ECollectionBackend,
3825  * but in most cases the @scratch_source need only define the resource type
3826  * (address book, calendar, etc.), a display name for the resource, and
3827  * possibly a server-side path or ID for the resource.
3828  *
3829  * When the operation is finished, @callback will be called.  You can then
3830  * call e_source_remote_create_finish() to get the result of the operation.
3831  *
3832  * Since: 3.6
3833  **/
3834 void
e_source_remote_create(ESource * source,ESource * scratch_source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3835 e_source_remote_create (ESource *source,
3836                         ESource *scratch_source,
3837                         GCancellable *cancellable,
3838                         GAsyncReadyCallback callback,
3839                         gpointer user_data)
3840 {
3841 	ESourceClass *class;
3842 
3843 	g_return_if_fail (E_IS_SOURCE (source));
3844 	g_return_if_fail (E_IS_SOURCE (scratch_source));
3845 
3846 	class = E_SOURCE_GET_CLASS (source);
3847 	g_return_if_fail (class != NULL);
3848 	g_return_if_fail (class->remote_create != NULL);
3849 
3850 	class->remote_create (
3851 		source, scratch_source,
3852 		cancellable, callback, user_data);
3853 }
3854 
3855 /**
3856  * e_source_remote_create_finish:
3857  * @source: an #ESource
3858  * @result: a #GAsyncResult
3859  * @error: return location for a #GError, or %NULL
3860  *
3861  * Finishes the operation started with e_source_remote_create().  If
3862  * an error occurred, the function will set @error and return %FALSE.
3863  *
3864  * Returns: %TRUE on success, %FALSE on error
3865  *
3866  * Since: 3.6
3867  **/
3868 gboolean
e_source_remote_create_finish(ESource * source,GAsyncResult * result,GError ** error)3869 e_source_remote_create_finish (ESource *source,
3870                                GAsyncResult *result,
3871                                GError **error)
3872 {
3873 	ESourceClass *class;
3874 
3875 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3876 
3877 	class = E_SOURCE_GET_CLASS (source);
3878 	g_return_val_if_fail (class != NULL, FALSE);
3879 	g_return_val_if_fail (class->remote_create_finish != NULL, FALSE);
3880 
3881 	return class->remote_create_finish (source, result, error);
3882 }
3883 
3884 /**
3885  * e_source_remote_delete_sync:
3886  * @source: an #ESource
3887  * @cancellable: optional #GCancellable object, or %NULL
3888  * @error: return location for a #GError, or %NULL
3889  *
3890  * Deletes the resource represented by @source from a remote server.
3891  * The @source must be #ESource:remote-deletable.  This will also delete
3892  * the key file for @source and broadcast its removal to all clients,
3893  * similar to e_source_remove_sync().
3894  *
3895  * If an error occurs, the function will set @error and return %FALSE.
3896  *
3897  * Returns: %TRUE on success, %FALSE on error
3898  *
3899  * Since: 3.6
3900  **/
3901 gboolean
e_source_remote_delete_sync(ESource * source,GCancellable * cancellable,GError ** error)3902 e_source_remote_delete_sync (ESource *source,
3903                              GCancellable *cancellable,
3904                              GError **error)
3905 {
3906 	ESourceClass *class;
3907 
3908 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3909 
3910 	class = E_SOURCE_GET_CLASS (source);
3911 	g_return_val_if_fail (class != NULL, FALSE);
3912 	g_return_val_if_fail (class->remote_delete_sync != NULL, FALSE);
3913 
3914 	return class->remote_delete_sync (source, cancellable, error);
3915 }
3916 
3917 /**
3918  * e_source_remote_delete:
3919  * @source: an #ESource
3920  * @cancellable: optional #GCancellable object, or %NULL
3921  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3922  * @user_data: data to pass to the callback function
3923  *
3924  * Asynchronously deletes the resource represented by @source from a remote
3925  * server.  The @source must be #ESource:remote-deletable.  This will also
3926  * delete the key file for @source and broadcast its removal to all clients,
3927  * similar to e_source_remove().
3928  *
3929  * When the operation is finished, @callback will be called.  You can then
3930  * call e_source_remote_delete_finish() to get the result of the operation.
3931  *
3932  * Since: 3.6
3933  **/
3934 void
e_source_remote_delete(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)3935 e_source_remote_delete (ESource *source,
3936                         GCancellable *cancellable,
3937                         GAsyncReadyCallback callback,
3938                         gpointer user_data)
3939 {
3940 	ESourceClass *class;
3941 
3942 	g_return_if_fail (E_IS_SOURCE (source));
3943 
3944 	class = E_SOURCE_GET_CLASS (source);
3945 	g_return_if_fail (class != NULL);
3946 	g_return_if_fail (class->remote_delete != NULL);
3947 
3948 	class->remote_delete (source, cancellable, callback, user_data);
3949 }
3950 
3951 /**
3952  * e_source_remote_delete_finish:
3953  * @source: an #ESource
3954  * @result: a #GAsyncResult
3955  * @error: return location for a #GError, or %NULL
3956  *
3957  * Finishes the operation started with e_source_remote_delete().  If
3958  * an error occurred, the function will set @error and return %FALSE.
3959  *
3960  * Returns: %TRUE on success, %FALSE on error
3961  *
3962  * Since: 3.6
3963  **/
3964 gboolean
e_source_remote_delete_finish(ESource * source,GAsyncResult * result,GError ** error)3965 e_source_remote_delete_finish (ESource *source,
3966                                GAsyncResult *result,
3967                                GError **error)
3968 {
3969 	ESourceClass *class;
3970 
3971 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
3972 
3973 	class = E_SOURCE_GET_CLASS (source);
3974 	g_return_val_if_fail (class != NULL, FALSE);
3975 	g_return_val_if_fail (class->remote_delete_finish != NULL, FALSE);
3976 
3977 	return class->remote_delete_finish (source, result, error);
3978 }
3979 
3980 /**
3981  * e_source_get_oauth2_access_token_sync:
3982  * @source: an #ESource
3983  * @cancellable: optional #GCancellable object, or %NULL
3984  * @out_access_token: (optional) (out): return location for the access token,
3985  *                    or %NULL
3986  * @out_expires_in: (optional) (out): return location for the token expiry,
3987  *                  or %NULL
3988  * @error: return location for a #GError, or %NULL
3989  *
3990  * Obtains the OAuth 2.0 access token for @source along with its expiry
3991  * in seconds from the current time (or 0 if unknown).
3992  *
3993  * Free the returned access token with g_free() when finished with it.
3994  * If an error occurs, the function will set @error and return %FALSE.
3995  *
3996  * Returns: %TRUE on success, %FALSE on error
3997  *
3998  * Since: 3.8
3999  **/
4000 gboolean
e_source_get_oauth2_access_token_sync(ESource * source,GCancellable * cancellable,gchar ** out_access_token,gint * out_expires_in,GError ** error)4001 e_source_get_oauth2_access_token_sync (ESource *source,
4002                                        GCancellable *cancellable,
4003                                        gchar **out_access_token,
4004                                        gint *out_expires_in,
4005                                        GError **error)
4006 {
4007 	ESourceClass *class;
4008 
4009 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4010 
4011 	class = E_SOURCE_GET_CLASS (source);
4012 	g_return_val_if_fail (class != NULL, FALSE);
4013 	g_return_val_if_fail (class->get_oauth2_access_token_sync != NULL, FALSE);
4014 
4015 	return class->get_oauth2_access_token_sync (
4016 		source, cancellable, out_access_token, out_expires_in, error);
4017 }
4018 
4019 /**
4020  * e_source_get_oauth2_access_token:
4021  * @source: an #ESource
4022  * @cancellable: optional #GCancellable object, or %NULL
4023  * @callback: a #GAsyncReadyCallback to call when the request
4024  *            is satisfied
4025  * @user_data: data to pass to the callback function
4026  *
4027  * Asynchronously obtains the OAuth 2.0 access token for @source along
4028  * with its expiry in seconds from the current time (or 0 if unknown).
4029  *
4030  * When the operation is finished, @callback will be called.  You can then
4031  * call e_source_get_oauth2_access_token_finish() to get the result of the
4032  * operation.
4033  *
4034  * Since: 3.8
4035  **/
4036 void
e_source_get_oauth2_access_token(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4037 e_source_get_oauth2_access_token (ESource *source,
4038                                   GCancellable *cancellable,
4039                                   GAsyncReadyCallback callback,
4040                                   gpointer user_data)
4041 {
4042 	ESourceClass *class;
4043 
4044 	g_return_if_fail (E_IS_SOURCE (source));
4045 
4046 	class = E_SOURCE_GET_CLASS (source);
4047 	g_return_if_fail (class != NULL);
4048 	g_return_if_fail (class->get_oauth2_access_token != NULL);
4049 
4050 	return class->get_oauth2_access_token (
4051 		source, cancellable, callback, user_data);
4052 }
4053 
4054 /**
4055  * e_source_get_oauth2_access_token_finish:
4056  * @source: an #ESource
4057  * @result: a #GAsyncResult
4058  * @out_access_token: (optional) (out): return location for the access token,
4059  *                    or %NULL
4060  * @out_expires_in: (optional) (out): return location for the token expiry,
4061  *                  or %NULL
4062  * @error: return location for a #GError, or %NULL
4063  *
4064  * Finishes the operation started with e_source_get_oauth2_access_token().
4065  *
4066  * Free the returned access token with g_free() when finished with it.
4067  * If an error occurred, the function will set @error and return %FALSE.
4068  *
4069  * Returns: %TRUE on success, %FALSE on error
4070  *
4071  * Since: 3.8
4072  **/
4073 gboolean
e_source_get_oauth2_access_token_finish(ESource * source,GAsyncResult * result,gchar ** out_access_token,gint * out_expires_in,GError ** error)4074 e_source_get_oauth2_access_token_finish (ESource *source,
4075                                          GAsyncResult *result,
4076                                          gchar **out_access_token,
4077                                          gint *out_expires_in,
4078                                          GError **error)
4079 {
4080 	ESourceClass *class;
4081 
4082 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4083 	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
4084 
4085 	class = E_SOURCE_GET_CLASS (source);
4086 	g_return_val_if_fail (class != NULL, FALSE);
4087 	g_return_val_if_fail (class->get_oauth2_access_token_finish != NULL, FALSE);
4088 
4089 	return class->get_oauth2_access_token_finish (
4090 		source, result, out_access_token, out_expires_in, error);
4091 }
4092 
4093 /**
4094  * e_source_store_password_sync:
4095  * @source: an #ESource
4096  * @password: the password to store
4097  * @permanently: store permanently or just for the session
4098  * @cancellable: optional #GCancellable object, or %NULL
4099  * @error: return location for a #GError, or %NULL
4100  *
4101  * Stores a password for @source.  This operation does not rely on the
4102  * registry service and therefore works for any #ESource -- registered
4103  * or "scratch".
4104  *
4105  * If @permanently is %TRUE, the password is stored in the default keyring.
4106  * Otherwise the password is stored in the memory-only session keyring.  If
4107  * an error occurs, the function sets @error and returns %FALSE.
4108  *
4109  * Returns: %TRUE on success, %FALSE on error
4110  *
4111  * Since: 3.12
4112  **/
4113 gboolean
e_source_store_password_sync(ESource * source,const gchar * password,gboolean permanently,GCancellable * cancellable,GError ** error)4114 e_source_store_password_sync (ESource *source,
4115                               const gchar *password,
4116                               gboolean permanently,
4117                               GCancellable *cancellable,
4118                               GError **error)
4119 {
4120 	gboolean success;
4121 	const gchar *uid;
4122 	gchar *label;
4123 
4124 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4125 	g_return_val_if_fail (password != NULL, FALSE);
4126 
4127 	uid = e_source_get_uid (source);
4128 	label = e_source_dup_secret_label (source);
4129 
4130 	success = e_secret_store_store_sync (uid, password, label, permanently, cancellable, error);
4131 
4132 	g_free (label);
4133 
4134 	return success;
4135 }
4136 
4137 /* Helper for e_source_store_password() */
4138 static void
source_store_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4139 source_store_password_thread (GTask *task,
4140                               gpointer source_object,
4141                               gpointer task_data,
4142                               GCancellable *cancellable)
4143 {
4144 	gboolean success;
4145 	AsyncContext *async_context;
4146 	GError *local_error = NULL;
4147 
4148 	async_context = (AsyncContext *) task_data;
4149 
4150 	success = e_source_store_password_sync (
4151 		E_SOURCE (source_object),
4152 		async_context->password,
4153 		async_context->permanently,
4154 		cancellable, &local_error);
4155 
4156 	if (local_error != NULL) {
4157 		g_task_return_error (task, local_error);
4158 	} else {
4159 		g_task_return_boolean (task, success);
4160 	}
4161 }
4162 
4163 /**
4164  * e_source_store_password:
4165  * @source: an #ESource
4166  * @password: the password to store
4167  * @permanently: store permanently or just for the session
4168  * @cancellable: optional #GCancellable object, or %NULL
4169  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4170  * @user_data: data to pass to the callback function
4171  *
4172  * Asynchronously stores a password for @source.  This operation does
4173  * not rely on the registry service and therefore works for any #ESource
4174  * -- registered or "scratch".
4175  *
4176  * If @permanently is %TRUE, the password is stored in the default keyring.
4177  * Otherwise the password is stored in the memory-only session keyring.  If
4178  * an error occurs, the function sets @error and returns %FALSE.
4179  *
4180  * When the operation is finished, @callback will be called.  You can then
4181  * call e_source_store_password_finish() to get the result of the operation.
4182  *
4183  * Since: 3.12
4184  **/
4185 void
e_source_store_password(ESource * source,const gchar * password,gboolean permanently,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4186 e_source_store_password (ESource *source,
4187                          const gchar *password,
4188                          gboolean permanently,
4189                          GCancellable *cancellable,
4190                          GAsyncReadyCallback callback,
4191                          gpointer user_data)
4192 {
4193 	GTask *task;
4194 	AsyncContext *async_context;
4195 
4196 	g_return_if_fail (E_IS_SOURCE (source));
4197 	g_return_if_fail (password != NULL);
4198 
4199 	async_context = g_slice_new0 (AsyncContext);
4200 	async_context->password = g_strdup (password);
4201 	async_context->permanently = permanently;
4202 
4203 	task = g_task_new (source, cancellable, callback, user_data);
4204 	g_task_set_source_tag (task, e_source_store_password);
4205 
4206 	g_task_set_task_data (
4207 		task, async_context,
4208 		(GDestroyNotify) async_context_free);
4209 
4210 	g_task_run_in_thread (task, source_store_password_thread);
4211 
4212 	g_object_unref (task);
4213 }
4214 
4215 /**
4216  * e_source_store_password_finish:
4217  * @source: an #ESource
4218  * @result: a #GAsyncResult
4219  * @error: return location for a #GError, or %NULL
4220  *
4221  * Finishes the operation started with e_source_store_password().
4222  *
4223  * Returns: %TRUE on success, %FALSE on error
4224  *
4225  * Since: 3.12
4226  **/
4227 gboolean
e_source_store_password_finish(ESource * source,GAsyncResult * result,GError ** error)4228 e_source_store_password_finish (ESource *source,
4229                                 GAsyncResult *result,
4230                                 GError **error)
4231 {
4232 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4233 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4234 
4235 	g_return_val_if_fail (
4236 		g_async_result_is_tagged (
4237 		result, e_source_store_password), FALSE);
4238 
4239 	return g_task_propagate_boolean (G_TASK (result), error);
4240 }
4241 
4242 /**
4243  * e_source_lookup_password_sync:
4244  * @source: an #ESource
4245  * @cancellable: optional #GCancellable object, or %NULL
4246  * @out_password: (out) (optional) (nullable): return location for the password, or %NULL
4247  * @error: return location for a #GError, or %NULL
4248  *
4249  * Looks up a password for @source.  Both the default and session keyrings
4250  * are queried.  This operation does not rely on the registry service and
4251  * therefore works for any #ESource -- registered or "scratch".
4252  *
4253  * Note the boolean return value indicates whether the lookup operation
4254  * itself completed successfully, not whether a password was found.  If
4255  * no password was found, the function will set @out_password to %NULL
4256  * but still return %TRUE.  If an error occurs, the function sets @error
4257  * and returns %FALSE.
4258  *
4259  * Returns: %TRUE on success, %FALSE on error
4260  *
4261  * Since: 3.12
4262  **/
4263 gboolean
e_source_lookup_password_sync(ESource * source,GCancellable * cancellable,gchar ** out_password,GError ** error)4264 e_source_lookup_password_sync (ESource *source,
4265                                GCancellable *cancellable,
4266                                gchar **out_password,
4267                                GError **error)
4268 {
4269 	const gchar *uid;
4270 
4271 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4272 
4273 	uid = e_source_get_uid (source);
4274 
4275 	return e_secret_store_lookup_sync (uid, out_password, cancellable, error);
4276 }
4277 
4278 /* Helper for e_source_lookup_password() */
4279 static void
source_lookup_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4280 source_lookup_password_thread (GTask *task,
4281                                gpointer source_object,
4282                                gpointer task_data,
4283                                GCancellable *cancellable)
4284 {
4285 	gboolean success;
4286 	AsyncContext *async_context;
4287 	GError *local_error = NULL;
4288 
4289 	async_context = (AsyncContext *) task_data;
4290 
4291 	success = e_source_lookup_password_sync (
4292 		E_SOURCE (source_object),
4293 		cancellable,
4294 		&async_context->password,
4295 		&local_error);
4296 
4297 	if (local_error != NULL) {
4298 		g_task_return_error (task, local_error);
4299 	} else {
4300 		g_task_return_boolean (task, success);
4301 	}
4302 }
4303 
4304 /**
4305  * e_source_lookup_password:
4306  * @source: an #ESource
4307  * @cancellable: optional #GCancellable object, or %NULL
4308  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4309  * @user_data: data to pass to the callback function
4310  *
4311  * Asynchronously looks up a password for @source.  Both the default and
4312  * session keyrings are queried.  This operation does not rely on the
4313  * registry service and therefore works for any #ESource -- registered
4314  * or "scratch".
4315  *
4316  * When the operation is finished, @callback will be called.  You can then
4317  * call e_source_lookup_password_finish() to get the result of the operation.
4318  *
4319  * Since: 3.12
4320  **/
4321 void
e_source_lookup_password(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4322 e_source_lookup_password (ESource *source,
4323                           GCancellable *cancellable,
4324                           GAsyncReadyCallback callback,
4325                           gpointer user_data)
4326 {
4327 	GTask *task;
4328 	AsyncContext *async_context;
4329 
4330 	g_return_if_fail (E_IS_SOURCE (source));
4331 
4332 	async_context = g_slice_new0 (AsyncContext);
4333 
4334 	task = g_task_new (source, cancellable, callback, user_data);
4335 	g_task_set_source_tag (task, e_source_lookup_password);
4336 
4337 	g_task_set_task_data (
4338 		task, async_context,
4339 		(GDestroyNotify) async_context_free);
4340 
4341 	g_task_run_in_thread (task, source_lookup_password_thread);
4342 
4343 	g_object_unref (task);
4344 }
4345 
4346 /**
4347  * e_source_lookup_password_finish:
4348  * @source: an #ESource
4349  * @result: a #GAsyncResult
4350  * @out_password: (out) (optional) (nullable): return location for the password, or %NULL
4351  * @error: return location for a #GError, or %NULL
4352  *
4353  * Finishes the operation started with e_source_lookup_password().
4354  *
4355  * Note the boolean return value indicates whether the lookup operation
4356  * itself completed successfully, not whether a password was found.  If
4357  * no password was found, the function will set @out_password to %NULL
4358  * but still return %TRUE.  If an error occurs, the function sets @error
4359  * and returns %FALSE.
4360  *
4361  * Returns: %TRUE on success, %FALSE on error
4362  *
4363  * Since: 3.12
4364  **/
4365 gboolean
e_source_lookup_password_finish(ESource * source,GAsyncResult * result,gchar ** out_password,GError ** error)4366 e_source_lookup_password_finish (ESource *source,
4367                                  GAsyncResult *result,
4368                                  gchar **out_password,
4369                                  GError **error)
4370 {
4371 	AsyncContext *async_context;
4372 
4373 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4374 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4375 
4376 	g_return_val_if_fail (
4377 		g_async_result_is_tagged (
4378 		result, e_source_lookup_password), FALSE);
4379 
4380 	async_context = g_task_get_task_data (G_TASK (result));
4381 
4382 	if (!g_task_had_error (G_TASK (result))) {
4383 		if (out_password != NULL) {
4384 			*out_password = async_context->password;
4385 			async_context->password = NULL;
4386 		}
4387 	}
4388 
4389 	return g_task_propagate_boolean (G_TASK (result), error);
4390 }
4391 
4392 /**
4393  * e_source_delete_password_sync:
4394  * @source: an #ESource
4395  * @cancellable: optional #GCancellable object, or %NULL
4396  * @error: return location for a #GError, or %NULL
4397  *
4398  * Deletes the password for @source from either the default keyring or
4399  * session keyring.  This operation does not rely on the registry service
4400  * and therefore works for any #ESource -- registered or "scratch".
4401  *
4402  * Note the boolean return value indicates whether the delete operation
4403  * itself completed successfully, not whether a password was found and
4404  * deleted.  If no password was found, the function will still return
4405  * %TRUE.  If an error occurs, the function sets @error and returns %FALSE.
4406  *
4407  * Returns: %TRUE on success, %FALSE on error
4408  *
4409  * Since: 3.12
4410  **/
4411 gboolean
e_source_delete_password_sync(ESource * source,GCancellable * cancellable,GError ** error)4412 e_source_delete_password_sync (ESource *source,
4413                                GCancellable *cancellable,
4414                                GError **error)
4415 {
4416 	const gchar *uid;
4417 
4418 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4419 
4420 	uid = e_source_get_uid (source);
4421 
4422 	return e_secret_store_delete_sync (uid, cancellable, error);
4423 }
4424 
4425 /* Helper for e_source_delete_password() */
4426 static void
source_delete_password_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4427 source_delete_password_thread (GTask *task,
4428                                gpointer source_object,
4429                                gpointer task_data,
4430                                GCancellable *cancellable)
4431 {
4432 	gboolean success;
4433 	GError *local_error = NULL;
4434 
4435 	success = e_source_delete_password_sync (
4436 		E_SOURCE (source_object),
4437 		cancellable, &local_error);
4438 
4439 	if (local_error != NULL) {
4440 		g_task_return_error (task, local_error);
4441 	} else {
4442 		g_task_return_boolean (task, success);
4443 	}
4444 }
4445 
4446 /**
4447  * e_source_delete_password:
4448  * @source: an #ESource
4449  * @cancellable: optional #GCancellable object, or %NULL
4450  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4451  * @user_data: data to pass to the callback function
4452  *
4453  * Asynchronously deletes the password for @source from either the default
4454  * keyring or session keyring.  This operation does not rely on the registry
4455  * service and therefore works for any #ESource -- registered or "scratch".
4456  *
4457  * When the operation is finished, @callback will be called.  You can then
4458  * call e_source_delete_password_finish() to get the result of the operation.
4459  *
4460  * Since: 3.12
4461  **/
4462 void
e_source_delete_password(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4463 e_source_delete_password (ESource *source,
4464                           GCancellable *cancellable,
4465                           GAsyncReadyCallback callback,
4466                           gpointer user_data)
4467 {
4468 	GTask *task;
4469 
4470 	g_return_if_fail (E_IS_SOURCE (source));
4471 
4472 	task = g_task_new (source, cancellable, callback, user_data);
4473 	g_task_set_source_tag (task, e_source_delete_password);
4474 
4475 	g_task_run_in_thread (task, source_delete_password_thread);
4476 
4477 	g_object_unref (task);
4478 }
4479 
4480 /**
4481  * e_source_delete_password_finish:
4482  * @source: an #ESource
4483  * @result: a #GAsyncResult
4484  * @error: return location for a #GError, or %NULL
4485  *
4486  * Finishes the operation started with e_source_delete_password().
4487  *
4488  * Note the boolean return value indicates whether the delete operation
4489  * itself completed successfully, not whether a password was found and
4490  * deleted.  If no password was found, the function will still return
4491  * %TRUE.  If an error occurs, the function sets @error and returns %FALSE.
4492  *
4493  * Returns: %TRUE on success, %FALSE on error
4494  *
4495  * Since: 3.12
4496  **/
4497 gboolean
e_source_delete_password_finish(ESource * source,GAsyncResult * result,GError ** error)4498 e_source_delete_password_finish (ESource *source,
4499                                  GAsyncResult *result,
4500                                  GError **error)
4501 {
4502 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4503 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4504 
4505 	g_return_val_if_fail (
4506 		g_async_result_is_tagged (
4507 		result, e_source_delete_password), FALSE);
4508 
4509 	return g_task_propagate_boolean (G_TASK (result), error);
4510 }
4511 
4512 /**
4513  * e_source_invoke_credentials_required_sync:
4514  * @source: an #ESource
4515  * @reason: an #ESourceCredentialsReason, why the credentials are required
4516  * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4517  * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4518  * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4519  * @cancellable: optional #GCancellable object, or %NULL
4520  * @error: return location for a #GError, or %NULL
4521  *
4522  * Let's the client-side know that credentials are required. The @reason defines which
4523  * parameters are used. The client passed the credentials with an e_source_invoke_authenticate()
4524  * call.
4525  *
4526  * The %E_SOURCE_CREDENTIALS_REASON_REQUIRED is used for the first credentials prompt,
4527  * when the client can return credentials as stored from the previous success login.
4528  *
4529  * The %E_SOURCE_CREDENTIALS_REASON_REJECTED is used when the previously used credentials
4530  * had been rejected by the server. That usually means that the user should be asked
4531  * to provide/correct the credentials.
4532  *
4533  * The %E_SOURCE_CREDENTIALS_REASON_SSL_FAILED is used when a secured connection failed
4534  * due to some server-side certificate issues.
4535  *
4536  * The %E_SOURCE_CREDENTIALS_REASON_ERROR is used when the server returned an error.
4537  * It is not possible to connect to it at the moment usually.
4538  *
4539  * If an error occurs, the function sets @error and returns %FALSE.
4540  *
4541  * Returns: %TRUE on success, %FALSE on error
4542  *
4543  * Since: 3.16
4544  **/
4545 gboolean
e_source_invoke_credentials_required_sync(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error,GCancellable * cancellable,GError ** error)4546 e_source_invoke_credentials_required_sync (ESource *source,
4547 					   ESourceCredentialsReason reason,
4548 					   const gchar *certificate_pem,
4549 					   GTlsCertificateFlags certificate_errors,
4550 					   const GError *op_error,
4551 					   GCancellable *cancellable,
4552 					   GError **error)
4553 {
4554 	GDBusObject *dbus_object;
4555 	EDBusSource *dbus_source = NULL;
4556 	ESourceClass *klass;
4557 	gchar *arg_reason, *arg_certificate_errors;
4558 	GEnumClass *enum_class;
4559 	GEnumValue *enum_value;
4560 	GFlagsClass *flags_class;
4561 	GFlagsValue *flags_value;
4562 	GString *certificate_errors_str;
4563 	gchar *dbus_error_name = NULL;
4564 	GError *local_error = NULL;
4565 
4566 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4567 
4568 	klass = E_SOURCE_GET_CLASS (source);
4569 	g_return_val_if_fail (klass != NULL, FALSE);
4570 	g_return_val_if_fail (klass->invoke_credentials_required_impl != NULL, FALSE);
4571 
4572 	dbus_object = e_source_ref_dbus_object (source);
4573 	if (dbus_object != NULL) {
4574 		dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
4575 		g_object_unref (dbus_object);
4576 	}
4577 
4578 	if (!dbus_source) {
4579 		g_warn_if_fail (dbus_source != NULL);
4580 		return FALSE;
4581 	}
4582 
4583 	enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
4584 	enum_value = g_enum_get_value (enum_class, reason);
4585 
4586 	g_return_val_if_fail (enum_value != NULL, FALSE);
4587 
4588 	arg_reason = g_strdup (enum_value->value_nick);
4589 	g_type_class_unref (enum_class);
4590 
4591 	certificate_errors_str = g_string_new ("");
4592 
4593 	flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
4594 	for (flags_value = g_flags_get_first_value (flags_class, certificate_errors);
4595 	     flags_value;
4596 	     flags_value = g_flags_get_first_value (flags_class, certificate_errors)) {
4597 		if (certificate_errors_str->len)
4598 			g_string_append_c (certificate_errors_str, ':');
4599 		g_string_append (certificate_errors_str, flags_value->value_nick);
4600 		certificate_errors &= ~flags_value->value;
4601 	}
4602 	g_type_class_unref (flags_class);
4603 
4604 	arg_certificate_errors = g_string_free (certificate_errors_str, FALSE);
4605 
4606 	if (reason == E_SOURCE_CREDENTIALS_REASON_SSL_FAILED)
4607 		e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
4608 	else if (reason != E_SOURCE_CREDENTIALS_REASON_ERROR)
4609 		e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS);
4610 
4611 	if (op_error)
4612 		dbus_error_name = g_dbus_error_encode_gerror (op_error);
4613 
4614 	klass->invoke_credentials_required_impl (source, dbus_source,
4615 			arg_reason ? arg_reason : "",
4616 			certificate_pem ? certificate_pem : "",
4617 			arg_certificate_errors ? arg_certificate_errors : "",
4618 			dbus_error_name ? dbus_error_name : "",
4619 			op_error ? op_error->message : "",
4620 			cancellable, &local_error);
4621 
4622 	g_free (arg_reason);
4623 	g_free (arg_certificate_errors);
4624 	g_free (dbus_error_name);
4625 	g_object_unref (dbus_source);
4626 
4627 	if (local_error != NULL) {
4628 		g_dbus_error_strip_remote_error (local_error);
4629 		g_propagate_error (error, local_error);
4630 		return FALSE;
4631 	}
4632 
4633 	return TRUE;
4634 }
4635 
4636 typedef struct _InvokeCredentialsRequiredData {
4637 	ESourceCredentialsReason reason;
4638 	gchar *certificate_pem;
4639 	GTlsCertificateFlags certificate_errors;
4640 	GError *op_error;
4641 } InvokeCredentialsRequiredData;
4642 
4643 static void
invoke_credentials_required_data_free(gpointer ptr)4644 invoke_credentials_required_data_free (gpointer ptr)
4645 {
4646 	InvokeCredentialsRequiredData *data = ptr;
4647 
4648 	if (data) {
4649 		g_free (data->certificate_pem);
4650 		g_clear_error (&data->op_error);
4651 		g_slice_free (InvokeCredentialsRequiredData, data);
4652 	}
4653 }
4654 
4655 static void
source_invoke_credentials_required_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4656 source_invoke_credentials_required_thread (GTask *task,
4657 					   gpointer source_object,
4658 					   gpointer task_data,
4659 					   GCancellable *cancellable)
4660 {
4661 	InvokeCredentialsRequiredData *data = task_data;
4662 	gboolean success;
4663 	GError *local_error = NULL;
4664 
4665 	success = e_source_invoke_credentials_required_sync (
4666 		E_SOURCE (source_object), data->reason, data->certificate_pem,
4667 		data->certificate_errors, data->op_error,
4668 		cancellable, &local_error);
4669 
4670 	if (local_error != NULL) {
4671 		g_task_return_error (task, local_error);
4672 	} else {
4673 		g_task_return_boolean (task, success);
4674 	}
4675 }
4676 
4677 /**
4678  * e_source_invoke_credentials_required:
4679  * @source: an #ESource
4680  * @reason: an #ESourceCredentialsReason, why the credentials are required
4681  * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4682  * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4683  * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4684  * @cancellable: optional #GCancellable object, or %NULL
4685  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4686  * @user_data: data to pass to the callback function
4687  *
4688  * Asynchronously calls the InvokeCredentialsRequired method on the server side,
4689  * to inform clients that credentials are required.
4690  *
4691  * When the operation is finished, @callback will be called. You can then
4692  * call e_source_invoke_credentials_required_finish() to get the result of the operation.
4693  *
4694  * Since: 3.16
4695  **/
4696 void
e_source_invoke_credentials_required(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4697 e_source_invoke_credentials_required (ESource *source,
4698 				      ESourceCredentialsReason reason,
4699 				      const gchar *certificate_pem,
4700 				      GTlsCertificateFlags certificate_errors,
4701 				      const GError *op_error,
4702 				      GCancellable *cancellable,
4703 				      GAsyncReadyCallback callback,
4704 				      gpointer user_data)
4705 {
4706 	InvokeCredentialsRequiredData *data;
4707 	GTask *task;
4708 
4709 	g_return_if_fail (E_IS_SOURCE (source));
4710 
4711 	data = g_slice_new0 (InvokeCredentialsRequiredData);
4712 	data->reason = reason;
4713 	data->certificate_pem = g_strdup (certificate_pem);
4714 	data->certificate_errors = certificate_errors;
4715 	data->op_error = op_error ? g_error_copy (op_error) : NULL;
4716 
4717 	task = g_task_new (source, cancellable, callback, user_data);
4718 	g_task_set_source_tag (task, e_source_invoke_credentials_required);
4719 	g_task_set_task_data (task, data, invoke_credentials_required_data_free);
4720 
4721 	g_task_run_in_thread (task, source_invoke_credentials_required_thread);
4722 
4723 	g_object_unref (task);
4724 }
4725 
4726 /**
4727  * e_source_invoke_credentials_required_finish:
4728  * @source: an #ESource
4729  * @result: a #GAsyncResult
4730  * @error: return location for a #GError, or %NULL
4731  *
4732  * Finishes the operation started with e_source_invoke_credentials_required().
4733  *
4734  * If an error occurs, the function sets @error and returns %FALSE.
4735  *
4736  * Returns: %TRUE on success, %FALSE on error
4737  *
4738  * Since: 3.16
4739  **/
4740 gboolean
e_source_invoke_credentials_required_finish(ESource * source,GAsyncResult * result,GError ** error)4741 e_source_invoke_credentials_required_finish (ESource *source,
4742 					     GAsyncResult *result,
4743 					     GError **error)
4744 {
4745 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4746 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4747 
4748 	g_return_val_if_fail (
4749 		g_async_result_is_tagged (
4750 		result, e_source_invoke_credentials_required), FALSE);
4751 
4752 	return g_task_propagate_boolean (G_TASK (result), error);
4753 }
4754 
4755 /**
4756  * e_source_invoke_authenticate_sync:
4757  * @source: an #ESource
4758  * @credentials: (nullable): an #ENamedParameters structure with credentials to use; can be %NULL
4759  *    to use those from the last call
4760  * @cancellable: optional #GCancellable object, or %NULL
4761  * @error: return location for a #GError, or %NULL
4762  *
4763  * Calls the InvokeAuthenticate method on the server side, thus the backend
4764  * knows what credentials to use to connect to its (possibly remote) data store.
4765  *
4766  * If an error occurs, the function sets @error and returns %FALSE.
4767  *
4768  * Returns: %TRUE on success, %FALSE on error
4769  *
4770  * Since: 3.16
4771  **/
4772 gboolean
e_source_invoke_authenticate_sync(ESource * source,const ENamedParameters * credentials,GCancellable * cancellable,GError ** error)4773 e_source_invoke_authenticate_sync (ESource *source,
4774 				   const ENamedParameters *credentials,
4775 				   GCancellable *cancellable,
4776 				   GError **error)
4777 {
4778 	GDBusObject *dbus_object;
4779 	EDBusSource *dbus_source = NULL;
4780 	ESourceClass *klass;
4781 	gchar **credentials_strv;
4782 	gboolean success;
4783 	GError *local_error = NULL;
4784 
4785 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4786 
4787 	klass = E_SOURCE_GET_CLASS (source);
4788 	g_return_val_if_fail (klass != NULL, FALSE);
4789 	g_return_val_if_fail (klass->invoke_authenticate_impl != NULL, FALSE);
4790 
4791 	dbus_object = e_source_ref_dbus_object (source);
4792 	if (dbus_object != NULL) {
4793 		dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
4794 		g_object_unref (dbus_object);
4795 	}
4796 
4797 	if (!dbus_source) {
4798 		g_warn_if_fail (dbus_source != NULL);
4799 		return FALSE;
4800 	}
4801 
4802 	if (credentials) {
4803 		if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND) &&
4804 		    !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_SSL_TRUST)) {
4805 			ENamedParameters *clone;
4806 			ESourceWebdav *webdav_extension;
4807 
4808 			clone = e_named_parameters_new_clone (credentials);
4809 
4810 			webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
4811 			e_named_parameters_set (clone, E_SOURCE_CREDENTIAL_SSL_TRUST,
4812 				e_source_webdav_get_ssl_trust (webdav_extension));
4813 
4814 			credentials_strv = e_named_parameters_to_strv (clone);
4815 
4816 			e_named_parameters_free (clone);
4817 		} else {
4818 			credentials_strv = e_named_parameters_to_strv (credentials);
4819 		}
4820 	} else {
4821 		ENamedParameters *empty_credentials;
4822 
4823 		empty_credentials = e_named_parameters_new ();
4824 		credentials_strv = e_named_parameters_to_strv (empty_credentials);
4825 		e_named_parameters_free (empty_credentials);
4826 	}
4827 
4828 	success = klass->invoke_authenticate_impl (source, dbus_source, (const gchar * const *) credentials_strv, cancellable, &local_error);
4829 
4830 	g_strfreev (credentials_strv);
4831 	g_object_unref (dbus_source);
4832 
4833 	if (local_error != NULL) {
4834 		g_dbus_error_strip_remote_error (local_error);
4835 		g_propagate_error (error, local_error);
4836 		return FALSE;
4837 	}
4838 
4839 	return success;
4840 }
4841 
4842 static void
source_invoke_authenticate_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)4843 source_invoke_authenticate_thread (GTask *task,
4844 				   gpointer source_object,
4845 				   gpointer task_data,
4846 				   GCancellable *cancellable)
4847 {
4848 	gboolean success;
4849 	GError *local_error = NULL;
4850 
4851 	success = e_source_invoke_authenticate_sync (
4852 		E_SOURCE (source_object), task_data,
4853 		cancellable, &local_error);
4854 
4855 	if (local_error != NULL) {
4856 		g_task_return_error (task, local_error);
4857 	} else {
4858 		g_task_return_boolean (task, success);
4859 	}
4860 }
4861 
4862 /**
4863  * e_source_invoke_authenticate:
4864  * @source: an #ESource
4865  * @credentials: (nullable): an #ENamedParameters structure with credentials to use; can be %NULL
4866  *    to use those from the last call
4867  * @cancellable: optional #GCancellable object, or %NULL
4868  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4869  * @user_data: data to pass to the callback function
4870  *
4871  * Asynchronously calls the InvokeAuthenticate method on the server side,
4872  * thus the backend knows what credentials to use to connect to its (possibly
4873  * remote) data store.
4874  *
4875  * When the operation is finished, @callback will be called. You can then
4876  * call e_source_invoke_authenticate_finish() to get the result of the operation.
4877  *
4878  * Since: 3.16
4879  **/
4880 void
e_source_invoke_authenticate(ESource * source,const ENamedParameters * credentials,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)4881 e_source_invoke_authenticate (ESource *source,
4882 			      const ENamedParameters *credentials,
4883 			      GCancellable *cancellable,
4884 			      GAsyncReadyCallback callback,
4885 			      gpointer user_data)
4886 {
4887 	ENamedParameters *credentials_copy;
4888 	GTask *task;
4889 
4890 	g_return_if_fail (E_IS_SOURCE (source));
4891 
4892 	credentials_copy = e_named_parameters_new_clone (credentials);
4893 
4894 	task = g_task_new (source, cancellable, callback, user_data);
4895 	g_task_set_source_tag (task, e_source_invoke_authenticate);
4896 	g_task_set_task_data (task, credentials_copy, (GDestroyNotify) e_named_parameters_free);
4897 
4898 	g_task_run_in_thread (task, source_invoke_authenticate_thread);
4899 
4900 	g_object_unref (task);
4901 }
4902 
4903 /**
4904  * e_source_invoke_authenticate_finish:
4905  * @source: an #ESource
4906  * @result: a #GAsyncResult
4907  * @error: return location for a #GError, or %NULL
4908  *
4909  * Finishes the operation started with e_source_invoke_authenticate().
4910  *
4911  * If an error occurs, the function sets @error and returns %FALSE.
4912  *
4913  * Returns: %TRUE on success, %FALSE on error
4914  *
4915  * Since: 3.16
4916  **/
4917 gboolean
e_source_invoke_authenticate_finish(ESource * source,GAsyncResult * result,GError ** error)4918 e_source_invoke_authenticate_finish (ESource *source,
4919 				     GAsyncResult *result,
4920 				     GError **error)
4921 {
4922 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4923 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
4924 
4925 	g_return_val_if_fail (
4926 		g_async_result_is_tagged (
4927 		result, e_source_invoke_authenticate), FALSE);
4928 
4929 	return g_task_propagate_boolean (G_TASK (result), error);
4930 }
4931 
4932 /**
4933  * e_source_emit_credentials_required:
4934  * @source: an #ESource
4935  * @reason: an #ESourceCredentialsReason, why the credentials are required
4936  * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
4937  * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
4938  * @op_error: (nullable): a #GError with a description of the previous credentials error, or %NULL
4939  *
4940  * Emits localy (in this process only) the ESource::credentials-required
4941  * signal with given parameters. That's the difference with e_source_invoke_credentials_required(),
4942  * which calls the signal globally, within each client.
4943  *
4944  * Since: 3.16
4945  **/
4946 void
e_source_emit_credentials_required(ESource * source,ESourceCredentialsReason reason,const gchar * certificate_pem,GTlsCertificateFlags certificate_errors,const GError * op_error)4947 e_source_emit_credentials_required (ESource *source,
4948 				    ESourceCredentialsReason reason,
4949 				    const gchar *certificate_pem,
4950 				    GTlsCertificateFlags certificate_errors,
4951 				    const GError *op_error)
4952 {
4953 	g_return_if_fail (E_IS_SOURCE (source));
4954 
4955 	g_signal_emit (source, signals[CREDENTIALS_REQUIRED], 0, reason, certificate_pem, certificate_errors, op_error);
4956 }
4957 
4958 /**
4959  * e_source_get_last_credentials_required_arguments_sync:
4960  * @source: an #ESource
4961  * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
4962  * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
4963  * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
4964  * @out_op_error: (out): a #GError with a description of the previous credentials error
4965  * @cancellable: optional #GCancellable object, or %NULL
4966  * @error: return location for a #GError, or %NULL
4967  *
4968  * Retrieves the last used arguments of the 'credentials-required' signal emission.
4969  * If there was none emitted yet, or a corresponding 'authenitcate' had been emitted
4970  * already, then the @out_reason is set to #E_SOURCE_CREDENTIALS_REASON_UNKNOWN
4971  * and the value of other 'out' arguments is set to no values.
4972  *
4973  * If an error occurs, the function sets @error and returns %FALSE. The result gchar
4974  * values should be freed with g_free() when no longer needed.
4975  *
4976  * Returns: %TRUE on success, %FALSE on error
4977  *
4978  * Since: 3.16
4979  **/
4980 gboolean
e_source_get_last_credentials_required_arguments_sync(ESource * source,ESourceCredentialsReason * out_reason,gchar ** out_certificate_pem,GTlsCertificateFlags * out_certificate_errors,GError ** out_op_error,GCancellable * cancellable,GError ** error)4981 e_source_get_last_credentials_required_arguments_sync (ESource *source,
4982 						       ESourceCredentialsReason *out_reason,
4983 						       gchar **out_certificate_pem,
4984 						       GTlsCertificateFlags *out_certificate_errors,
4985 						       GError **out_op_error,
4986 						       GCancellable *cancellable,
4987 						       GError **error)
4988 {
4989 	GDBusObject *dbus_object;
4990 	EDBusSource *dbus_source = NULL;
4991 	gboolean success;
4992 	gchar *arg_reason = NULL, *arg_certificate_errors = NULL;
4993 	gchar *arg_dbus_error_name = NULL, *arg_dbus_error_message = NULL;
4994 	GError *local_error = NULL;
4995 
4996 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
4997 	g_return_val_if_fail (out_reason != NULL, FALSE);
4998 	g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
4999 	g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
5000 	g_return_val_if_fail (out_op_error != NULL, FALSE);
5001 
5002 	*out_reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
5003 	*out_certificate_pem =  NULL;
5004 	*out_certificate_errors = 0;
5005 	*out_op_error = NULL;
5006 
5007 	dbus_object = e_source_ref_dbus_object (source);
5008 	if (dbus_object != NULL) {
5009 		dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
5010 		g_object_unref (dbus_object);
5011 	}
5012 
5013 	if (!dbus_source)
5014 		return FALSE;
5015 
5016 	success = e_dbus_source_call_get_last_credentials_required_arguments_sync (dbus_source,
5017 		&arg_reason, out_certificate_pem, &arg_certificate_errors,
5018 		&arg_dbus_error_name, &arg_dbus_error_message, cancellable, &local_error);
5019 
5020 	g_object_unref (dbus_source);
5021 
5022 	*out_reason = source_credentials_reason_from_text (arg_reason);
5023 	*out_certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
5024 
5025 	if (arg_dbus_error_name && *arg_dbus_error_name && arg_dbus_error_message) {
5026 		*out_op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
5027 		g_dbus_error_strip_remote_error (*out_op_error);
5028 	}
5029 
5030 	if (*out_certificate_pem && !**out_certificate_pem) {
5031 		g_free (*out_certificate_pem);
5032 		*out_certificate_pem = NULL;
5033 	}
5034 
5035 	g_free (arg_reason);
5036 	g_free (arg_certificate_errors);
5037 	g_free (arg_dbus_error_name);
5038 	g_free (arg_dbus_error_message);
5039 
5040 	if (local_error != NULL) {
5041 		g_dbus_error_strip_remote_error (local_error);
5042 		g_propagate_error (error, local_error);
5043 		return FALSE;
5044 	}
5045 
5046 	return success;
5047 }
5048 
5049 static void
source_get_last_credentials_required_arguments_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)5050 source_get_last_credentials_required_arguments_thread (GTask *task,
5051 						       gpointer source_object,
5052 						       gpointer task_data,
5053 						       GCancellable *cancellable)
5054 {
5055 	InvokeCredentialsRequiredData *data;
5056 	GError *local_error = NULL;
5057 
5058 	data = g_slice_new0 (InvokeCredentialsRequiredData);
5059 	data->reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
5060 	data->certificate_pem = NULL;
5061 	data->certificate_errors = 0;
5062 	data->op_error = NULL;
5063 
5064 	e_source_get_last_credentials_required_arguments_sync (
5065 		E_SOURCE (source_object), &data->reason, &data->certificate_pem,
5066 		&data->certificate_errors, &data->op_error,
5067 		cancellable, &local_error);
5068 
5069 	if (local_error != NULL) {
5070 		g_task_return_error (task, local_error);
5071 		invoke_credentials_required_data_free (data);
5072 	} else {
5073 		g_task_return_pointer (task, data, invoke_credentials_required_data_free);
5074 	}
5075 }
5076 
5077 /**
5078  * e_source_get_last_credentials_required_arguments:
5079  * @source: an #ESource
5080  * @cancellable: optional #GCancellable object, or %NULL
5081  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
5082  * @user_data: data to pass to the callback function
5083  *
5084  * Asynchronously calls the GetLastCredentialsRequiredArguments method
5085  * on the server side, to get the last values used for the 'credentials-required'
5086  * signal. See e_source_get_last_credentials_required_arguments_sync() for
5087  * more information.
5088  *
5089  * When the operation is finished, @callback will be called. You can then
5090  * call e_source_get_last_credentials_required_arguments_finish() to get
5091  * the result of the operation.
5092  *
5093  * Since: 3.16
5094  **/
5095 void
e_source_get_last_credentials_required_arguments(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)5096 e_source_get_last_credentials_required_arguments (ESource *source,
5097 						  GCancellable *cancellable,
5098 						  GAsyncReadyCallback callback,
5099 						  gpointer user_data)
5100 {
5101 	GTask *task;
5102 
5103 	g_return_if_fail (E_IS_SOURCE (source));
5104 
5105 	task = g_task_new (source, cancellable, callback, user_data);
5106 	g_task_set_source_tag (task, e_source_get_last_credentials_required_arguments);
5107 
5108 	g_task_run_in_thread (task, source_get_last_credentials_required_arguments_thread);
5109 
5110 	g_object_unref (task);
5111 }
5112 
5113 /**
5114  * e_source_get_last_credentials_required_arguments_finish:
5115  * @source: an #ESource
5116  * @result: a #GAsyncResult
5117  * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
5118  * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
5119  * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
5120  * @out_op_error: (out): a #GError with a description of the previous credentials error
5121  * @error: return location for a #GError, or %NULL
5122  *
5123  * Finishes the operation started with e_source_get_last_credentials_required_arguments().
5124  * See e_source_get_last_credentials_required_arguments_sync() for more information
5125  * about the output arguments.
5126  *
5127  * If an error occurs, the function sets @error and returns %FALSE.
5128  *
5129  * Returns: %TRUE on success, %FALSE on error
5130  *
5131  * Since: 3.16
5132  **/
5133 gboolean
e_source_get_last_credentials_required_arguments_finish(ESource * source,GAsyncResult * result,ESourceCredentialsReason * out_reason,gchar ** out_certificate_pem,GTlsCertificateFlags * out_certificate_errors,GError ** out_op_error,GError ** error)5134 e_source_get_last_credentials_required_arguments_finish (ESource *source,
5135 							 GAsyncResult *result,
5136 							 ESourceCredentialsReason *out_reason,
5137 							 gchar **out_certificate_pem,
5138 							 GTlsCertificateFlags *out_certificate_errors,
5139 							 GError **out_op_error,
5140 							 GError **error)
5141 {
5142 	InvokeCredentialsRequiredData *data;
5143 
5144 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5145 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
5146 	g_return_val_if_fail (out_reason != NULL, FALSE);
5147 	g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
5148 	g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
5149 	g_return_val_if_fail (out_op_error != NULL, FALSE);
5150 
5151 	g_return_val_if_fail (
5152 		g_async_result_is_tagged (
5153 		result, e_source_get_last_credentials_required_arguments), FALSE);
5154 
5155 	data = g_task_propagate_pointer (G_TASK (result), error);
5156 	if (!data)
5157 		return FALSE;
5158 
5159 	*out_reason = data->reason;
5160 	*out_certificate_pem =  g_strdup (data->certificate_pem);
5161 	*out_certificate_errors = data->certificate_errors;
5162 	*out_op_error = data->op_error ? g_error_copy (data->op_error) : NULL;
5163 
5164 	invoke_credentials_required_data_free (data);
5165 
5166 	return TRUE;
5167 }
5168 
5169 /**
5170  * e_source_unset_last_credentials_required_arguments_sync:
5171  * @source: an #ESource
5172  * @cancellable: optional #GCancellable object, or %NULL
5173  * @error: return location for a #GError, or %NULL
5174  *
5175  * Unsets the last used arguments of the 'credentials-required' signal emission.
5176  *
5177  * If an error occurs, the function sets @error and returns %FALSE.
5178  *
5179  * Returns: %TRUE on success, %FALSE on error
5180  *
5181  * Since: 3.18
5182  **/
5183 gboolean
e_source_unset_last_credentials_required_arguments_sync(ESource * source,GCancellable * cancellable,GError ** error)5184 e_source_unset_last_credentials_required_arguments_sync (ESource *source,
5185 							 GCancellable *cancellable,
5186 							 GError **error)
5187 {
5188 	ESourceClass *klass;
5189 
5190 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5191 
5192 	klass = E_SOURCE_GET_CLASS (source);
5193 	g_return_val_if_fail (klass != NULL, FALSE);
5194 	g_return_val_if_fail (klass->unset_last_credentials_required_arguments_impl != NULL, FALSE);
5195 
5196 	return klass->unset_last_credentials_required_arguments_impl (source, cancellable, error);
5197 }
5198 
5199 static void
source_unset_last_credentials_required_arguments_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)5200 source_unset_last_credentials_required_arguments_thread (GTask *task,
5201 							 gpointer source_object,
5202 							 gpointer task_data,
5203 							 GCancellable *cancellable)
5204 {
5205 	GError *local_error = NULL;
5206 
5207 	e_source_unset_last_credentials_required_arguments_sync (
5208 		E_SOURCE (source_object), cancellable, &local_error);
5209 
5210 	if (local_error != NULL) {
5211 		g_task_return_error (task, local_error);
5212 	} else {
5213 		g_task_return_boolean (task, TRUE);
5214 	}
5215 }
5216 
5217 /**
5218  * e_source_unset_last_credentials_required_arguments:
5219  * @source: an #ESource
5220  * @cancellable: optional #GCancellable object, or %NULL
5221  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
5222  * @user_data: data to pass to the callback function
5223  *
5224  * Asynchronously calls the UnsetLastCredentialsRequiredArguments method
5225  * on the server side, to unset the last values used for the 'credentials-required'
5226  * signal.
5227  *
5228  * When the operation is finished, @callback will be called. You can then
5229  * call e_source_unset_last_credentials_required_arguments_finish() to get
5230  * the result of the operation.
5231  *
5232  * Since: 3.18
5233  **/
5234 void
e_source_unset_last_credentials_required_arguments(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)5235 e_source_unset_last_credentials_required_arguments (ESource *source,
5236 						    GCancellable *cancellable,
5237 						    GAsyncReadyCallback callback,
5238 						    gpointer user_data)
5239 {
5240 	GTask *task;
5241 
5242 	g_return_if_fail (E_IS_SOURCE (source));
5243 
5244 	task = g_task_new (source, cancellable, callback, user_data);
5245 	g_task_set_source_tag (task, e_source_unset_last_credentials_required_arguments);
5246 
5247 	g_task_run_in_thread (task, source_unset_last_credentials_required_arguments_thread);
5248 
5249 	g_object_unref (task);
5250 }
5251 
5252 /**
5253  * e_source_unset_last_credentials_required_arguments_finish:
5254  * @source: an #ESource
5255  * @result: a #GAsyncResult
5256  * @error: return location for a #GError, or %NULL
5257  *
5258  * Finishes the operation started with e_source_unset_last_credentials_required_arguments().
5259  *
5260  * If an error occurs, the function sets @error and returns %FALSE.
5261  *
5262  * Returns: %TRUE on success, %FALSE on error
5263  *
5264  * Since: 3.18
5265  **/
5266 gboolean
e_source_unset_last_credentials_required_arguments_finish(ESource * source,GAsyncResult * result,GError ** error)5267 e_source_unset_last_credentials_required_arguments_finish (ESource *source,
5268 							   GAsyncResult *result,
5269 							   GError **error)
5270 {
5271 	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
5272 	g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
5273 
5274 	g_return_val_if_fail (
5275 		g_async_result_is_tagged (
5276 		result, e_source_unset_last_credentials_required_arguments), FALSE);
5277 
5278 	return g_task_propagate_boolean (G_TASK (result), error);
5279 }
5280