1 /*
2  * e-server-side-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-server-side-source
20  * @include: libebackend/libebackend.h
21  * @short_description: A server-side data source
22  *
23  * An #EServerSideSource is an #ESource with some additional capabilities
24  * exclusive to the registry D-Bus service.
25  **/
26 
27 #include "evolution-data-server-config.h"
28 
29 #include <stdio.h>
30 #include <glib/gi18n-lib.h>
31 
32 /* Private D-Bus classes. */
33 #include "e-dbus-source.h"
34 
35 #include "e-server-side-source.h"
36 
37 #define DBUS_OBJECT_PATH	E_SOURCE_REGISTRY_SERVER_OBJECT_PATH "/Source"
38 
39 #define PRIMARY_GROUP_NAME	"Data Source"
40 
41 typedef struct _AsyncContext AsyncContext;
42 
43 struct _EServerSideSourcePrivate {
44 	gpointer server;  /* weak pointer */
45 	GWeakRef oauth2_support;
46 
47 	GNode node;
48 	GFile *file;
49 
50 	/* For comparison. */
51 	gchar *file_contents;
52 
53 	gchar *write_directory;
54 
55 	GMutex last_values_lock;
56 	gchar *last_reason;
57 	gchar *last_certificate_pem;
58 	gchar *last_certificate_errors;
59 	gchar *last_dbus_error_name;
60 	gchar *last_dbus_error_message;
61 	ENamedParameters *last_credentials;
62 
63 	GMutex pending_credentials_lookup_lock;
64 	GCancellable *pending_credentials_lookup;
65 };
66 
67 struct _AsyncContext {
68 	EDBusSourceRemoteCreatable *remote_creatable;
69 	EDBusSourceRemoteDeletable *remote_deletable;
70 	EDBusSourceOAuth2Support *oauth2_support;
71 	GDBusMethodInvocation *invocation;
72 };
73 
74 enum {
75 	PROP_0,
76 	PROP_EXPORTED,
77 	PROP_FILE,
78 	PROP_OAUTH2_SUPPORT,
79 	PROP_REMOTE_CREATABLE,
80 	PROP_REMOTE_DELETABLE,
81 	PROP_REMOVABLE,
82 	PROP_SERVER,
83 	PROP_WRITABLE,
84 	PROP_WRITE_DIRECTORY
85 };
86 
87 static GInitableIface *initable_parent_interface;
88 
89 /* Forward Declarations */
90 static void	e_server_side_source_initable_init
91 						(GInitableIface *iface);
92 
G_DEFINE_TYPE_WITH_CODE(EServerSideSource,e_server_side_source,E_TYPE_SOURCE,G_ADD_PRIVATE (EServerSideSource)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_server_side_source_initable_init))93 G_DEFINE_TYPE_WITH_CODE (
94 	EServerSideSource,
95 	e_server_side_source,
96 	E_TYPE_SOURCE,
97 	G_ADD_PRIVATE (EServerSideSource)
98 	G_IMPLEMENT_INTERFACE (
99 		G_TYPE_INITABLE,
100 		e_server_side_source_initable_init))
101 
102 static void
103 async_context_free (AsyncContext *async_context)
104 {
105 	if (async_context->remote_creatable != NULL)
106 		g_object_unref (async_context->remote_creatable);
107 
108 	if (async_context->remote_deletable != NULL)
109 		g_object_unref (async_context->remote_deletable);
110 
111 	if (async_context->oauth2_support != NULL)
112 		g_object_unref (async_context->oauth2_support);
113 
114 	if (async_context->invocation != NULL)
115 		g_object_unref (async_context->invocation);
116 
117 	g_slice_free (AsyncContext, async_context);
118 }
119 
120 static gboolean
server_side_source_parse_data(GKeyFile * key_file,const gchar * data,gsize length,GError ** error)121 server_side_source_parse_data (GKeyFile *key_file,
122                                const gchar *data,
123                                gsize length,
124                                GError **error)
125 {
126 	gboolean success;
127 
128 	success = g_key_file_load_from_data (
129 		key_file, data, length, G_KEY_FILE_NONE, error);
130 
131 	if (!success)
132 		return FALSE;
133 
134 	/* Make sure the key file has a [Data Source] group. */
135 	if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
136 		g_set_error (
137 			error, G_KEY_FILE_ERROR,
138 			G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
139 			_("Data source is missing a [%s] group"),
140 			PRIMARY_GROUP_NAME);
141 		return FALSE;
142 	}
143 
144 	return TRUE;
145 }
146 
147 static void
server_side_source_print_diff(ESource * source,const gchar * old_data,const gchar * new_data)148 server_side_source_print_diff (ESource *source,
149                                const gchar *old_data,
150                                const gchar *new_data)
151 {
152 	gchar **old_strv = NULL;
153 	gchar **new_strv = NULL;
154 	guint old_length = 0;
155 	guint new_length = 0;
156 	guint ii;
157 
158 	if (!e_source_registry_debug_enabled ())
159 		return;
160 
161 	e_source_registry_debug_print ("Saving %s\n", e_source_get_uid (source));
162 
163 	if (old_data != NULL) {
164 		old_strv = g_strsplit (old_data, "\n", 0);
165 		old_length = g_strv_length (old_strv);
166 	}
167 
168 	if (new_data != NULL) {
169 		new_strv = g_strsplit (new_data, "\n", 0);
170 		new_length = g_strv_length (new_strv);
171 	}
172 
173 	for (ii = 0; ii < MIN (old_length, new_length); ii++) {
174 		if (g_strcmp0 (old_strv[ii], new_strv[ii]) != 0) {
175 			e_source_registry_debug_print (" - : %s\n", old_strv[ii]);
176 			e_source_registry_debug_print (" + : %s\n", new_strv[ii]);
177 		} else {
178 			e_source_registry_debug_print ("   : %s\n", old_strv[ii]);
179 		}
180 	}
181 
182 	for (; ii < old_length; ii++)
183 		e_source_registry_debug_print (" - : %s\n", old_strv[ii]);
184 
185 	for (; ii < new_length; ii++)
186 		e_source_registry_debug_print (" + : %s\n", new_strv[ii]);
187 
188 	g_strfreev (old_strv);
189 	g_strfreev (new_strv);
190 }
191 
192 static gboolean
server_side_source_traverse_cb(GNode * node,GQueue * queue)193 server_side_source_traverse_cb (GNode *node,
194                                 GQueue *queue)
195 {
196 	g_queue_push_tail (queue, g_object_ref (node->data));
197 
198 	return FALSE;
199 }
200 
201 static ESourceCredentialsReason
server_side_source_credentials_reason_from_text(const gchar * arg_reason)202 server_side_source_credentials_reason_from_text (const gchar *arg_reason)
203 {
204 	ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
205 
206 	if (arg_reason && *arg_reason) {
207 		GEnumClass *enum_class;
208 		GEnumValue *enum_value;
209 
210 		enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
211 		enum_value = g_enum_get_value_by_nick (enum_class, arg_reason);
212 
213 		if (enum_value) {
214 			reason = enum_value->value;
215 		} else {
216 			g_warning ("%s: Unknown reason enum: '%s'", G_STRFUNC, arg_reason);
217 		}
218 
219 		g_type_class_unref (enum_class);
220 	}
221 
222 	return reason;
223 }
224 
225 typedef struct _ReinvokeCredentialsRequiredData {
226 	EServerSideSource *source;
227 	gchar *arg_reason;
228 	gchar *arg_certificate_pem;
229 	gchar *arg_certificate_errors;
230 	gchar *arg_dbus_error_name;
231 	gchar *arg_dbus_error_message;
232 } ReinvokeCredentialsRequiredData;
233 
234 static void
reinvoke_credentials_required_data_free(gpointer ptr)235 reinvoke_credentials_required_data_free (gpointer ptr)
236 {
237 	ReinvokeCredentialsRequiredData *data = ptr;
238 
239 	if (data) {
240 		g_clear_object (&data->source);
241 		g_free (data->arg_reason);
242 		g_free (data->arg_certificate_pem);
243 		g_free (data->arg_certificate_errors);
244 		g_free (data->arg_dbus_error_name);
245 		g_free (data->arg_dbus_error_message);
246 		g_slice_free (ReinvokeCredentialsRequiredData, data);
247 	}
248 }
249 
250 static void server_side_source_credentials_lookup_cb (GObject *source_object, GAsyncResult *result, gpointer user_data);
251 
252 static gboolean
server_side_source_invoke_credentials_required_cb(EDBusSource * dbus_interface,GDBusMethodInvocation * invocation,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,EServerSideSource * source)253 server_side_source_invoke_credentials_required_cb (EDBusSource *dbus_interface,
254 						   GDBusMethodInvocation *invocation,
255 						   const gchar *arg_reason,
256 						   const gchar *arg_certificate_pem,
257 						   const gchar *arg_certificate_errors,
258 						   const gchar *arg_dbus_error_name,
259 						   const gchar *arg_dbus_error_message,
260 						   EServerSideSource *source)
261 {
262 	gboolean skip_emit = FALSE;
263 
264 	if (invocation)
265 		e_dbus_source_complete_invoke_credentials_required (dbus_interface, invocation);
266 
267 	g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
268 	if (source->priv->pending_credentials_lookup) {
269 		g_cancellable_cancel (source->priv->pending_credentials_lookup);
270 		g_clear_object (&source->priv->pending_credentials_lookup);
271 	}
272 	g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
273 
274 	g_mutex_lock (&source->priv->last_values_lock);
275 
276 	g_free (source->priv->last_reason);
277 	g_free (source->priv->last_certificate_pem);
278 	g_free (source->priv->last_certificate_errors);
279 	g_free (source->priv->last_dbus_error_name);
280 	g_free (source->priv->last_dbus_error_message);
281 	source->priv->last_reason = g_strdup (arg_reason);
282 	source->priv->last_certificate_pem = g_strdup (arg_certificate_pem);
283 	source->priv->last_certificate_errors = g_strdup (arg_certificate_errors);
284 	source->priv->last_dbus_error_name = g_strdup (arg_dbus_error_name);
285 	source->priv->last_dbus_error_message = g_strdup (arg_dbus_error_message);
286 
287 	g_mutex_unlock (&source->priv->last_values_lock);
288 
289 	/* Do not bother clients, when the password is stored. */
290 	if (server_side_source_credentials_reason_from_text (arg_reason) == E_SOURCE_CREDENTIALS_REASON_REQUIRED) {
291 		ESourceRegistryServer *server;
292 		ESourceCredentialsProvider *credentials_provider;
293 
294 		server = e_server_side_source_get_server (source);
295 		credentials_provider = server ? e_source_registry_server_ref_credentials_provider (server) : NULL;
296 
297 		if (credentials_provider) {
298 			ReinvokeCredentialsRequiredData *data;
299 			GCancellable *cancellable;
300 
301 			g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
302 			if (source->priv->pending_credentials_lookup) {
303 				g_cancellable_cancel (source->priv->pending_credentials_lookup);
304 				g_clear_object (&source->priv->pending_credentials_lookup);
305 			}
306 			cancellable = g_cancellable_new ();
307 			source->priv->pending_credentials_lookup = g_object_ref (cancellable);
308 			g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
309 
310 			data = g_slice_new0 (ReinvokeCredentialsRequiredData);
311 			data->source = g_object_ref (source);
312 			data->arg_reason = g_strdup (arg_reason);
313 			data->arg_certificate_pem = g_strdup (arg_certificate_pem);
314 			data->arg_certificate_errors = g_strdup (arg_certificate_errors);
315 			data->arg_dbus_error_name = g_strdup (arg_dbus_error_name);
316 			data->arg_dbus_error_message = g_strdup (arg_dbus_error_message);
317 
318 			skip_emit = TRUE;
319 
320 			e_source_credentials_provider_lookup (credentials_provider, E_SOURCE (source),
321 				cancellable, server_side_source_credentials_lookup_cb, data);
322 
323 			g_object_unref (cancellable);
324 		}
325 
326 		g_clear_object (&credentials_provider);
327 	}
328 
329 	if (!skip_emit) {
330 		e_dbus_source_emit_credentials_required (dbus_interface, arg_reason, arg_certificate_pem, arg_certificate_errors, arg_dbus_error_name, arg_dbus_error_message);
331 	}
332 
333 	return TRUE;
334 }
335 
336 static gboolean
server_side_source_invoke_authenticate_cb(EDBusSource * dbus_interface,GDBusMethodInvocation * invocation,const gchar * const * arg_credentials,EServerSideSource * source)337 server_side_source_invoke_authenticate_cb (EDBusSource *dbus_interface,
338 					   GDBusMethodInvocation *invocation,
339 					   const gchar * const *arg_credentials,
340 					   EServerSideSource *source)
341 {
342 	gchar **last_credentials_strv = NULL;
343 
344 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), TRUE);
345 
346 	g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
347 	if (source->priv->pending_credentials_lookup) {
348 		g_cancellable_cancel (source->priv->pending_credentials_lookup);
349 		g_clear_object (&source->priv->pending_credentials_lookup);
350 	}
351 	g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
352 
353 	g_mutex_lock (&source->priv->last_values_lock);
354 
355 	/* Empty credentials are used to use the last credentials instead */
356 	if (source->priv->last_credentials && arg_credentials && !arg_credentials[0]) {
357 		last_credentials_strv = e_named_parameters_to_strv (source->priv->last_credentials);
358 		arg_credentials = (const gchar * const *) last_credentials_strv;
359 	} else if (arg_credentials && arg_credentials[0]) {
360 		ENamedParameters *credentials = e_named_parameters_new_strv (arg_credentials);
361 
362 		/* If only one credential value is passed in, and it's the SSL Trust,
363 		   and there was any credentials already tried, then merge the previous
364 		   credentials with the SSL Trust, to inherit the password, if any. */
365 		if (source->priv->last_credentials &&
366 		    e_named_parameters_count (credentials) == 1 &&
367 		    e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_SSL_TRUST)) {
368 			gint ii, count;
369 
370 			count = e_named_parameters_count (source->priv->last_credentials);
371 			for (ii = 0; ii < count; ii++) {
372 				gchar *name;
373 
374 				name = e_named_parameters_get_name (source->priv->last_credentials, ii);
375 				if (!name)
376 					continue;
377 
378 				if (*name && !e_named_parameters_exists (credentials, name)) {
379 					e_named_parameters_set (credentials, name,
380 						e_named_parameters_get (source->priv->last_credentials, name));
381 				}
382 
383 				g_free (name);
384 			}
385 
386 			last_credentials_strv = e_named_parameters_to_strv (credentials);
387 			arg_credentials = (const gchar * const *) last_credentials_strv;
388 		}
389 
390 		e_named_parameters_free (source->priv->last_credentials);
391 		source->priv->last_credentials = credentials;
392 	}
393 
394 	g_free (source->priv->last_reason);
395 	g_free (source->priv->last_certificate_pem);
396 	g_free (source->priv->last_certificate_errors);
397 	g_free (source->priv->last_dbus_error_name);
398 	g_free (source->priv->last_dbus_error_message);
399 	source->priv->last_reason = NULL;
400 	source->priv->last_certificate_pem = NULL;
401 	source->priv->last_certificate_errors = NULL;
402 	source->priv->last_dbus_error_name = NULL;
403 	source->priv->last_dbus_error_message = NULL;
404 
405 	g_mutex_unlock (&source->priv->last_values_lock);
406 
407 	if (invocation)
408 		e_dbus_source_complete_invoke_authenticate (dbus_interface, invocation);
409 
410 	e_dbus_source_emit_authenticate (dbus_interface, arg_credentials);
411 
412 	g_strfreev (last_credentials_strv);
413 
414 	return TRUE;
415 }
416 
417 static void
server_side_source_credentials_lookup_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)418 server_side_source_credentials_lookup_cb (GObject *source_object,
419 					  GAsyncResult *result,
420 					  gpointer user_data)
421 {
422 	GDBusObject *dbus_object;
423 	EDBusSource *dbus_source;
424 	ReinvokeCredentialsRequiredData *data = user_data;
425 	ENamedParameters *credentials = NULL;
426 	gboolean success;
427 	GError *error = NULL;
428 
429 	g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (source_object));
430 	g_return_if_fail (data != NULL);
431 
432 	success = e_source_credentials_provider_lookup_finish (E_SOURCE_CREDENTIALS_PROVIDER (source_object), result, &credentials, &error);
433 
434 	dbus_object = e_source_ref_dbus_object (E_SOURCE (data->source));
435 	if (!dbus_object) {
436 		e_named_parameters_free (credentials);
437 		reinvoke_credentials_required_data_free (data);
438 		return;
439 	}
440 
441 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
442 	if (!dbus_source) {
443 		e_named_parameters_free (credentials);
444 		g_clear_object (&dbus_object);
445 		reinvoke_credentials_required_data_free (data);
446 		return;
447 	}
448 
449 	if (success && credentials) {
450 		gchar **arg_credentials;
451 
452 		arg_credentials = e_named_parameters_to_strv (credentials);
453 
454 		server_side_source_invoke_authenticate_cb (dbus_source, NULL,
455 			(const gchar * const *) arg_credentials, data->source);
456 
457 		g_strfreev (arg_credentials);
458 	} else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
459 		if (e_source_registry_debug_enabled ()) {
460 			printf ("%s: Failed to lookup password for source %s (%s): %s\n", G_STRFUNC,
461 				e_source_get_uid (E_SOURCE (data->source)),
462 				e_source_get_display_name (E_SOURCE (data->source)),
463 				error ? error->message : "Unknown error");
464 			fflush (stdout);
465 		}
466 
467 		g_prefix_error (&error, "%s", _("Failed to lookup credentials: "));
468 
469 		if (server_side_source_credentials_reason_from_text (data->arg_reason) == E_SOURCE_CREDENTIALS_REASON_REQUIRED &&
470 		    error && !e_source_credentials_provider_can_prompt (E_SOURCE_CREDENTIALS_PROVIDER (source_object), E_SOURCE (data->source))) {
471 			GEnumClass *enum_class;
472 			GEnumValue *enum_value;
473 			gchar *dbus_error_name;
474 
475 			enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
476 			enum_value = g_enum_get_value (enum_class, E_SOURCE_CREDENTIALS_REASON_ERROR);
477 
478 			g_return_if_fail (enum_value != NULL);
479 
480 			dbus_error_name = g_dbus_error_encode_gerror (error);
481 
482 			/* Use error reason when the source cannot be prompted for credentials */
483 			e_dbus_source_emit_credentials_required (dbus_source, enum_value->value_nick,
484 				data->arg_certificate_pem, data->arg_certificate_errors, dbus_error_name, error->message);
485 
486 			g_type_class_unref (enum_class);
487 			g_free (dbus_error_name);
488 		} else {
489 			/* Reinvoke for clients only, if not cancelled */
490 			const gchar *arg_dbus_error_name, *arg_dbus_error_message;
491 			gchar *dbus_error_name = NULL;
492 
493 			arg_dbus_error_name = data->arg_dbus_error_name;
494 			arg_dbus_error_message = data->arg_dbus_error_message;
495 
496 			if (!arg_dbus_error_name || !*arg_dbus_error_name) {
497 				if (!error)
498 					error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown error"));
499 
500 				dbus_error_name = g_dbus_error_encode_gerror (error);
501 				arg_dbus_error_name = dbus_error_name;
502 				arg_dbus_error_message = error->message;
503 			}
504 
505 			e_dbus_source_emit_credentials_required (dbus_source, data->arg_reason,
506 				data->arg_certificate_pem, data->arg_certificate_errors,
507 				arg_dbus_error_name, arg_dbus_error_message);
508 
509 			g_free (dbus_error_name);
510 		}
511 	}
512 
513 	e_named_parameters_free (credentials);
514 	reinvoke_credentials_required_data_free (data);
515 	g_object_unref (dbus_source);
516 	g_object_unref (dbus_object);
517 	g_clear_error (&error);
518 }
519 
520 static gboolean
server_side_source_get_last_credentials_required_arguments_cb(EDBusSource * dbus_interface,GDBusMethodInvocation * invocation,EServerSideSource * source)521 server_side_source_get_last_credentials_required_arguments_cb (EDBusSource *dbus_interface,
522 							       GDBusMethodInvocation *invocation,
523 							       EServerSideSource *source)
524 {
525 	g_mutex_lock (&source->priv->last_values_lock);
526 
527 	e_dbus_source_complete_get_last_credentials_required_arguments (dbus_interface, invocation,
528 		source->priv->last_reason ? source->priv->last_reason : "",
529 		source->priv->last_certificate_pem ? source->priv->last_certificate_pem : "",
530 		source->priv->last_certificate_errors ? source->priv->last_certificate_errors : "",
531 		source->priv->last_dbus_error_name ? source->priv->last_dbus_error_name : "",
532 		source->priv->last_dbus_error_message ? source->priv->last_dbus_error_message : "");
533 
534 	g_mutex_unlock (&source->priv->last_values_lock);
535 
536 	return TRUE;
537 }
538 
539 static void
server_side_source_unset_last_credentials_required_arguments(EServerSideSource * source)540 server_side_source_unset_last_credentials_required_arguments (EServerSideSource *source)
541 {
542 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
543 
544 	g_mutex_lock (&source->priv->last_values_lock);
545 
546 	g_free (source->priv->last_reason);
547 	g_free (source->priv->last_certificate_pem);
548 	g_free (source->priv->last_certificate_errors);
549 	g_free (source->priv->last_dbus_error_name);
550 	g_free (source->priv->last_dbus_error_message);
551 
552 	source->priv->last_reason = NULL;
553 	source->priv->last_certificate_pem = NULL;
554 	source->priv->last_certificate_errors = NULL;
555 	source->priv->last_dbus_error_name = NULL;
556 	source->priv->last_dbus_error_message = NULL;
557 
558 	g_mutex_unlock (&source->priv->last_values_lock);
559 }
560 
561 static gboolean
server_side_source_unset_last_credentials_required_arguments_cb(EDBusSource * dbus_interface,GDBusMethodInvocation * invocation,EServerSideSource * source)562 server_side_source_unset_last_credentials_required_arguments_cb (EDBusSource *dbus_interface,
563 								 GDBusMethodInvocation *invocation,
564 								 EServerSideSource *source)
565 {
566 	server_side_source_unset_last_credentials_required_arguments (source);
567 
568 	e_dbus_source_complete_unset_last_credentials_required_arguments (dbus_interface, invocation);
569 
570 	return TRUE;
571 }
572 
573 static gboolean
server_side_source_remove_cb(EDBusSourceRemovable * dbus_interface,GDBusMethodInvocation * invocation,EServerSideSource * source)574 server_side_source_remove_cb (EDBusSourceRemovable *dbus_interface,
575                               GDBusMethodInvocation *invocation,
576                               EServerSideSource *source)
577 {
578 	GError *error = NULL;
579 
580 	/* Note we don't need to verify the source is removable here
581 	 * since if it isn't, the remove() method won't be available.
582 	 * Descendants of the source are removed whether they export
583 	 * a remove() method or not. */
584 
585 	e_source_remove_sync (E_SOURCE (source), NULL, &error);
586 
587 	if (error != NULL)
588 		g_dbus_method_invocation_take_error (invocation, error);
589 	else
590 		e_dbus_source_removable_complete_remove (
591 			dbus_interface, invocation);
592 
593 	return TRUE;
594 }
595 
596 static gboolean
server_side_source_write_cb(EDBusSourceWritable * dbus_interface,GDBusMethodInvocation * invocation,const gchar * data,ESource * source)597 server_side_source_write_cb (EDBusSourceWritable *dbus_interface,
598                              GDBusMethodInvocation *invocation,
599                              const gchar *data,
600                              ESource *source)
601 {
602 	GKeyFile *key_file;
603 	GDBusObject *dbus_object;
604 	EDBusSource *dbus_source;
605 	GError *error = NULL;
606 
607 	/* Note we don't need to verify the source is writable here
608 	 * since if it isn't, the write() method won't be available. */
609 
610 	dbus_object = e_source_ref_dbus_object (source);
611 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
612 
613 	/* Validate the raw data before making the changes live. */
614 	key_file = g_key_file_new ();
615 	server_side_source_parse_data (key_file, data, strlen (data), &error);
616 	g_key_file_free (key_file);
617 
618 	/* Q: How does this trigger data being written to disk?
619 	 *
620 	 * A: Here's the sequence of events:
621 	 *
622 	 *    1) We set the EDBusSource:data property.
623 	 *    2) ESource picks up the "notify::data" signal and parses
624 	 *       the raw data, which triggers an ESource:changed signal.
625 	 *    3) Our changed() method schedules an idle callback.
626 	 *    4) The idle callback calls e_source_write_sync().
627 	 *    5) e_source_write_sync() calls e_dbus_source_dup_data()
628 	 *       and synchronously writes the resulting string to disk.
629 	 *
630 	 * XXX: This should be done more straigtforward, because rely
631 	 *      on two different signals and having actual data file
632 	 *      save in 5 steps is ridiculous, not talking that
633 	 *      the returned GError from this D-Bus call doesn't handle
634 	 *      errors from actual file save, which can also break, thus
635 	 *      the caller doesn't know about any real problem during saving
636 	 *      and thinks that everything went fine.
637 	 */
638 
639 	if (error == NULL) {
640 		e_dbus_source_set_data (dbus_source, data);
641 
642 		/* Make sure the ESource::changed signal is called, otherwise
643 		 * the above Q&A doesn't work and changed data are not saved. */
644 		e_source_changed (source);
645 	}
646 
647 	if (error != NULL)
648 		g_dbus_method_invocation_take_error (invocation, error);
649 	else
650 		e_dbus_source_writable_complete_write (
651 			dbus_interface, invocation);
652 
653 	g_object_unref (dbus_source);
654 	g_object_unref (dbus_object);
655 
656 	return TRUE;
657 }
658 
659 /* Helper for server_side_source_remote_create_cb() */
660 static void
server_side_source_remote_create_done_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)661 server_side_source_remote_create_done_cb (GObject *source_object,
662                                           GAsyncResult *result,
663                                           gpointer user_data)
664 {
665 	ESource *source;
666 	AsyncContext *async_context;
667 	GError *error = NULL;
668 
669 	source = E_SOURCE (source_object);
670 	async_context = (AsyncContext *) user_data;
671 
672 	e_source_remote_create_finish (source, result, &error);
673 
674 	if (error != NULL)
675 		g_dbus_method_invocation_take_error (
676 			async_context->invocation, error);
677 	else
678 		e_dbus_source_remote_creatable_complete_create (
679 			async_context->remote_creatable,
680 			async_context->invocation);
681 
682 	async_context_free (async_context);
683 }
684 
685 static gboolean
server_side_source_remote_create_cb(EDBusSourceRemoteCreatable * dbus_interface,GDBusMethodInvocation * invocation,const gchar * uid,const gchar * data,ESource * source)686 server_side_source_remote_create_cb (EDBusSourceRemoteCreatable *dbus_interface,
687                                      GDBusMethodInvocation *invocation,
688                                      const gchar *uid,
689                                      const gchar *data,
690                                      ESource *source)
691 {
692 	EServerSideSource *server_side_source;
693 	ESourceRegistryServer *server;
694 	AsyncContext *async_context;
695 	ESource *scratch_source;
696 	GDBusObject *dbus_object;
697 	EDBusSource *dbus_source;
698 	GKeyFile *key_file;
699 	GFile *file;
700 	GError *error = NULL;
701 
702 	/* Create a new EServerSideSource from 'uid' and 'data' but
703 	 * DO NOT add it to the ESourceRegistryServer yet.  It's up
704 	 * to the ECollectionBackend whether to use source as given
705 	 * or create its own equivalent EServerSideSource, possibly
706 	 * in response to a notification from a remote server. */
707 
708 	/* Validate the raw data. */
709 	key_file = g_key_file_new ();
710 	server_side_source_parse_data (key_file, data, strlen (data), &error);
711 	g_key_file_free (key_file);
712 
713 	if (error != NULL) {
714 		g_dbus_method_invocation_take_error (invocation, error);
715 		return TRUE;
716 	}
717 
718 	server_side_source = E_SERVER_SIDE_SOURCE (source);
719 	server = e_server_side_source_get_server (server_side_source);
720 
721 	file = e_server_side_source_new_user_file (uid);
722 	scratch_source = e_server_side_source_new (server, file, &error);
723 	g_object_unref (file);
724 
725 	/* Sanity check. */
726 	g_warn_if_fail (
727 		((scratch_source != NULL) && (error == NULL)) ||
728 		((scratch_source == NULL) && (error != NULL)));
729 
730 	if (error != NULL) {
731 		g_dbus_method_invocation_take_error (invocation, error);
732 		return TRUE;
733 	}
734 
735 	dbus_object = e_source_ref_dbus_object (scratch_source);
736 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
737 
738 	e_dbus_source_set_data (dbus_source, data);
739 
740 	g_object_unref (dbus_object);
741 	g_object_unref (dbus_source);
742 
743 	async_context = g_slice_new0 (AsyncContext);
744 	async_context->remote_creatable = g_object_ref (dbus_interface);
745 	async_context->invocation = g_object_ref (invocation);
746 
747 	e_source_remote_create (
748 		source, scratch_source, NULL,
749 		server_side_source_remote_create_done_cb,
750 		async_context);
751 
752 	g_object_unref (scratch_source);
753 
754 	return TRUE;
755 }
756 
757 /* Helper for server_side_source_remote_delete_cb() */
758 static void
server_side_source_remote_delete_done_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)759 server_side_source_remote_delete_done_cb (GObject *source_object,
760                                           GAsyncResult *result,
761                                           gpointer user_data)
762 {
763 	ESource *source;
764 	AsyncContext *async_context;
765 	GError *error = NULL;
766 
767 	source = E_SOURCE (source_object);
768 	async_context = (AsyncContext *) user_data;
769 
770 	e_source_remote_delete_finish (source, result, &error);
771 
772 	if (error != NULL)
773 		g_dbus_method_invocation_take_error (
774 			async_context->invocation, error);
775 	else
776 		e_dbus_source_remote_deletable_complete_delete (
777 			async_context->remote_deletable,
778 			async_context->invocation);
779 
780 	async_context_free (async_context);
781 }
782 
783 static gboolean
server_side_source_remote_delete_cb(EDBusSourceRemoteDeletable * dbus_interface,GDBusMethodInvocation * invocation,ESource * source)784 server_side_source_remote_delete_cb (EDBusSourceRemoteDeletable *dbus_interface,
785                                      GDBusMethodInvocation *invocation,
786                                      ESource *source)
787 {
788 	AsyncContext *async_context;
789 
790 	async_context = g_slice_new0 (AsyncContext);
791 	async_context->remote_deletable = g_object_ref (dbus_interface);
792 	async_context->invocation = g_object_ref (invocation);
793 
794 	e_source_remote_delete (
795 		source, NULL,
796 		server_side_source_remote_delete_done_cb,
797 		async_context);
798 
799 	return TRUE;
800 }
801 
802 /* Helper for server_side_source_get_access_token_cb() */
803 static void
server_side_source_get_access_token_done_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)804 server_side_source_get_access_token_done_cb (GObject *source_object,
805                                              GAsyncResult *result,
806                                              gpointer user_data)
807 {
808 	ESource *source;
809 	AsyncContext *async_context;
810 	gchar *access_token = NULL;
811 	gint expires_in = 0;
812 	GError *error = NULL;
813 
814 	source = E_SOURCE (source_object);
815 	async_context = (AsyncContext *) user_data;
816 
817 	e_source_get_oauth2_access_token_finish (
818 		source, result, &access_token, &expires_in, &error);
819 
820 	/* Sanity check. */
821 	g_return_if_fail (
822 		((access_token != NULL) && (error == NULL)) ||
823 		((access_token == NULL) && (error != NULL)));
824 
825 	if (error != NULL)
826 		g_dbus_method_invocation_take_error (
827 			async_context->invocation, error);
828 	else
829 		e_dbus_source_oauth2_support_complete_get_access_token (
830 			async_context->oauth2_support,
831 			async_context->invocation,
832 			access_token, expires_in);
833 
834 	g_free (access_token);
835 
836 	async_context_free (async_context);
837 }
838 
839 static gboolean
server_side_source_get_access_token_cb(EDBusSourceOAuth2Support * dbus_interface,GDBusMethodInvocation * invocation,ESource * source)840 server_side_source_get_access_token_cb (EDBusSourceOAuth2Support *dbus_interface,
841                                         GDBusMethodInvocation *invocation,
842                                         ESource *source)
843 {
844 	AsyncContext *async_context;
845 
846 	async_context = g_slice_new0 (AsyncContext);
847 	async_context->oauth2_support = g_object_ref (dbus_interface);
848 	async_context->invocation = g_object_ref (invocation);
849 
850 	e_source_get_oauth2_access_token (
851 		source, NULL,
852 		server_side_source_get_access_token_done_cb,
853 		async_context);
854 
855 	return TRUE;
856 }
857 
858 static void
server_side_source_set_file(EServerSideSource * source,GFile * file)859 server_side_source_set_file (EServerSideSource *source,
860                              GFile *file)
861 {
862 	g_return_if_fail (file == NULL || G_IS_FILE (file));
863 	g_return_if_fail (source->priv->file == NULL);
864 
865 	if (file != NULL)
866 		source->priv->file = g_object_ref (file);
867 }
868 
869 static void
server_side_source_set_server(EServerSideSource * source,ESourceRegistryServer * server)870 server_side_source_set_server (EServerSideSource *source,
871                                ESourceRegistryServer *server)
872 {
873 	g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
874 	g_return_if_fail (source->priv->server == NULL);
875 
876 	source->priv->server = server;
877 
878 	g_object_add_weak_pointer (
879 		G_OBJECT (server), &source->priv->server);
880 }
881 
882 static void
server_side_source_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)883 server_side_source_set_property (GObject *object,
884                                  guint property_id,
885                                  const GValue *value,
886                                  GParamSpec *pspec)
887 {
888 	switch (property_id) {
889 		case PROP_FILE:
890 			server_side_source_set_file (
891 				E_SERVER_SIDE_SOURCE (object),
892 				g_value_get_object (value));
893 			return;
894 
895 		case PROP_OAUTH2_SUPPORT:
896 			e_server_side_source_set_oauth2_support (
897 				E_SERVER_SIDE_SOURCE (object),
898 				g_value_get_object (value));
899 			return;
900 
901 		case PROP_REMOTE_CREATABLE:
902 			e_server_side_source_set_remote_creatable (
903 				E_SERVER_SIDE_SOURCE (object),
904 				g_value_get_boolean (value));
905 			return;
906 
907 		case PROP_REMOTE_DELETABLE:
908 			e_server_side_source_set_remote_deletable (
909 				E_SERVER_SIDE_SOURCE (object),
910 				g_value_get_boolean (value));
911 			return;
912 
913 		case PROP_REMOVABLE:
914 			e_server_side_source_set_removable (
915 				E_SERVER_SIDE_SOURCE (object),
916 				g_value_get_boolean (value));
917 			return;
918 
919 		case PROP_SERVER:
920 			server_side_source_set_server (
921 				E_SERVER_SIDE_SOURCE (object),
922 				g_value_get_object (value));
923 			return;
924 
925 		case PROP_WRITABLE:
926 			e_server_side_source_set_writable (
927 				E_SERVER_SIDE_SOURCE (object),
928 				g_value_get_boolean (value));
929 			return;
930 
931 		case PROP_WRITE_DIRECTORY:
932 			e_server_side_source_set_write_directory (
933 				E_SERVER_SIDE_SOURCE (object),
934 				g_value_get_string (value));
935 			return;
936 	}
937 
938 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
939 }
940 
941 static void
server_side_source_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)942 server_side_source_get_property (GObject *object,
943                                  guint property_id,
944                                  GValue *value,
945                                  GParamSpec *pspec)
946 {
947 	switch (property_id) {
948 		case PROP_EXPORTED:
949 			g_value_set_boolean (
950 				value,
951 				e_server_side_source_get_exported (
952 				E_SERVER_SIDE_SOURCE (object)));
953 			return;
954 
955 		case PROP_FILE:
956 			g_value_set_object (
957 				value,
958 				e_server_side_source_get_file (
959 				E_SERVER_SIDE_SOURCE (object)));
960 			return;
961 
962 		case PROP_OAUTH2_SUPPORT:
963 			g_value_take_object (
964 				value,
965 				e_server_side_source_ref_oauth2_support (
966 				E_SERVER_SIDE_SOURCE (object)));
967 			return;
968 
969 		case PROP_REMOTE_CREATABLE:
970 			g_value_set_boolean (
971 				value,
972 				e_source_get_remote_creatable (
973 				E_SOURCE (object)));
974 			return;
975 
976 		case PROP_REMOTE_DELETABLE:
977 			g_value_set_boolean (
978 				value,
979 				e_source_get_remote_deletable (
980 				E_SOURCE (object)));
981 			return;
982 
983 		case PROP_REMOVABLE:
984 			g_value_set_boolean (
985 				value,
986 				e_source_get_removable (
987 				E_SOURCE (object)));
988 			return;
989 
990 		case PROP_SERVER:
991 			g_value_set_object (
992 				value,
993 				e_server_side_source_get_server (
994 				E_SERVER_SIDE_SOURCE (object)));
995 			return;
996 
997 		case PROP_WRITABLE:
998 			g_value_set_boolean (
999 				value,
1000 				e_source_get_writable (
1001 				E_SOURCE (object)));
1002 			return;
1003 
1004 		case PROP_WRITE_DIRECTORY:
1005 			g_value_set_string (
1006 				value,
1007 				e_server_side_source_get_write_directory (
1008 				E_SERVER_SIDE_SOURCE (object)));
1009 			return;
1010 	}
1011 
1012 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1013 }
1014 
1015 static void
server_side_source_dispose(GObject * object)1016 server_side_source_dispose (GObject *object)
1017 {
1018 	EServerSideSourcePrivate *priv;
1019 
1020 	priv = E_SERVER_SIDE_SOURCE (object)->priv;
1021 
1022 	g_mutex_lock (&priv->last_values_lock);
1023 
1024 	g_free (priv->last_reason);
1025 	g_free (priv->last_certificate_pem);
1026 	g_free (priv->last_certificate_errors);
1027 	g_free (priv->last_dbus_error_name);
1028 	g_free (priv->last_dbus_error_message);
1029 	priv->last_reason = NULL;
1030 	priv->last_certificate_pem = NULL;
1031 	priv->last_certificate_errors = NULL;
1032 	priv->last_dbus_error_name = NULL;
1033 	priv->last_dbus_error_message = NULL;
1034 
1035 	e_named_parameters_free (priv->last_credentials);
1036 	priv->last_credentials = NULL;
1037 
1038 	g_mutex_unlock (&priv->last_values_lock);
1039 
1040 	g_mutex_lock (&priv->pending_credentials_lookup_lock);
1041 	if (priv->pending_credentials_lookup) {
1042 		g_cancellable_cancel (priv->pending_credentials_lookup);
1043 		g_clear_object (&priv->pending_credentials_lookup);
1044 	}
1045 	g_mutex_unlock (&priv->pending_credentials_lookup_lock);
1046 
1047 	if (priv->server != NULL) {
1048 		g_object_remove_weak_pointer (
1049 			G_OBJECT (priv->server), &priv->server);
1050 		priv->server = NULL;
1051 	}
1052 
1053 	g_weak_ref_set (&priv->oauth2_support, NULL);
1054 
1055 	g_clear_object (&priv->file);
1056 
1057 	/* Chain up to parent's dispose() method. */
1058 	G_OBJECT_CLASS (e_server_side_source_parent_class)->dispose (object);
1059 }
1060 
1061 static void
server_side_source_finalize(GObject * object)1062 server_side_source_finalize (GObject *object)
1063 {
1064 	EServerSideSourcePrivate *priv;
1065 
1066 	priv = E_SERVER_SIDE_SOURCE (object)->priv;
1067 
1068 	g_node_unlink (&priv->node);
1069 
1070 	g_free (priv->file_contents);
1071 	g_free (priv->write_directory);
1072 
1073 	g_weak_ref_clear (&priv->oauth2_support);
1074 	g_mutex_clear (&priv->last_values_lock);
1075 	g_mutex_clear (&priv->pending_credentials_lookup_lock);
1076 
1077 	/* Chain up to parent's finalize() method. */
1078 	G_OBJECT_CLASS (e_server_side_source_parent_class)->finalize (object);
1079 }
1080 
1081 static void
server_side_source_changed(ESource * source)1082 server_side_source_changed (ESource *source)
1083 {
1084 	GDBusObject *dbus_object;
1085 	EDBusSource *dbus_source;
1086 	gchar *old_data;
1087 	gchar *new_data;
1088 	GError *error = NULL;
1089 
1090 	/* Do not write changes to disk until the source has been exported. */
1091 	if (!e_server_side_source_get_exported (E_SERVER_SIDE_SOURCE (source)))
1092 		return;
1093 
1094 	dbus_object = e_source_ref_dbus_object (source);
1095 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1096 
1097 	old_data = e_dbus_source_dup_data (dbus_source);
1098 	new_data = e_source_to_string (source, NULL);
1099 
1100 	/* Setting the "data" property triggers the ESource::changed,
1101 	 * signal, which invokes this callback, which sets the "data"
1102 	 * property, etc.  This breaks an otherwise infinite loop. */
1103 	if (g_strcmp0 (old_data, new_data) != 0)
1104 		e_dbus_source_set_data (dbus_source, new_data);
1105 
1106 	g_free (old_data);
1107 	g_free (new_data);
1108 
1109 	g_object_unref (dbus_source);
1110 	g_object_unref (dbus_object);
1111 
1112 	/* This writes the "data" property to disk. */
1113 	e_source_write_sync (source, NULL, &error);
1114 
1115 	if (error != NULL) {
1116 		g_warning ("%s: %s", G_STRFUNC, error->message);
1117 		g_error_free (error);
1118 	}
1119 }
1120 
1121 static gboolean
server_side_source_remove_sync(ESource * source,GCancellable * cancellable,GError ** error)1122 server_side_source_remove_sync (ESource *source,
1123                                 GCancellable *cancellable,
1124                                 GError **error)
1125 {
1126 	EAsyncClosure *closure;
1127 	GAsyncResult *result;
1128 	gboolean success;
1129 
1130 	closure = e_async_closure_new ();
1131 
1132 	e_source_remove (
1133 		source, cancellable, e_async_closure_callback, closure);
1134 
1135 	result = e_async_closure_wait (closure);
1136 
1137 	success = e_source_remove_finish (source, result, error);
1138 
1139 	e_async_closure_free (closure);
1140 
1141 	return success;
1142 }
1143 
1144 static void
server_side_source_remove(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1145 server_side_source_remove (ESource *source,
1146                            GCancellable *cancellable,
1147                            GAsyncReadyCallback callback,
1148                            gpointer user_data)
1149 {
1150 	EServerSideSourcePrivate *priv;
1151 	GSimpleAsyncResult *simple;
1152 	ESourceRegistryServer *server;
1153 	GQueue queue = G_QUEUE_INIT;
1154 	GList *list, *link;
1155 	GError *error = NULL;
1156 
1157 	/* XXX Yes we block here.  We do this operation
1158 	 *     synchronously to keep the server code simple. */
1159 
1160 	priv = E_SERVER_SIDE_SOURCE (source)->priv;
1161 
1162 	simple = g_simple_async_result_new (
1163 		G_OBJECT (source), callback, user_data,
1164 		server_side_source_remove);
1165 
1166 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1167 
1168 	/* Collect the source and its descendants into a queue.
1169 	 * Do this before unexporting so we hold references to
1170 	 * all the removed sources. */
1171 	g_node_traverse (
1172 		&priv->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
1173 		(GNodeTraverseFunc) server_side_source_traverse_cb, &queue);
1174 
1175 	/* Unexport the object and its descendants. */
1176 	server = E_SOURCE_REGISTRY_SERVER (priv->server);
1177 	e_source_registry_server_remove_source (server, source);
1178 
1179 	list = g_queue_peek_head_link (&queue);
1180 
1181 	/* Delete the key file for each source in the queue. */
1182 	for (link = list; link != NULL; link = g_list_next (link)) {
1183 		EServerSideSource *child;
1184 		GFile *file;
1185 
1186 		child = E_SERVER_SIDE_SOURCE (link->data);
1187 		file = e_server_side_source_get_file (child);
1188 
1189 		if (file != NULL)
1190 			g_file_delete (file, cancellable, &error);
1191 
1192 		/* XXX Even though e_source_registry_server_remove_source()
1193 		 *     is called first, the object path is unexported from
1194 		 *     an idle callback some time after we have deleted the
1195 		 *     key file.  That creates a small window of time where
1196 		 *     the file is deleted but the object is still exported.
1197 		 *
1198 		 *     If a client calls e_source_remove() during that small
1199 		 *     window of time, we still want to report a successful
1200 		 *     removal, so disregard G_IO_ERROR_NOT_FOUND. */
1201 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
1202 			g_clear_error (&error);
1203 
1204 		if (error != NULL)
1205 			goto exit;
1206 	}
1207 
1208 exit:
1209 	while (!g_queue_is_empty (&queue))
1210 		g_object_unref (g_queue_pop_head (&queue));
1211 
1212 	if (error != NULL)
1213 		g_simple_async_result_take_error (simple, error);
1214 
1215 	g_simple_async_result_complete_in_idle (simple);
1216 	g_object_unref (simple);
1217 }
1218 
1219 static gboolean
server_side_source_remove_finish(ESource * source,GAsyncResult * result,GError ** error)1220 server_side_source_remove_finish (ESource *source,
1221                                   GAsyncResult *result,
1222                                   GError **error)
1223 {
1224 	GSimpleAsyncResult *simple;
1225 
1226 	g_return_val_if_fail (
1227 		g_simple_async_result_is_valid (
1228 		result, G_OBJECT (source),
1229 		server_side_source_remove), FALSE);
1230 
1231 	simple = G_SIMPLE_ASYNC_RESULT (result);
1232 
1233 	/* Assume success unless a GError is set. */
1234 	return !g_simple_async_result_propagate_error (simple, error);
1235 }
1236 
1237 static gboolean
server_side_source_write_sync(ESource * source,GCancellable * cancellable,GError ** error)1238 server_side_source_write_sync (ESource *source,
1239                                GCancellable *cancellable,
1240                                GError **error)
1241 {
1242 	EAsyncClosure *closure;
1243 	GAsyncResult *result;
1244 	gboolean success;
1245 
1246 	closure = e_async_closure_new ();
1247 
1248 	e_source_write (
1249 		source, cancellable, e_async_closure_callback, closure);
1250 
1251 	result = e_async_closure_wait (closure);
1252 
1253 	success = e_source_write_finish (source, result, error);
1254 
1255 	e_async_closure_free (closure);
1256 
1257 	return success;
1258 }
1259 
1260 static void
server_side_source_write(ESource * source,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1261 server_side_source_write (ESource *source,
1262                           GCancellable *cancellable,
1263                           GAsyncReadyCallback callback,
1264                           gpointer user_data)
1265 {
1266 	EServerSideSourcePrivate *priv;
1267 	GSimpleAsyncResult *simple;
1268 	GDBusObject *dbus_object;
1269 	EDBusSource *dbus_source;
1270 	gboolean replace_file;
1271 	const gchar *old_data;
1272 	gchar *new_data;
1273 	GError *error = NULL;
1274 
1275 	/* XXX Yes we block here.  We do this operation
1276 	 *     synchronously to keep the server code simple. */
1277 
1278 	priv = E_SERVER_SIDE_SOURCE (source)->priv;
1279 
1280 	simple = g_simple_async_result_new (
1281 		G_OBJECT (source), callback, user_data,
1282 		server_side_source_write);
1283 
1284 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1285 
1286 	dbus_object = e_source_ref_dbus_object (source);
1287 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1288 
1289 	old_data = priv->file_contents;
1290 	new_data = e_source_to_string (source, NULL);
1291 
1292 	/* When writing source data to disk, we always write to the
1293 	 * source's specified "write-directory" even if the key file
1294 	 * was originally read from a different directory.  To avoid
1295 	 * polluting the write directory with key files identical to
1296 	 * the original, we check that the data has actually changed
1297 	 * before writing a copy to disk. */
1298 
1299 	replace_file =
1300 		G_IS_FILE (priv->file) &&
1301 		(g_strcmp0 (old_data, new_data) != 0);
1302 
1303 	if (replace_file) {
1304 		GFile *file;
1305 		GFile *write_directory;
1306 		gchar *basename;
1307 
1308 		g_warn_if_fail (priv->write_directory != NULL);
1309 
1310 		basename = g_file_get_basename (priv->file);
1311 		write_directory = g_file_new_for_path (priv->write_directory);
1312 		file = g_file_get_child (write_directory, basename);
1313 		g_free (basename);
1314 
1315 		if (!g_file_equal (file, priv->file)) {
1316 			g_object_unref (priv->file);
1317 			priv->file = g_object_ref (file);
1318 		}
1319 
1320 		server_side_source_print_diff (source, old_data, new_data);
1321 
1322 		g_file_make_directory_with_parents (
1323 			write_directory, cancellable, &error);
1324 
1325 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
1326 			g_clear_error (&error);
1327 
1328 		if (error == NULL)
1329 			g_file_replace_contents (
1330 				file, new_data, strlen (new_data),
1331 				NULL, FALSE, G_FILE_CREATE_NONE,
1332 				NULL, cancellable, &error);
1333 
1334 		if (error == NULL) {
1335 			g_free (priv->file_contents);
1336 			priv->file_contents = new_data;
1337 			new_data = NULL;
1338 		}
1339 
1340 		g_object_unref (write_directory);
1341 		g_object_unref (file);
1342 	}
1343 
1344 	g_free (new_data);
1345 
1346 	g_object_unref (dbus_source);
1347 	g_object_unref (dbus_object);
1348 
1349 	if (error != NULL)
1350 		g_simple_async_result_take_error (simple, error);
1351 
1352 	g_simple_async_result_complete_in_idle (simple);
1353 	g_object_unref (simple);
1354 }
1355 
1356 static gboolean
server_side_source_write_finish(ESource * source,GAsyncResult * result,GError ** error)1357 server_side_source_write_finish (ESource *source,
1358                                  GAsyncResult *result,
1359                                  GError **error)
1360 {
1361 	GSimpleAsyncResult *simple;
1362 
1363 	g_return_val_if_fail (
1364 		g_simple_async_result_is_valid (
1365 		result, G_OBJECT (source),
1366 		server_side_source_write), FALSE);
1367 
1368 	simple = G_SIMPLE_ASYNC_RESULT (result);
1369 
1370 	/* Assume success unless a GError is set. */
1371 	return !g_simple_async_result_propagate_error (simple, error);
1372 }
1373 
1374 static gboolean
server_side_source_remote_create_sync(ESource * source,ESource * scratch_source,GCancellable * cancellable,GError ** error)1375 server_side_source_remote_create_sync (ESource *source,
1376                                        ESource *scratch_source,
1377                                        GCancellable *cancellable,
1378                                        GError **error)
1379 {
1380 	ECollectionBackend *backend;
1381 	ESourceRegistryServer *server;
1382 	EServerSideSource *server_side_source;
1383 	gboolean success;
1384 
1385 	if (!e_source_get_remote_creatable (source)) {
1386 		g_set_error (
1387 			error, G_IO_ERROR,
1388 			G_IO_ERROR_NOT_SUPPORTED,
1389 			_("Data source “%s” does not "
1390 			"support creating remote resources"),
1391 			e_source_get_display_name (source));
1392 		return FALSE;
1393 	}
1394 
1395 	server_side_source = E_SERVER_SIDE_SOURCE (source);
1396 	server = e_server_side_source_get_server (server_side_source);
1397 	backend = e_source_registry_server_ref_backend (server, source);
1398 
1399 	if (backend == NULL) {
1400 		g_set_error (
1401 			error, G_IO_ERROR,
1402 			G_IO_ERROR_NOT_SUPPORTED,
1403 			_("Data source “%s” has no collection "
1404 			"backend to create the remote resource"),
1405 			e_source_get_display_name (source));
1406 		return FALSE;
1407 	}
1408 
1409 	success = e_collection_backend_create_resource_sync (
1410 		backend, scratch_source, cancellable, error);
1411 
1412 	g_object_unref (backend);
1413 
1414 	return success;
1415 }
1416 
1417 static gboolean
server_side_source_remote_delete_sync(ESource * source,GCancellable * cancellable,GError ** error)1418 server_side_source_remote_delete_sync (ESource *source,
1419                                        GCancellable *cancellable,
1420                                        GError **error)
1421 {
1422 	ECollectionBackend *backend;
1423 	ESourceRegistryServer *server;
1424 	EServerSideSource *server_side_source;
1425 	gboolean success;
1426 
1427 	if (!e_source_get_remote_deletable (source)) {
1428 		g_set_error (
1429 			error, G_IO_ERROR,
1430 			G_IO_ERROR_NOT_SUPPORTED,
1431 			_("Data source “%s” does not "
1432 			"support deleting remote resources"),
1433 			e_source_get_display_name (source));
1434 		return FALSE;
1435 	}
1436 
1437 	server_side_source = E_SERVER_SIDE_SOURCE (source);
1438 	server = e_server_side_source_get_server (server_side_source);
1439 	backend = e_source_registry_server_ref_backend (server, source);
1440 
1441 	if (backend == NULL) {
1442 		g_set_error (
1443 			error, G_IO_ERROR,
1444 			G_IO_ERROR_NOT_SUPPORTED,
1445 			_("Data source “%s” has no collection "
1446 			"backend to delete the remote resource"),
1447 			e_source_get_display_name (source));
1448 		return FALSE;
1449 	}
1450 
1451 	success = e_collection_backend_delete_resource_sync (
1452 		backend, source, cancellable, error);
1453 
1454 	g_object_unref (backend);
1455 
1456 	return success;
1457 }
1458 
1459 static gboolean
server_side_source_get_oauth2_access_token_sync(ESource * source,GCancellable * cancellable,gchar ** out_access_token,gint * out_expires_in,GError ** error)1460 server_side_source_get_oauth2_access_token_sync (ESource *source,
1461                                                  GCancellable *cancellable,
1462                                                  gchar **out_access_token,
1463                                                  gint *out_expires_in,
1464                                                  GError **error)
1465 {
1466 	EOAuth2Support *oauth2_support;
1467 	gboolean success;
1468 
1469 	oauth2_support = e_server_side_source_ref_oauth2_support (
1470 		E_SERVER_SIDE_SOURCE (source));
1471 
1472 	if (oauth2_support == NULL) {
1473 		ESourceRegistryServer *server;
1474 
1475 		server = e_server_side_source_get_server (E_SERVER_SIDE_SOURCE (source));
1476 
1477 		if (server)
1478 			oauth2_support = e_source_registry_server_ref_oauth2_support (server);
1479 
1480 		if (!oauth2_support) {
1481 			g_set_error (
1482 				error, G_IO_ERROR,
1483 				G_IO_ERROR_NOT_SUPPORTED,
1484 				_("Data source “%s” does not "
1485 				"support OAuth 2.0 authentication"),
1486 				e_source_get_display_name (source));
1487 			return FALSE;
1488 		}
1489 	}
1490 
1491 	success = e_oauth2_support_get_access_token_sync (
1492 		oauth2_support, source, cancellable,
1493 		out_access_token, out_expires_in, error);
1494 
1495 	g_object_unref (oauth2_support);
1496 
1497 	return success;
1498 }
1499 
1500 static gboolean
server_side_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)1501 server_side_source_invoke_credentials_required_impl (ESource *source,
1502 						     gpointer dbus_source, /* EDBusSource * */
1503 						     const gchar *arg_reason,
1504 						     const gchar *arg_certificate_pem,
1505 						     const gchar *arg_certificate_errors,
1506 						     const gchar *arg_dbus_error_name,
1507 						     const gchar *arg_dbus_error_message,
1508 						     GCancellable *cancellable,
1509 						     GError **error)
1510 {
1511 	g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1512 
1513 	return server_side_source_invoke_credentials_required_cb (dbus_source, NULL,
1514 		arg_reason ? arg_reason : "",
1515 		arg_certificate_pem ? arg_certificate_pem : "",
1516 		arg_certificate_errors ? arg_certificate_errors : "",
1517 		arg_dbus_error_name ? arg_dbus_error_name : "",
1518 		arg_dbus_error_message ? arg_dbus_error_message : "",
1519 		E_SERVER_SIDE_SOURCE (source));
1520 }
1521 
1522 static gboolean
server_side_source_invoke_authenticate_impl(ESource * source,gpointer dbus_source,const gchar * const * arg_credentials,GCancellable * cancellable,GError ** error)1523 server_side_source_invoke_authenticate_impl (ESource *source,
1524 					     gpointer dbus_source, /* EDBusSource * */
1525 					     const gchar * const *arg_credentials,
1526 					     GCancellable *cancellable,
1527 					     GError **error)
1528 {
1529 	g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
1530 
1531 	return server_side_source_invoke_authenticate_cb (dbus_source, NULL,
1532 		arg_credentials, E_SERVER_SIDE_SOURCE (source));
1533 }
1534 
1535 static gboolean
server_side_source_unset_last_credentials_required_arguments_impl(ESource * source,GCancellable * cancellable,GError ** error)1536 server_side_source_unset_last_credentials_required_arguments_impl (ESource *source,
1537 								   GCancellable *cancellable,
1538 								   GError **error)
1539 {
1540 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1541 
1542 	server_side_source_unset_last_credentials_required_arguments (E_SERVER_SIDE_SOURCE (source));
1543 
1544 	return TRUE;
1545 }
1546 
1547 static gboolean
server_side_source_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)1548 server_side_source_initable_init (GInitable *initable,
1549                                   GCancellable *cancellable,
1550                                   GError **error)
1551 {
1552 	EServerSideSource *source;
1553 	GDBusObject *dbus_object;
1554 	EDBusSource *dbus_source;
1555 	gchar *uid;
1556 
1557 	source = E_SERVER_SIDE_SOURCE (initable);
1558 
1559 	dbus_source = e_dbus_source_skeleton_new ();
1560 
1561 	uid = e_source_dup_uid (E_SOURCE (source));
1562 	if (uid == NULL)
1563 		uid = e_util_generate_uid ();
1564 	e_dbus_source_set_uid (dbus_source, uid);
1565 	g_free (uid);
1566 
1567 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1568 	e_dbus_object_skeleton_set_source (
1569 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_source);
1570 	g_object_unref (dbus_object);
1571 
1572 	g_signal_connect (
1573 		dbus_source, "handle-invoke-credentials-required",
1574 		G_CALLBACK (server_side_source_invoke_credentials_required_cb), source);
1575 	g_signal_connect (
1576 		dbus_source, "handle-invoke-authenticate",
1577 		G_CALLBACK (server_side_source_invoke_authenticate_cb), source);
1578 	g_signal_connect (
1579 		dbus_source, "handle-get-last-credentials-required-arguments",
1580 		G_CALLBACK (server_side_source_get_last_credentials_required_arguments_cb), source);
1581 	g_signal_connect (
1582 		dbus_source, "handle-unset-last-credentials-required-arguments",
1583 		G_CALLBACK (server_side_source_unset_last_credentials_required_arguments_cb), source);
1584 
1585 	g_object_unref (dbus_source);
1586 
1587 	if (!e_server_side_source_load (source, cancellable, error))
1588 		return FALSE;
1589 
1590 	/* Chain up to parent interface's init() method. */
1591 	return initable_parent_interface->init (initable, cancellable, error);
1592 }
1593 
1594 static void
e_server_side_source_class_init(EServerSideSourceClass * class)1595 e_server_side_source_class_init (EServerSideSourceClass *class)
1596 {
1597 	GObjectClass *object_class;
1598 	ESourceClass *source_class;
1599 
1600 	object_class = G_OBJECT_CLASS (class);
1601 	object_class->set_property = server_side_source_set_property;
1602 	object_class->get_property = server_side_source_get_property;
1603 	object_class->dispose = server_side_source_dispose;
1604 	object_class->finalize = server_side_source_finalize;
1605 
1606 	source_class = E_SOURCE_CLASS (class);
1607 	source_class->changed = server_side_source_changed;
1608 	source_class->remove_sync = server_side_source_remove_sync;
1609 	source_class->remove = server_side_source_remove;
1610 	source_class->remove_finish = server_side_source_remove_finish;
1611 	source_class->write_sync = server_side_source_write_sync;
1612 	source_class->write = server_side_source_write;
1613 	source_class->write_finish = server_side_source_write_finish;
1614 	source_class->remote_create_sync = server_side_source_remote_create_sync;
1615 	source_class->remote_delete_sync = server_side_source_remote_delete_sync;
1616 	source_class->get_oauth2_access_token_sync = server_side_source_get_oauth2_access_token_sync;
1617 	source_class->invoke_credentials_required_impl = server_side_source_invoke_credentials_required_impl;
1618 	source_class->invoke_authenticate_impl = server_side_source_invoke_authenticate_impl;
1619 	source_class->unset_last_credentials_required_arguments_impl = server_side_source_unset_last_credentials_required_arguments_impl;
1620 
1621 	g_object_class_install_property (
1622 		object_class,
1623 		PROP_EXPORTED,
1624 		g_param_spec_boolean (
1625 			"exported",
1626 			"Exported",
1627 			"Whether the source has been exported over D-Bus",
1628 			FALSE,
1629 			G_PARAM_READABLE |
1630 			G_PARAM_STATIC_STRINGS));
1631 
1632 	g_object_class_install_property (
1633 		object_class,
1634 		PROP_FILE,
1635 		g_param_spec_object (
1636 			"file",
1637 			"File",
1638 			"The key file for the data source",
1639 			G_TYPE_FILE,
1640 			G_PARAM_READWRITE |
1641 			G_PARAM_CONSTRUCT_ONLY |
1642 			G_PARAM_STATIC_STRINGS));
1643 
1644 	g_object_class_install_property (
1645 		object_class,
1646 		PROP_OAUTH2_SUPPORT,
1647 		g_param_spec_object (
1648 			"oauth2-support",
1649 			"OAuth2 Support",
1650 			"The object providing OAuth 2.0 support",
1651 			E_TYPE_OAUTH2_SUPPORT,
1652 			G_PARAM_READWRITE |
1653 			G_PARAM_EXPLICIT_NOTIFY |
1654 			G_PARAM_STATIC_STRINGS));
1655 
1656 	/* This overrides the "remote-creatable" property
1657 	 * in ESourceClass with a writable version. */
1658 	g_object_class_install_property (
1659 		object_class,
1660 		PROP_REMOTE_CREATABLE,
1661 		g_param_spec_boolean (
1662 			"remote-creatable",
1663 			"Remote Creatable",
1664 			"Whether the data source "
1665 			"can create remote resources",
1666 			FALSE,
1667 			G_PARAM_READWRITE |
1668 			G_PARAM_EXPLICIT_NOTIFY |
1669 			G_PARAM_STATIC_STRINGS));
1670 
1671 	/* This overrides the "remote-deletable" property
1672 	 * in ESourceClass with a writable version. */
1673 	g_object_class_install_property (
1674 		object_class,
1675 		PROP_REMOTE_DELETABLE,
1676 		g_param_spec_boolean (
1677 			"remote-deletable",
1678 			"Remote Deletable",
1679 			"Whether the data source "
1680 			"can delete remote resources",
1681 			FALSE,
1682 			G_PARAM_READWRITE |
1683 			G_PARAM_EXPLICIT_NOTIFY |
1684 			G_PARAM_STATIC_STRINGS));
1685 
1686 	/* This overrides the "removable" property
1687 	 * in ESourceClass with a writable version. */
1688 	g_object_class_install_property (
1689 		object_class,
1690 		PROP_REMOVABLE,
1691 		g_param_spec_boolean (
1692 			"removable",
1693 			"Removable",
1694 			"Whether the data source is removable",
1695 			FALSE,
1696 			G_PARAM_READWRITE |
1697 			G_PARAM_EXPLICIT_NOTIFY |
1698 			G_PARAM_STATIC_STRINGS));
1699 
1700 	g_object_class_install_property (
1701 		object_class,
1702 		PROP_SERVER,
1703 		g_param_spec_object (
1704 			"server",
1705 			"Server",
1706 			"The server to which the data source belongs",
1707 			E_TYPE_SOURCE_REGISTRY_SERVER,
1708 			G_PARAM_READWRITE |
1709 			G_PARAM_CONSTRUCT_ONLY |
1710 			G_PARAM_STATIC_STRINGS));
1711 
1712 	/* This overrides the "writable" property
1713 	 * in ESourceClass with a writable version. */
1714 	g_object_class_install_property (
1715 		object_class,
1716 		PROP_WRITABLE,
1717 		g_param_spec_boolean (
1718 			"writable",
1719 			"Writable",
1720 			"Whether the data source is writable",
1721 			FALSE,
1722 			G_PARAM_READWRITE |
1723 			G_PARAM_EXPLICIT_NOTIFY |
1724 			G_PARAM_STATIC_STRINGS));
1725 
1726 	/* Do not use G_PARAM_CONSTRUCT.  We initialize the
1727 	 * property ourselves in e_server_side_source_init(). */
1728 	g_object_class_install_property (
1729 		object_class,
1730 		PROP_WRITE_DIRECTORY,
1731 		g_param_spec_string (
1732 			"write-directory",
1733 			"Write Directory",
1734 			"Directory in which to write changes to disk",
1735 			NULL,
1736 			G_PARAM_READWRITE |
1737 			G_PARAM_EXPLICIT_NOTIFY |
1738 			G_PARAM_STATIC_STRINGS));
1739 }
1740 
1741 static void
e_server_side_source_initable_init(GInitableIface * iface)1742 e_server_side_source_initable_init (GInitableIface *iface)
1743 {
1744 	initable_parent_interface = g_type_interface_peek_parent (iface);
1745 
1746 	iface->init = server_side_source_initable_init;
1747 }
1748 
1749 static void
e_server_side_source_init(EServerSideSource * source)1750 e_server_side_source_init (EServerSideSource *source)
1751 {
1752 	const gchar *user_dir;
1753 
1754 	source->priv = e_server_side_source_get_instance_private (source);
1755 
1756 	source->priv->node.data = source;
1757 
1758 	user_dir = e_server_side_source_get_user_dir ();
1759 	source->priv->write_directory = g_strdup (user_dir);
1760 
1761 	g_weak_ref_init (&source->priv->oauth2_support, NULL);
1762 	g_mutex_init (&source->priv->last_values_lock);
1763 	g_mutex_init (&source->priv->pending_credentials_lookup_lock);
1764 }
1765 
1766 /**
1767  * e_server_side_source_get_user_dir:
1768  *
1769  * Returns the directory where user-specific data source files are stored.
1770  *
1771  * Returns: the user-specific data source directory
1772  *
1773  * Since: 3.6
1774  **/
1775 const gchar *
e_server_side_source_get_user_dir(void)1776 e_server_side_source_get_user_dir (void)
1777 {
1778 	static gchar *dirname = NULL;
1779 
1780 	if (G_UNLIKELY (dirname == NULL)) {
1781 		const gchar *config_dir = e_get_user_config_dir ();
1782 		dirname = g_build_filename (config_dir, "sources", NULL);
1783 		g_mkdir_with_parents (dirname, 0700);
1784 	}
1785 
1786 	return dirname;
1787 }
1788 
1789 /**
1790  * e_server_side_source_new_user_file:
1791  * @uid: unique identifier for a data source, or %NULL
1792  *
1793  * Generates a unique file name for a new user-specific data source.
1794  * If @uid is non-%NULL it will be used in the basename of the file,
1795  * otherwise a unique basename will be generated using e_util_generate_uid().
1796  *
1797  * The returned #GFile can then be passed to e_server_side_source_new().
1798  * Unreference the #GFile with g_object_unref() when finished with it.
1799  *
1800  * Note the data source file itself is not created here, only its name.
1801  *
1802  * Returns: (transfer full): the #GFile for a new data source
1803  *
1804  * Since: 3.6
1805  **/
1806 GFile *
e_server_side_source_new_user_file(const gchar * uid)1807 e_server_side_source_new_user_file (const gchar *uid)
1808 {
1809 	GFile *file;
1810 	gchar *safe_uid;
1811 	gchar *basename;
1812 	gchar *filename;
1813 	const gchar *user_dir;
1814 
1815 	if (uid == NULL)
1816 		safe_uid = e_util_generate_uid ();
1817 	else
1818 		safe_uid = g_strdup (uid);
1819 	e_filename_make_safe (safe_uid);
1820 
1821 	user_dir = e_server_side_source_get_user_dir ();
1822 	basename = g_strconcat (safe_uid, ".source", NULL);
1823 	filename = g_build_filename (user_dir, basename, NULL);
1824 
1825 	file = g_file_new_for_path (filename);
1826 
1827 	g_free (basename);
1828 	g_free (filename);
1829 	g_free (safe_uid);
1830 
1831 	return file;
1832 }
1833 
1834 /**
1835  * e_server_side_source_uid_from_file:
1836  * @file: a #GFile for a data source
1837  * @error: return location for a #GError, or %NULL
1838  *
1839  * Extracts a unique identity string from the base name of @file.
1840  * If the base name of @file is missing a '.source' extension, the
1841  * function sets @error and returns %NULL.
1842  *
1843  * Returns: the unique identity string for @file, or %NULL
1844  *
1845  * Since: 3.6
1846  **/
1847 gchar *
e_server_side_source_uid_from_file(GFile * file,GError ** error)1848 e_server_side_source_uid_from_file (GFile *file,
1849                                     GError **error)
1850 {
1851 	gchar *basename;
1852 	gchar *uid = NULL;
1853 
1854 	g_return_val_if_fail (G_IS_FILE (file), FALSE);
1855 
1856 	basename = g_file_get_basename (file);
1857 
1858 	if (*basename == '.') {
1859 		/* ignore hidden files */
1860 	} else if (g_str_has_suffix (basename, ".source")) {
1861 		/* strlen(".source") --> 7 */
1862 		uid = g_strndup (basename, strlen (basename) - 7);
1863 	} else {
1864 		g_set_error (
1865 			error, G_IO_ERROR,
1866 			G_IO_ERROR_INVALID_FILENAME,
1867 			_("File must have a “.source” extension"));
1868 	}
1869 
1870 	g_free (basename);
1871 
1872 	return uid;
1873 }
1874 
1875 /**
1876  * e_server_side_source_new:
1877  * @server: an #ESourceRegistryServer
1878  * @file: a #GFile, or %NULL
1879  * @error: return location for a #GError, or %NULL
1880  *
1881  * Creates a new #EServerSideSource which belongs to @server.  If @file
1882  * is non-%NULL and points to an existing file, the #EServerSideSource is
1883  * initialized from the file content.  If a read error occurs or the file
1884  * contains syntax errors, the function sets @error and returns %NULL.
1885  *
1886  * Returns: a new #EServerSideSource, or %NULL
1887  *
1888  * Since: 3.6
1889  **/
1890 ESource *
e_server_side_source_new(ESourceRegistryServer * server,GFile * file,GError ** error)1891 e_server_side_source_new (ESourceRegistryServer *server,
1892                           GFile *file,
1893                           GError **error)
1894 {
1895 	EDBusObjectSkeleton *dbus_object;
1896 	ESource *source;
1897 	gchar *uid = NULL;
1898 
1899 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1900 	g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
1901 
1902 	/* Extract a UID from the GFile, if we were given one. */
1903 	if (file != NULL) {
1904 		uid = e_server_side_source_uid_from_file (file, error);
1905 		if (uid == NULL)
1906 			return NULL;
1907 	}
1908 
1909 	/* XXX This is an awkward way of initializing the "dbus-object"
1910 	 *     property, but e_source_ref_dbus_object() needs to work. */
1911 	dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1912 
1913 	source = g_initable_new (
1914 		E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1915 		"dbus-object", dbus_object,
1916 		"file", file, "server", server,
1917 		"uid", uid, NULL);
1918 
1919 	g_object_unref (dbus_object);
1920 	g_free (uid);
1921 
1922 	return source;
1923 }
1924 
1925 /**
1926  * e_server_side_source_new_memory_only:
1927  * @server: an #ESourceRegistryServer
1928  * @uid: a unique identifier, or %NULL
1929  * @error: return location for a #GError, or %NULL
1930  *
1931  * Creates a memory-only #EServerSideSource which belongs to @server.
1932  * No on-disk key file is created for this data source, so it will not
1933  * be remembered across sessions.
1934  *
1935  * Data source collections are often populated with memory-only data
1936  * sources to serve as proxies for resources discovered on a remote server.
1937  * These data sources are usually neither #EServerSideSource:writable nor
1938  * #EServerSideSource:removable by clients, at least not directly.
1939  *
1940  * If an error occurs while instantiating the #EServerSideSource, the
1941  * function sets @error and returns %NULL.  Although at this time there
1942  * are no known error conditions for memory-only data sources.
1943  *
1944  * Returns: a new memory-only #EServerSideSource, or %NULL
1945  *
1946  * Since: 3.6
1947  **/
1948 ESource *
e_server_side_source_new_memory_only(ESourceRegistryServer * server,const gchar * uid,GError ** error)1949 e_server_side_source_new_memory_only (ESourceRegistryServer *server,
1950                                       const gchar *uid,
1951                                       GError **error)
1952 {
1953 	EDBusObjectSkeleton *dbus_object;
1954 	ESource *source;
1955 
1956 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1957 
1958 	/* XXX This is an awkward way of initializing the "dbus-object"
1959 	 *     property, but e_source_ref_dbus_object() needs to work. */
1960 	dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1961 
1962 	source = g_initable_new (
1963 		E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1964 		"dbus-object", dbus_object,
1965 		"server", server, "uid", uid, NULL);
1966 
1967 	g_object_unref (dbus_object);
1968 
1969 	return source;
1970 }
1971 
1972 /**
1973  * e_server_side_source_load:
1974  * @source: an #EServerSideSource
1975  * @cancellable: optional #GCancellable object, or %NULL
1976  * @error: return location for a #GError, or %NULL
1977  *
1978  * Reloads data source content from the file pointed to by the
1979  * #EServerSideSource:file property.
1980  *
1981  * If the #EServerSideSource:file property is %NULL or the file it points
1982  * to does not exist, the function does nothing and returns %TRUE.
1983  *
1984  * If a read error occurs or the file contains syntax errors, the function
1985  * sets @error and returns %FALSE.
1986  *
1987  * Returns: %TRUE on success, %FALSE on failure
1988  *
1989  * Since: 3.6
1990  **/
1991 gboolean
e_server_side_source_load(EServerSideSource * source,GCancellable * cancellable,GError ** error)1992 e_server_side_source_load (EServerSideSource *source,
1993                            GCancellable *cancellable,
1994                            GError **error)
1995 {
1996 	GDBusObject *dbus_object;
1997 	EDBusSource *dbus_source;
1998 	GKeyFile *key_file;
1999 	GFile *file;
2000 	gboolean success = TRUE;
2001 	gchar *data = NULL;
2002 	gsize length;
2003 	GError *local_error = NULL;
2004 
2005 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
2006 
2007 	file = e_server_side_source_get_file (source);
2008 
2009 	if (file != NULL && !g_file_load_contents (file, cancellable, &data, &length, NULL, &local_error)) {
2010 		data = NULL;
2011 		length = 0;
2012 	}
2013 
2014 	/* Disregard G_IO_ERROR_NOT_FOUND and treat it as a successful load. */
2015 	if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
2016 		g_error_free (local_error);
2017 
2018 	} else if (local_error != NULL) {
2019 		g_propagate_error (error, local_error);
2020 		return FALSE;
2021 
2022 	} else {
2023 		g_free (source->priv->file_contents);
2024 		source->priv->file_contents = g_strdup (data);
2025 	}
2026 
2027 	if (data == NULL) {
2028 		/* Create the bare minimum to pass parse_data(). */
2029 		data = g_strdup_printf ("[%s]", PRIMARY_GROUP_NAME);
2030 		length = strlen (data);
2031 	}
2032 
2033 	key_file = g_key_file_new ();
2034 
2035 	success = server_side_source_parse_data (
2036 		key_file, data, length, error);
2037 
2038 	g_key_file_free (key_file);
2039 
2040 	if (!success) {
2041 		g_free (data);
2042 		return FALSE;
2043 	}
2044 
2045 	/* Update the D-Bus interface properties. */
2046 
2047 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2048 	dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
2049 
2050 	e_dbus_source_set_data (dbus_source, data);
2051 
2052 	g_object_unref (dbus_source);
2053 	g_object_unref (dbus_object);
2054 
2055 	g_free (data);
2056 
2057 	return TRUE;
2058 }
2059 
2060 /**
2061  * e_server_side_source_get_file:
2062  * @source: an #EServerSideSource
2063  *
2064  * Returns the #GFile from which data source content is loaded and to
2065  * which changes are saved.  Note the @source may not have a #GFile.
2066  *
2067  * Returns: (transfer none) (nullable): the #GFile for @source, or %NULL
2068  *
2069  * Since: 3.6
2070  **/
2071 GFile *
e_server_side_source_get_file(EServerSideSource * source)2072 e_server_side_source_get_file (EServerSideSource *source)
2073 {
2074 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2075 
2076 	return source->priv->file;
2077 }
2078 
2079 /**
2080  * e_server_side_source_get_node:
2081  * @source: an #EServerSideSource
2082  *
2083  * Returns the #GNode representing the @source's hierarchical placement,
2084  * or %NULL if @source has not been placed in the data source hierarchy.
2085  * The data member of the #GNode points back to @source.  This is an easy
2086  * way to traverse ancestor and descendant data sources.
2087  *
2088  * Note that accessing other data sources this way is not thread-safe,
2089  * and this therefore function may be replaced at some later date.
2090  *
2091  * Returns: (transfer none) (nullable): a #GNode, or %NULL
2092  *
2093  * Since: 3.6
2094  **/
2095 GNode *
e_server_side_source_get_node(EServerSideSource * source)2096 e_server_side_source_get_node (EServerSideSource *source)
2097 {
2098 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2099 
2100 	return &source->priv->node;
2101 }
2102 
2103 /**
2104  * e_server_side_source_get_server:
2105  * @source: an #EServerSideSource
2106  *
2107  * Returns the #ESourceRegistryServer to which @source belongs.
2108  *
2109  * Returns: (transfer none): the #ESourceRegistryServer for @source
2110  *
2111  * Since: 3.6
2112  **/
2113 ESourceRegistryServer *
e_server_side_source_get_server(EServerSideSource * source)2114 e_server_side_source_get_server (EServerSideSource *source)
2115 {
2116 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2117 
2118 	return source->priv->server;
2119 }
2120 
2121 /**
2122  * e_server_side_source_get_exported:
2123  * @source: an #EServerSideSource
2124  *
2125  * Returns whether @source has been exported over D-Bus.
2126  *
2127  * The function returns %FALSE after @source is initially created, %TRUE
2128  * after passing @source uid to e_source_registry_server_ref_source() (provided
2129  * that @source's #ESource:parent is also exported).
2130  *
2131  * Returns: whether @source has been exported
2132  *
2133  * Since: 3.6
2134  **/
2135 gboolean
e_server_side_source_get_exported(EServerSideSource * source)2136 e_server_side_source_get_exported (EServerSideSource *source)
2137 {
2138 	ESourceRegistryServer *server;
2139 	ESource *exported_source;
2140 	gboolean exported = FALSE;
2141 	const gchar *uid;
2142 
2143 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
2144 
2145 	uid = e_source_get_uid (E_SOURCE (source));
2146 	server = e_server_side_source_get_server (source);
2147 
2148 	/* We're exported if we can look ourselves up in the registry. */
2149 
2150 	exported_source = e_source_registry_server_ref_source (server, uid);
2151 	if (exported_source != NULL) {
2152 		exported = TRUE;
2153 		g_object_unref (exported_source);
2154 	}
2155 
2156 	return exported;
2157 }
2158 
2159 /**
2160  * e_server_side_source_get_write_directory:
2161  * @source: an #EServerSideSource
2162  *
2163  * Returns the local directory path where changes to @source are written.
2164  *
2165  * By default, changes are written to the local directory path returned by
2166  * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
2167  * to override this to use its own private cache directory for data sources
2168  * it creates automatically.
2169  *
2170  * Returns: the directory where changes are written
2171  *
2172  * Since: 3.6
2173  **/
2174 const gchar *
e_server_side_source_get_write_directory(EServerSideSource * source)2175 e_server_side_source_get_write_directory (EServerSideSource *source)
2176 {
2177 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2178 
2179 	return source->priv->write_directory;
2180 }
2181 
2182 /**
2183  * e_server_side_source_set_write_directory:
2184  * @source: an #EServerSideSource
2185  * @write_directory: the directory where changes are to be written
2186  *
2187  * Sets the local directory path where changes to @source are to be written.
2188  *
2189  * By default, changes are written to the local directory path returned by
2190  * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
2191  * to override this to use its own private cache directory for data sources
2192  * it creates automatically.
2193  *
2194  * Since: 3.6
2195  **/
2196 void
e_server_side_source_set_write_directory(EServerSideSource * source,const gchar * write_directory)2197 e_server_side_source_set_write_directory (EServerSideSource *source,
2198                                           const gchar *write_directory)
2199 {
2200 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2201 	g_return_if_fail (write_directory != NULL);
2202 
2203 	if (g_strcmp0 (source->priv->write_directory, write_directory) == 0)
2204 		return;
2205 
2206 	g_free (source->priv->write_directory);
2207 	source->priv->write_directory = g_strdup (write_directory);
2208 
2209 	g_object_notify (G_OBJECT (source), "write-directory");
2210 }
2211 
2212 /**
2213  * e_server_side_source_set_removable:
2214  * @source: an #EServerSideSource
2215  * @removable: whether to export the Removable interface
2216  *
2217  * Sets whether to allow registry clients to remove @source and its
2218  * descendants.  If %TRUE, the Removable D-Bus interface is exported at
2219  * the object path for @source.  If %FALSE, the Removable D-Bus interface
2220  * is unexported at the object path for @source, and any attempt by clients
2221  * to call e_source_remove() will fail.
2222  *
2223  * Note this is only enforced for clients of the registry D-Bus service.
2224  * The service itself may remove any data source at any time.
2225  *
2226  * Since: 3.6
2227  **/
2228 void
e_server_side_source_set_removable(EServerSideSource * source,gboolean removable)2229 e_server_side_source_set_removable (EServerSideSource *source,
2230                                     gboolean removable)
2231 {
2232 	EDBusSourceRemovable *dbus_interface = NULL;
2233 	GDBusObject *dbus_object;
2234 	gboolean currently_removable;
2235 
2236 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2237 
2238 	currently_removable = e_source_get_removable (E_SOURCE (source));
2239 
2240 	if (removable == currently_removable)
2241 		return;
2242 
2243 	if (removable) {
2244 		dbus_interface =
2245 			e_dbus_source_removable_skeleton_new ();
2246 
2247 		g_signal_connect (
2248 			dbus_interface, "handle-remove",
2249 			G_CALLBACK (server_side_source_remove_cb), source);
2250 	}
2251 
2252 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2253 	e_dbus_object_skeleton_set_source_removable (
2254 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2255 	g_object_unref (dbus_object);
2256 
2257 	if (dbus_interface != NULL)
2258 		g_object_unref (dbus_interface);
2259 
2260 	g_object_notify (G_OBJECT (source), "removable");
2261 }
2262 
2263 /**
2264  * e_server_side_source_set_writable:
2265  * @source: an #EServerSideSource
2266  * @writable: whether to export the Writable interface
2267  *
2268  * Sets whether to allow registry clients to alter the content of @source.
2269  * If %TRUE, the Writable D-Bus interface is exported at the object path
2270  * for @source.  If %FALSE, the Writable D-Bus interface is unexported at
2271  * the object path for @source, and any attempt by clients to call
2272  * e_source_write() will fail.
2273  *
2274  * Note this is only enforced for clients of the registry D-Bus service.
2275  * The service itself can write to any data source at any time.
2276  *
2277  * Since: 3.6
2278  **/
2279 void
e_server_side_source_set_writable(EServerSideSource * source,gboolean writable)2280 e_server_side_source_set_writable (EServerSideSource *source,
2281                                    gboolean writable)
2282 {
2283 	EDBusSourceWritable *dbus_interface = NULL;
2284 	GDBusObject *dbus_object;
2285 	gboolean currently_writable;
2286 
2287 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2288 
2289 	currently_writable = e_source_get_writable (E_SOURCE (source));
2290 
2291 	if (writable == currently_writable)
2292 		return;
2293 
2294 	if (writable) {
2295 		dbus_interface =
2296 			e_dbus_source_writable_skeleton_new ();
2297 
2298 		g_signal_connect (
2299 			dbus_interface, "handle-write",
2300 			G_CALLBACK (server_side_source_write_cb), source);
2301 	}
2302 
2303 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2304 	e_dbus_object_skeleton_set_source_writable (
2305 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2306 	g_object_unref (dbus_object);
2307 
2308 	if (dbus_interface != NULL)
2309 		g_object_unref (dbus_interface);
2310 
2311 	g_object_notify (G_OBJECT (source), "writable");
2312 }
2313 
2314 /**
2315  * e_server_side_source_set_remote_creatable:
2316  * @source: an #EServerSideSource
2317  * @remote_creatable: whether to export the RemoteCreatable interface
2318  *
2319  * Indicates whether @source can be used to create resources on a remote
2320  * server.  Typically this is only set to %TRUE for collection sources.
2321  *
2322  * If %TRUE, the RemoteCreatable D-Bus interface is exported at the object
2323  * path for @source.  If %FALSE, the RemoteCreatable D-Bus interface is
2324  * unexported at the object path for @source, and any attempt by clients
2325  * to call e_source_remote_create() will fail.
2326  *
2327  * Unlike the #ESource:removable and #ESource:writable properties, this
2328  * is enforced for both clients of the registry D-Bus service and within
2329  * the registry D-Bus service itself.
2330  *
2331  * Since: 3.6
2332  **/
2333 void
e_server_side_source_set_remote_creatable(EServerSideSource * source,gboolean remote_creatable)2334 e_server_side_source_set_remote_creatable (EServerSideSource *source,
2335                                            gboolean remote_creatable)
2336 {
2337 	EDBusSourceRemoteCreatable *dbus_interface = NULL;
2338 	GDBusObject *dbus_object;
2339 	gboolean currently_remote_creatable;
2340 
2341 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2342 
2343 	currently_remote_creatable =
2344 		e_source_get_remote_creatable (E_SOURCE (source));
2345 
2346 	if (remote_creatable == currently_remote_creatable)
2347 		return;
2348 
2349 	if (remote_creatable) {
2350 		dbus_interface =
2351 			e_dbus_source_remote_creatable_skeleton_new ();
2352 
2353 		g_signal_connect (
2354 			dbus_interface, "handle-create",
2355 			G_CALLBACK (server_side_source_remote_create_cb),
2356 			source);
2357 	}
2358 
2359 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2360 	e_dbus_object_skeleton_set_source_remote_creatable (
2361 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2362 	g_object_unref (dbus_object);
2363 
2364 	if (dbus_interface != NULL)
2365 		g_object_unref (dbus_interface);
2366 
2367 	g_object_notify (G_OBJECT (source), "remote-creatable");
2368 }
2369 
2370 /**
2371  * e_server_side_source_set_remote_deletable:
2372  * @source: an #EServerSideSource
2373  * @remote_deletable: whether to export the RemoteDeletable interface
2374  *
2375  * Indicates whether @source can be used to delete resources on a remote
2376  * server.  Typically this is only set to %TRUE for sources created by an
2377  * #ECollectionBackend to represent a remote resource.
2378  *
2379  * If %TRUE, the RemoteDeletable D-Bus interface is exported at the object
2380  * path for @source.  If %FALSE, the RemoteDeletable D-Bus interface is
2381  * unexported at the object path for @source, and any attempt by clients
2382  * to call e_source_remote_delete() will fail.
2383  *
2384  * Unlike the #ESource:removable and #ESource:writable properties, this
2385  * is enforced for both clients of the registry D-Bus server and within
2386  * the registry D-Bus service itself.
2387  *
2388  * Since: 3.6
2389  **/
2390 void
e_server_side_source_set_remote_deletable(EServerSideSource * source,gboolean remote_deletable)2391 e_server_side_source_set_remote_deletable (EServerSideSource *source,
2392                                            gboolean remote_deletable)
2393 {
2394 	EDBusSourceRemoteDeletable *dbus_interface = NULL;
2395 	GDBusObject *dbus_object;
2396 	gboolean currently_remote_deletable;
2397 
2398 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2399 
2400 	currently_remote_deletable =
2401 		e_source_get_remote_deletable (E_SOURCE (source));
2402 
2403 	if (remote_deletable == currently_remote_deletable)
2404 		return;
2405 
2406 	if (remote_deletable) {
2407 		dbus_interface =
2408 			e_dbus_source_remote_deletable_skeleton_new ();
2409 
2410 		g_signal_connect (
2411 			dbus_interface, "handle-delete",
2412 			G_CALLBACK (server_side_source_remote_delete_cb),
2413 			source);
2414 	}
2415 
2416 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2417 	e_dbus_object_skeleton_set_source_remote_deletable (
2418 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2419 	g_object_unref (dbus_object);
2420 
2421 	if (dbus_interface != NULL)
2422 		g_object_unref (dbus_interface);
2423 
2424 	g_object_notify (G_OBJECT (source), "remote-deletable");
2425 }
2426 
2427 /**
2428  * e_server_side_source_ref_oauth2_support:
2429  * @source: an #EServerSideSource
2430  *
2431  * Returns the object implementing the #EOAuth2SupportInterface,
2432  * or %NULL if @source does not support OAuth 2.0 authentication.
2433  *
2434  * The returned #EOAuth2Support object is referenced for thread-safety.
2435  * Unreference the object with g_object_unref() when finished with it.
2436  *
2437  * Returns: (transfer full) (nullable): an #EOAuth2Support object, or %NULL
2438  *
2439  * Since: 3.8
2440  **/
2441 EOAuth2Support *
e_server_side_source_ref_oauth2_support(EServerSideSource * source)2442 e_server_side_source_ref_oauth2_support (EServerSideSource *source)
2443 {
2444 	g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2445 
2446 	return g_weak_ref_get (&source->priv->oauth2_support);
2447 }
2448 
2449 /**
2450  * e_server_side_source_set_oauth2_support:
2451  * @source: an #EServerSideSource
2452  * @oauth2_support: an #EOAuth2Support object, or %NULL
2453  *
2454  * Indicates whether @source supports OAuth 2.0 authentication.
2455  *
2456  * If @oauth2_support is non-%NULL, the OAuth2Support D-Bus interface is
2457  * exported at the object path for @source.  If @oauth2_support is %NULL,
2458  * the OAuth2Support D-Bus interface is unexported at the object path for
2459  * @source, and any attempt by clients to call
2460  * e_source_get_oauth2_access_token() will fail.
2461  *
2462  * Requests for OAuth 2.0 access tokens are forwarded to @oauth2_support,
2463  * which implements the #EOAuth2SupportInterface.
2464  *
2465  * Since: 3.8
2466  **/
2467 void
e_server_side_source_set_oauth2_support(EServerSideSource * source,EOAuth2Support * oauth2_support)2468 e_server_side_source_set_oauth2_support (EServerSideSource *source,
2469                                          EOAuth2Support *oauth2_support)
2470 {
2471 	EDBusSourceOAuth2Support *dbus_interface = NULL;
2472 	GDBusObject *dbus_object;
2473 
2474 	g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2475 
2476 	if (oauth2_support != NULL) {
2477 		g_return_if_fail (E_IS_OAUTH2_SUPPORT (oauth2_support));
2478 
2479 		dbus_interface =
2480 			e_dbus_source_oauth2_support_skeleton_new ();
2481 
2482 		g_signal_connect (
2483 			dbus_interface, "handle-get-access-token",
2484 			G_CALLBACK (server_side_source_get_access_token_cb),
2485 			source);
2486 	}
2487 
2488 	g_weak_ref_set (&source->priv->oauth2_support, oauth2_support);
2489 
2490 	dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2491 	e_dbus_object_skeleton_set_source_oauth2_support (
2492 		E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2493 	g_object_unref (dbus_object);
2494 
2495 	if (dbus_interface != NULL)
2496 		g_object_unref (dbus_interface);
2497 
2498 	g_object_notify (G_OBJECT (source), "oauth2-support");
2499 }
2500