1 /*
2  * e-data-cal.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-data-cal
20  * @include: libedata-cal/libedata-cal.h
21  * @short_description: Server side D-Bus layer to communicate with calendars
22  *
23  * This class communicates with #ECalClients over the bus and accesses
24  * an #ECalBackend to satisfy client requests.
25  **/
26 
27 #include "evolution-data-server-config.h"
28 
29 #include <glib/gi18n-lib.h>
30 #include <unistd.h>
31 
32 /* Private D-Bus classes. */
33 #include <e-dbus-calendar.h>
34 
35 #include <libedataserver/libedataserver.h>
36 
37 #include "e-data-cal.h"
38 #include "e-cal-backend.h"
39 #include "e-cal-backend-sexp.h"
40 
41 typedef struct _AsyncContext AsyncContext;
42 
43 struct _EDataCalPrivate {
44 	GDBusConnection *connection;
45 	EDBusCalendar *dbus_interface;
46 	GWeakRef backend;
47 	gchar *object_path;
48 
49 	GMutex sender_lock;
50 	GHashTable *sender_table;
51 };
52 
53 struct _AsyncContext {
54 	EDataCal *data_cal;
55 	EDBusCalendar *dbus_interface;
56 	GDBusMethodInvocation *invocation;
57 	GCancellable *cancellable;
58 	guint watcher_id;
59 };
60 
61 enum {
62 	PROP_0,
63 	PROP_BACKEND,
64 	PROP_CONNECTION,
65 	PROP_OBJECT_PATH
66 };
67 
68 /* Forward Declarations */
69 static void	e_data_cal_initable_init	(GInitableIface *iface);
70 
G_DEFINE_TYPE_WITH_CODE(EDataCal,e_data_cal,G_TYPE_OBJECT,G_ADD_PRIVATE (EDataCal)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_data_cal_initable_init))71 G_DEFINE_TYPE_WITH_CODE (
72 	EDataCal,
73 	e_data_cal,
74 	G_TYPE_OBJECT,
75 	G_ADD_PRIVATE (EDataCal)
76 	G_IMPLEMENT_INTERFACE (
77 		G_TYPE_INITABLE,
78 		e_data_cal_initable_init))
79 
80 static void
81 sender_vanished_cb (GDBusConnection *connection,
82                     const gchar *sender,
83                     GCancellable *cancellable)
84 {
85 	g_cancellable_cancel (cancellable);
86 }
87 
88 static void
sender_table_insert(EDataCal * data_cal,const gchar * sender,GCancellable * cancellable)89 sender_table_insert (EDataCal *data_cal,
90                      const gchar *sender,
91                      GCancellable *cancellable)
92 {
93 	GHashTable *sender_table;
94 	GPtrArray *array;
95 
96 	g_return_if_fail (sender != NULL);
97 
98 	g_mutex_lock (&data_cal->priv->sender_lock);
99 
100 	sender_table = data_cal->priv->sender_table;
101 	array = g_hash_table_lookup (sender_table, sender);
102 
103 	if (array == NULL) {
104 		array = g_ptr_array_new_with_free_func (
105 			(GDestroyNotify) g_object_unref);
106 		g_hash_table_insert (
107 			sender_table, g_strdup (sender), array);
108 	}
109 
110 	g_ptr_array_add (array, g_object_ref (cancellable));
111 
112 	g_mutex_unlock (&data_cal->priv->sender_lock);
113 }
114 
115 static gboolean
sender_table_remove(EDataCal * data_cal,const gchar * sender,GCancellable * cancellable)116 sender_table_remove (EDataCal *data_cal,
117                      const gchar *sender,
118                      GCancellable *cancellable)
119 {
120 	GHashTable *sender_table;
121 	GPtrArray *array;
122 	gboolean removed = FALSE;
123 
124 	g_return_val_if_fail (sender != NULL, FALSE);
125 
126 	g_mutex_lock (&data_cal->priv->sender_lock);
127 
128 	sender_table = data_cal->priv->sender_table;
129 	array = g_hash_table_lookup (sender_table, sender);
130 
131 	if (array != NULL) {
132 		removed = g_ptr_array_remove_fast (array, cancellable);
133 
134 		if (array->len == 0)
135 			g_hash_table_remove (sender_table, sender);
136 	}
137 
138 	g_mutex_unlock (&data_cal->priv->sender_lock);
139 
140 	return removed;
141 }
142 
143 static AsyncContext *
async_context_new(EDataCal * data_cal,GDBusMethodInvocation * invocation)144 async_context_new (EDataCal *data_cal,
145                    GDBusMethodInvocation *invocation)
146 {
147 	AsyncContext *async_context;
148 	EDBusCalendar *dbus_interface;
149 
150 	dbus_interface = data_cal->priv->dbus_interface;
151 
152 	async_context = g_slice_new0 (AsyncContext);
153 	async_context->data_cal = g_object_ref (data_cal);
154 	async_context->dbus_interface = g_object_ref (dbus_interface);
155 	async_context->invocation = g_object_ref (invocation);
156 	async_context->cancellable = g_cancellable_new ();
157 
158 	async_context->watcher_id = g_bus_watch_name_on_connection (
159 		g_dbus_method_invocation_get_connection (invocation),
160 		g_dbus_method_invocation_get_sender (invocation),
161 		G_BUS_NAME_WATCHER_FLAGS_NONE,
162 		(GBusNameAppearedCallback) NULL,
163 		(GBusNameVanishedCallback) sender_vanished_cb,
164 		g_object_ref (async_context->cancellable),
165 		(GDestroyNotify) g_object_unref);
166 
167 	sender_table_insert (
168 		async_context->data_cal,
169 		g_dbus_method_invocation_get_sender (invocation),
170 		async_context->cancellable);
171 
172 	return async_context;
173 }
174 
175 static void
async_context_free(AsyncContext * async_context)176 async_context_free (AsyncContext *async_context)
177 {
178 	sender_table_remove (
179 		async_context->data_cal,
180 		g_dbus_method_invocation_get_sender (
181 			async_context->invocation),
182 		async_context->cancellable);
183 
184 	g_clear_object (&async_context->data_cal);
185 	g_clear_object (&async_context->dbus_interface);
186 	g_clear_object (&async_context->invocation);
187 	g_clear_object (&async_context->cancellable);
188 
189 	if (async_context->watcher_id > 0)
190 		g_bus_unwatch_name (async_context->watcher_id);
191 
192 	g_slice_free (AsyncContext, async_context);
193 }
194 
195 static gchar *
construct_calview_path(void)196 construct_calview_path (void)
197 {
198 	static volatile gint counter = 1;
199 
200 	g_atomic_int_inc (&counter);
201 
202 	return g_strdup_printf (
203 		"/org/gnome/evolution/dataserver/CalendarView/%d/%d",
204 		getpid (), counter);
205 }
206 
207 static void
data_cal_convert_to_client_error(GError * error)208 data_cal_convert_to_client_error (GError *error)
209 {
210 	g_return_if_fail (error != NULL);
211 
212 	/* Data-Factory returns common error for unknown/broken ESource-s */
213 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
214 		error->domain = E_CAL_CLIENT_ERROR;
215 		error->code = E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR;
216 	}
217 }
218 
219 static GPtrArray *
data_cal_encode_properties(EDBusCalendar * dbus_interface)220 data_cal_encode_properties (EDBusCalendar *dbus_interface)
221 {
222 	GPtrArray *properties_array;
223 
224 	g_warn_if_fail (E_DBUS_IS_CALENDAR (dbus_interface));
225 
226 	properties_array = g_ptr_array_new_with_free_func (g_free);
227 
228 	if (dbus_interface) {
229 		GParamSpec **properties;
230 		guint ii, n_properties = 0;
231 
232 		properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (dbus_interface), &n_properties);
233 
234 		for (ii = 0; ii < n_properties; ii++) {
235 			gboolean can_process =
236 				g_type_is_a (properties[ii]->value_type, G_TYPE_BOOLEAN) ||
237 				g_type_is_a (properties[ii]->value_type, G_TYPE_STRING) ||
238 				g_type_is_a (properties[ii]->value_type, G_TYPE_STRV) ||
239 				g_type_is_a (properties[ii]->value_type, G_TYPE_UCHAR) ||
240 				g_type_is_a (properties[ii]->value_type, G_TYPE_INT) ||
241 				g_type_is_a (properties[ii]->value_type, G_TYPE_UINT) ||
242 				g_type_is_a (properties[ii]->value_type, G_TYPE_INT64) ||
243 				g_type_is_a (properties[ii]->value_type, G_TYPE_UINT64) ||
244 				g_type_is_a (properties[ii]->value_type, G_TYPE_DOUBLE);
245 
246 			if (can_process) {
247 				GValue value = G_VALUE_INIT;
248 				GVariant *stored = NULL;
249 
250 				g_value_init (&value, properties[ii]->value_type);
251 				g_object_get_property ((GObject *) dbus_interface, properties[ii]->name, &value);
252 
253 				#define WORKOUT(gvl, gvr) \
254 					if (g_type_is_a (properties[ii]->value_type, G_TYPE_ ## gvl)) \
255 						stored = g_dbus_gvalue_to_gvariant (&value, G_VARIANT_TYPE_ ## gvr);
256 
257 				WORKOUT (BOOLEAN, BOOLEAN);
258 				WORKOUT (STRING, STRING);
259 				WORKOUT (STRV, STRING_ARRAY);
260 				WORKOUT (UCHAR, BYTE);
261 				WORKOUT (INT, INT32);
262 				WORKOUT (UINT, UINT32);
263 				WORKOUT (INT64, INT64);
264 				WORKOUT (UINT64, UINT64);
265 				WORKOUT (DOUBLE, DOUBLE);
266 
267 				#undef WORKOUT
268 
269 				g_value_unset (&value);
270 
271 				if (stored) {
272 					g_ptr_array_add (properties_array, g_strdup (properties[ii]->name));
273 					g_ptr_array_add (properties_array, g_variant_print (stored, TRUE));
274 
275 					g_variant_unref (stored);
276 				}
277 			}
278 		}
279 
280 		g_free (properties);
281 	}
282 
283 	g_ptr_array_add (properties_array, NULL);
284 
285 	return properties_array;
286 }
287 
288 static gboolean
data_cal_handle_retrieve_properties_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,EDataCal * data_cal)289 data_cal_handle_retrieve_properties_cb (EDBusCalendar *dbus_interface,
290 					GDBusMethodInvocation *invocation,
291 					EDataCal *data_cal)
292 {
293 	GPtrArray *properties_array;
294 
295 	properties_array = data_cal_encode_properties (dbus_interface);
296 
297 	e_dbus_calendar_complete_retrieve_properties (
298 		dbus_interface,
299 		invocation,
300 		(const gchar * const *) properties_array->pdata);
301 
302 	g_ptr_array_free (properties_array, TRUE);
303 
304 	return TRUE;
305 }
306 
307 static void
data_cal_complete_open_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)308 data_cal_complete_open_cb (GObject *source_object,
309                            GAsyncResult *result,
310                            gpointer user_data)
311 {
312 	AsyncContext *async_context = user_data;
313 	GError *error = NULL;
314 
315 	e_cal_backend_open_finish (
316 		E_CAL_BACKEND (source_object), result, &error);
317 
318 	if (error == NULL) {
319 		GPtrArray *properties_array;
320 
321 		properties_array = data_cal_encode_properties (async_context->dbus_interface);
322 
323 		e_dbus_calendar_complete_open (
324 			async_context->dbus_interface,
325 			async_context->invocation,
326 			(const gchar * const *) properties_array->pdata);
327 
328 		g_ptr_array_free (properties_array, TRUE);
329 	} else {
330 		data_cal_convert_to_client_error (error);
331 		g_dbus_method_invocation_take_error (
332 			async_context->invocation, error);
333 	}
334 
335 	async_context_free (async_context);
336 }
337 
338 static gboolean
data_cal_handle_open_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,EDataCal * data_cal)339 data_cal_handle_open_cb (EDBusCalendar *dbus_interface,
340                          GDBusMethodInvocation *invocation,
341                          EDataCal *data_cal)
342 {
343 	ECalBackend *backend;
344 	AsyncContext *async_context;
345 
346 	backend = e_data_cal_ref_backend (data_cal);
347 	g_return_val_if_fail (backend != NULL, FALSE);
348 
349 	async_context = async_context_new (data_cal, invocation);
350 
351 	e_cal_backend_open (
352 		backend,
353 		async_context->cancellable,
354 		data_cal_complete_open_cb,
355 		async_context);
356 
357 	g_object_unref (backend);
358 
359 	return TRUE;
360 }
361 
362 static void
data_cal_complete_refresh_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)363 data_cal_complete_refresh_cb (GObject *source_object,
364                               GAsyncResult *result,
365                               gpointer user_data)
366 {
367 	AsyncContext *async_context = user_data;
368 	GError *error = NULL;
369 
370 	e_cal_backend_refresh_finish (
371 		E_CAL_BACKEND (source_object), result, &error);
372 
373 	if (error == NULL) {
374 		e_dbus_calendar_complete_refresh (
375 			async_context->dbus_interface,
376 			async_context->invocation);
377 	} else {
378 		data_cal_convert_to_client_error (error);
379 		g_dbus_method_invocation_take_error (
380 			async_context->invocation, error);
381 	}
382 
383 	async_context_free (async_context);
384 }
385 
386 static gboolean
data_cal_handle_refresh_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,EDataCal * data_cal)387 data_cal_handle_refresh_cb (EDBusCalendar *dbus_interface,
388                             GDBusMethodInvocation *invocation,
389                             EDataCal *data_cal)
390 {
391 	ECalBackend *backend;
392 	AsyncContext *async_context;
393 
394 	backend = e_data_cal_ref_backend (data_cal);
395 	g_return_val_if_fail (backend != NULL, FALSE);
396 
397 	async_context = async_context_new (data_cal, invocation);
398 
399 	e_cal_backend_refresh (
400 		backend,
401 		async_context->cancellable,
402 		data_cal_complete_refresh_cb,
403 		async_context);
404 
405 	g_object_unref (backend);
406 
407 	return TRUE;
408 }
409 
410 static void
data_cal_complete_get_object_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)411 data_cal_complete_get_object_cb (GObject *source_object,
412                                  GAsyncResult *result,
413                                  gpointer user_data)
414 {
415 	AsyncContext *async_context = user_data;
416 	gchar *calobj;
417 	GError *error = NULL;
418 
419 	calobj = e_cal_backend_get_object_finish (
420 		E_CAL_BACKEND (source_object), result, &error);
421 
422 	/* Sanity check. */
423 	g_return_if_fail (
424 		((calobj != NULL) && (error == NULL)) ||
425 		((calobj == NULL) && (error != NULL)));
426 
427 	if (error == NULL) {
428 		gchar *utf8_calobj;
429 
430 		utf8_calobj = e_util_utf8_make_valid (calobj);
431 
432 		e_dbus_calendar_complete_get_object (
433 			async_context->dbus_interface,
434 			async_context->invocation,
435 			utf8_calobj);
436 
437 		g_free (utf8_calobj);
438 		g_free (calobj);
439 	} else {
440 		data_cal_convert_to_client_error (error);
441 		g_dbus_method_invocation_take_error (
442 			async_context->invocation, error);
443 	}
444 
445 	async_context_free (async_context);
446 }
447 
448 static gboolean
data_cal_handle_get_object_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_uid,const gchar * in_rid,EDataCal * data_cal)449 data_cal_handle_get_object_cb (EDBusCalendar *dbus_interface,
450                                GDBusMethodInvocation *invocation,
451                                const gchar *in_uid,
452                                const gchar *in_rid,
453                                EDataCal *data_cal)
454 {
455 	ECalBackend *backend;
456 	AsyncContext *async_context;
457 
458 	/* Recurrence ID is optional.  Its omission is denoted
459 	 * via D-Bus by an emptry string.  Convert it to NULL. */
460 	if (in_rid != NULL && *in_rid == '\0')
461 		in_rid = NULL;
462 
463 	backend = e_data_cal_ref_backend (data_cal);
464 	g_return_val_if_fail (backend != NULL, FALSE);
465 
466 	async_context = async_context_new (data_cal, invocation);
467 
468 	e_cal_backend_get_object (
469 		backend,
470 		in_uid, in_rid,
471 		async_context->cancellable,
472 		data_cal_complete_get_object_cb,
473 		async_context);
474 
475 	g_object_unref (backend);
476 
477 	return TRUE;
478 }
479 
480 static void
data_cal_complete_get_object_list_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)481 data_cal_complete_get_object_list_cb (GObject *source_object,
482                                       GAsyncResult *result,
483                                       gpointer user_data)
484 {
485 	AsyncContext *async_context = user_data;
486 	GQueue queue = G_QUEUE_INIT;
487 	GError *error = NULL;
488 
489 	e_cal_backend_get_object_list_finish (
490 		E_CAL_BACKEND (source_object), result, &queue, &error);
491 
492 	if (error == NULL) {
493 		gchar **strv;
494 		gint ii = 0;
495 
496 		strv = g_new0 (gchar *, queue.length + 1);
497 
498 		while (!g_queue_is_empty (&queue)) {
499 			gchar *calobj;
500 
501 			calobj = g_queue_pop_head (&queue);
502 
503 			strv[ii++] = e_util_utf8_make_valid (calobj);
504 
505 			g_free (calobj);
506 		}
507 
508 		e_dbus_calendar_complete_get_object_list (
509 			async_context->dbus_interface,
510 			async_context->invocation,
511 			(const gchar * const *) strv);
512 
513 		g_strfreev (strv);
514 	} else {
515 		data_cal_convert_to_client_error (error);
516 		g_dbus_method_invocation_take_error (
517 			async_context->invocation, error);
518 	}
519 
520 	async_context_free (async_context);
521 }
522 
523 static gboolean
data_cal_handle_get_object_list_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_query,EDataCal * data_cal)524 data_cal_handle_get_object_list_cb (EDBusCalendar *dbus_interface,
525                                     GDBusMethodInvocation *invocation,
526                                     const gchar *in_query,
527                                     EDataCal *data_cal)
528 {
529 	ECalBackend *backend;
530 	AsyncContext *async_context;
531 
532 	backend = e_data_cal_ref_backend (data_cal);
533 	g_return_val_if_fail (backend != NULL, FALSE);
534 
535 	async_context = async_context_new (data_cal, invocation);
536 
537 	e_cal_backend_get_object_list (
538 		backend,
539 		in_query,
540 		async_context->cancellable,
541 		data_cal_complete_get_object_list_cb,
542 		async_context);
543 
544 	g_object_unref (backend);
545 
546 	return TRUE;
547 }
548 
549 static void
data_cal_complete_get_free_busy_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)550 data_cal_complete_get_free_busy_cb (GObject *source_object,
551                                     GAsyncResult *result,
552                                     gpointer user_data)
553 {
554 	AsyncContext *async_context = user_data;
555 	GSList *out_freebusy = NULL;
556 	GError *error = NULL;
557 
558 	e_cal_backend_get_free_busy_finish (
559 		E_CAL_BACKEND (source_object), result, &out_freebusy, &error);
560 
561 	if (error == NULL) {
562 		gchar **strv;
563 		gint ii = 0;
564 		GSList *link;
565 
566 		strv = g_new0 (gchar *, g_slist_length (out_freebusy) + 1);
567 
568 		for (link = out_freebusy; link; link = g_slist_next (link)) {
569 			gchar *ical_freebusy = link->data;
570 
571 			strv[ii++] = e_util_utf8_make_valid (ical_freebusy);
572 		}
573 
574 		e_dbus_calendar_complete_get_free_busy (
575 			async_context->dbus_interface,
576 			async_context->invocation,
577 			(const gchar * const *) strv);
578 
579 		g_strfreev (strv);
580 	} else {
581 		data_cal_convert_to_client_error (error);
582 		g_dbus_method_invocation_take_error (
583 			async_context->invocation, error);
584 	}
585 
586 	g_slist_free_full (out_freebusy, g_free);
587 	async_context_free (async_context);
588 }
589 
590 static gboolean
data_cal_handle_get_free_busy_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,gint64 in_start,gint64 in_end,const gchar * const * in_users,EDataCal * data_cal)591 data_cal_handle_get_free_busy_cb (EDBusCalendar *dbus_interface,
592                                   GDBusMethodInvocation *invocation,
593                                   gint64 in_start,
594                                   gint64 in_end,
595                                   const gchar * const *in_users,
596                                   EDataCal *data_cal)
597 {
598 	ECalBackend *backend;
599 	AsyncContext *async_context;
600 
601 	backend = e_data_cal_ref_backend (data_cal);
602 	g_return_val_if_fail (backend != NULL, FALSE);
603 
604 	async_context = async_context_new (data_cal, invocation);
605 
606 	e_cal_backend_get_free_busy (
607 		backend,
608 		(time_t) in_start,
609 		(time_t) in_end,
610 		in_users,
611 		async_context->cancellable,
612 		data_cal_complete_get_free_busy_cb,
613 		async_context);
614 
615 	g_object_unref (backend);
616 
617 	return TRUE;
618 }
619 
620 static void
data_cal_complete_create_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)621 data_cal_complete_create_objects_cb (GObject *source_object,
622                                      GAsyncResult *result,
623                                      gpointer user_data)
624 {
625 	AsyncContext *async_context = user_data;
626 	GQueue queue = G_QUEUE_INIT;
627 	GError *error = NULL;
628 
629 	e_cal_backend_create_objects_finish (
630 		E_CAL_BACKEND (source_object), result, &queue, &error);
631 
632 	if (error == NULL) {
633 		gchar **strv;
634 		gint ii = 0;
635 
636 		strv = g_new0 (gchar *, queue.length + 1);
637 
638 		while (!g_queue_is_empty (&queue)) {
639 			gchar *uid;
640 
641 			uid = g_queue_pop_head (&queue);
642 			strv[ii++] = e_util_utf8_make_valid (uid);
643 			g_free (uid);
644 		}
645 
646 		e_dbus_calendar_complete_create_objects (
647 			async_context->dbus_interface,
648 			async_context->invocation,
649 			(const gchar * const *) strv);
650 
651 		g_strfreev (strv);
652 	} else {
653 		data_cal_convert_to_client_error (error);
654 		g_dbus_method_invocation_take_error (
655 			async_context->invocation, error);
656 	}
657 
658 	async_context_free (async_context);
659 }
660 
661 static gboolean
data_cal_handle_create_objects_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * const * in_calobjs,guint32 in_opflags,EDataCal * data_cal)662 data_cal_handle_create_objects_cb (EDBusCalendar *dbus_interface,
663                                    GDBusMethodInvocation *invocation,
664                                    const gchar * const *in_calobjs,
665 				   guint32 in_opflags,
666                                    EDataCal *data_cal)
667 {
668 	ECalBackend *backend;
669 	AsyncContext *async_context;
670 
671 	backend = e_data_cal_ref_backend (data_cal);
672 	g_return_val_if_fail (backend != NULL, FALSE);
673 
674 	async_context = async_context_new (data_cal, invocation);
675 
676 	e_cal_backend_create_objects (
677 		backend,
678 		in_calobjs,
679 		in_opflags,
680 		async_context->cancellable,
681 		data_cal_complete_create_objects_cb,
682 		async_context);
683 
684 	g_object_unref (backend);
685 
686 	return TRUE;
687 }
688 
689 static void
data_cal_complete_modify_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)690 data_cal_complete_modify_objects_cb (GObject *source_object,
691                                      GAsyncResult *result,
692                                      gpointer user_data)
693 {
694 	AsyncContext *async_context = user_data;
695 	GError *error = NULL;
696 
697 	e_cal_backend_modify_objects_finish (
698 		E_CAL_BACKEND (source_object), result, &error);
699 
700 	if (error == NULL) {
701 		e_dbus_calendar_complete_modify_objects (
702 			async_context->dbus_interface,
703 			async_context->invocation);
704 	} else {
705 		data_cal_convert_to_client_error (error);
706 		g_dbus_method_invocation_take_error (
707 			async_context->invocation, error);
708 	}
709 
710 	async_context_free (async_context);
711 }
712 
713 static gboolean
data_cal_handle_modify_objects_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * const * in_ics_objects,const gchar * in_mod_type,guint32 in_opflags,EDataCal * data_cal)714 data_cal_handle_modify_objects_cb (EDBusCalendar *dbus_interface,
715                                    GDBusMethodInvocation *invocation,
716                                    const gchar * const *in_ics_objects,
717                                    const gchar *in_mod_type,
718 				   guint32 in_opflags,
719                                    EDataCal *data_cal)
720 {
721 	ECalBackend *backend;
722 	AsyncContext *async_context;
723 	GFlagsClass *flags_class;
724 	ECalObjModType mod = 0;
725 	gchar **flags_strv;
726 	gint ii;
727 
728 	backend = e_data_cal_ref_backend (data_cal);
729 	g_return_val_if_fail (backend != NULL, FALSE);
730 
731 	flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
732 	flags_strv = g_strsplit (in_mod_type, ":", -1);
733 	for (ii = 0; flags_strv[ii] != NULL; ii++) {
734 		GFlagsValue *flags_value;
735 
736 		flags_value = g_flags_get_value_by_nick (
737 			flags_class, flags_strv[ii]);
738 		if (flags_value != NULL) {
739 			mod |= flags_value->value;
740 		} else {
741 			g_warning (
742 				"%s: Unknown flag: %s",
743 				G_STRFUNC, flags_strv[ii]);
744 		}
745 	}
746 	g_strfreev (flags_strv);
747 	g_type_class_unref (flags_class);
748 
749 	async_context = async_context_new (data_cal, invocation);
750 
751 	e_cal_backend_modify_objects (
752 		backend,
753 		in_ics_objects, mod, in_opflags,
754 		async_context->cancellable,
755 		data_cal_complete_modify_objects_cb,
756 		async_context);
757 
758 	g_object_unref (backend);
759 
760 	return TRUE;
761 }
762 
763 static void
data_cal_complete_remove_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)764 data_cal_complete_remove_objects_cb (GObject *source_object,
765                                      GAsyncResult *result,
766                                      gpointer user_data)
767 {
768 	AsyncContext *async_context = user_data;
769 	GError *error = NULL;
770 
771 	e_cal_backend_remove_objects_finish (
772 		E_CAL_BACKEND (source_object), result, &error);
773 
774 	if (error == NULL) {
775 		e_dbus_calendar_complete_remove_objects (
776 			async_context->dbus_interface,
777 			async_context->invocation);
778 	} else {
779 		data_cal_convert_to_client_error (error);
780 		g_dbus_method_invocation_take_error (
781 			async_context->invocation, error);
782 	}
783 
784 	async_context_free (async_context);
785 }
786 
787 static gboolean
data_cal_handle_remove_objects_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,GVariant * in_uid_rid_array,const gchar * in_mod_type,guint32 in_opflags,EDataCal * data_cal)788 data_cal_handle_remove_objects_cb (EDBusCalendar *dbus_interface,
789                                    GDBusMethodInvocation *invocation,
790                                    GVariant *in_uid_rid_array,
791                                    const gchar *in_mod_type,
792 				   guint32 in_opflags,
793                                    EDataCal *data_cal)
794 {
795 	ECalBackend *backend;
796 	AsyncContext *async_context;
797 	GFlagsClass *flags_class;
798 	ECalObjModType mod = 0;
799 	GQueue component_ids = G_QUEUE_INIT;
800 	gchar **flags_strv;
801 	gsize n_children, ii;
802 
803 	backend = e_data_cal_ref_backend (data_cal);
804 	g_return_val_if_fail (backend != NULL, FALSE);
805 
806 	flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
807 	flags_strv = g_strsplit (in_mod_type, ":", -1);
808 	for (ii = 0; flags_strv[ii] != NULL; ii++) {
809 		GFlagsValue *flags_value;
810 
811 		flags_value = g_flags_get_value_by_nick (
812 			flags_class, flags_strv[ii]);
813 		if (flags_value != NULL) {
814 			mod |= flags_value->value;
815 		} else {
816 			g_warning (
817 				"%s: Unknown flag: %s",
818 				G_STRFUNC, flags_strv[ii]);
819 		}
820 	}
821 	g_strfreev (flags_strv);
822 	g_type_class_unref (flags_class);
823 
824 	n_children = g_variant_n_children (in_uid_rid_array);
825 	for (ii = 0; ii < n_children; ii++) {
826 		gchar *uid = NULL, *rid = NULL;
827 
828 		g_variant_get_child (in_uid_rid_array, ii, "(ss)", &uid, &rid);
829 
830 		if (!uid || !*uid) {
831 			g_free (uid);
832 			g_free (rid);
833 			continue;
834 		}
835 
836 		g_queue_push_tail (&component_ids, e_cal_component_id_new_take (uid, rid));
837 	}
838 
839 	async_context = async_context_new (data_cal, invocation);
840 
841 	e_cal_backend_remove_objects (
842 		backend,
843 		component_ids.head, mod, in_opflags,
844 		async_context->cancellable,
845 		data_cal_complete_remove_objects_cb,
846 		async_context);
847 
848 	while (!g_queue_is_empty (&component_ids))
849 		e_cal_component_id_free (g_queue_pop_head (&component_ids));
850 
851 	g_object_unref (backend);
852 
853 	return TRUE;
854 }
855 
856 static void
data_cal_complete_receive_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)857 data_cal_complete_receive_objects_cb (GObject *source_object,
858                                       GAsyncResult *result,
859                                       gpointer user_data)
860 {
861 	AsyncContext *async_context = user_data;
862 	GError *error = NULL;
863 
864 	e_cal_backend_receive_objects_finish (
865 		E_CAL_BACKEND (source_object), result, &error);
866 
867 	if (error == NULL) {
868 		e_dbus_calendar_complete_receive_objects (
869 			async_context->dbus_interface,
870 			async_context->invocation);
871 	} else {
872 		data_cal_convert_to_client_error (error);
873 		g_dbus_method_invocation_take_error (
874 			async_context->invocation, error);
875 	}
876 
877 	async_context_free (async_context);
878 }
879 
880 static gboolean
data_cal_handle_receive_objects_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_calobj,guint32 in_opflags,EDataCal * data_cal)881 data_cal_handle_receive_objects_cb (EDBusCalendar *dbus_interface,
882                                     GDBusMethodInvocation *invocation,
883                                     const gchar *in_calobj,
884 				    guint32 in_opflags,
885                                     EDataCal *data_cal)
886 {
887 	ECalBackend *backend;
888 	AsyncContext *async_context;
889 
890 	backend = e_data_cal_ref_backend (data_cal);
891 	g_return_val_if_fail (backend != NULL, FALSE);
892 
893 	async_context = async_context_new (data_cal, invocation);
894 
895 	e_cal_backend_receive_objects (
896 		backend,
897 		in_calobj,
898 		in_opflags,
899 		async_context->cancellable,
900 		data_cal_complete_receive_objects_cb,
901 		async_context);
902 
903 	g_object_unref (backend);
904 
905 	return TRUE;
906 }
907 
908 static void
data_cal_complete_send_objects_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)909 data_cal_complete_send_objects_cb (GObject *source_object,
910                                    GAsyncResult *result,
911                                    gpointer user_data)
912 {
913 	AsyncContext *async_context = user_data;
914 	gchar *calobj;
915 	GQueue queue = G_QUEUE_INIT;
916 	GError *error = NULL;
917 
918 	calobj = e_cal_backend_send_objects_finish (
919 		E_CAL_BACKEND (source_object), result, &queue, &error);
920 
921 	/* Sanity check. */
922 	g_return_if_fail (
923 		((calobj != NULL) && (error == NULL)) ||
924 		((calobj == NULL) && (error != NULL)));
925 
926 	if (calobj != NULL) {
927 		gchar **strv;
928 		gchar *utf8_calobj;
929 		gint ii = 0;
930 
931 		strv = g_new0 (gchar *, queue.length + 1);
932 
933 		while (!g_queue_is_empty (&queue)) {
934 			gchar *user;
935 
936 			user = g_queue_pop_head (&queue);
937 			strv[ii++] = e_util_utf8_make_valid (user);
938 			g_free (user);
939 		}
940 
941 		utf8_calobj = e_util_utf8_make_valid (calobj);
942 
943 		e_dbus_calendar_complete_send_objects (
944 			async_context->dbus_interface,
945 			async_context->invocation,
946 			(const gchar * const *) strv,
947 			utf8_calobj);
948 
949 		g_free (utf8_calobj);
950 		g_free (calobj);
951 
952 		g_strfreev (strv);
953 	} else {
954 		data_cal_convert_to_client_error (error);
955 		g_dbus_method_invocation_take_error (
956 			async_context->invocation, error);
957 	}
958 
959 	async_context_free (async_context);
960 }
961 
962 static gboolean
data_cal_handle_send_objects_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_calobj,guint32 in_opflags,EDataCal * data_cal)963 data_cal_handle_send_objects_cb (EDBusCalendar *dbus_interface,
964                                  GDBusMethodInvocation *invocation,
965                                  const gchar *in_calobj,
966 				 guint32 in_opflags,
967                                  EDataCal *data_cal)
968 {
969 	ECalBackend *backend;
970 	AsyncContext *async_context;
971 
972 	backend = e_data_cal_ref_backend (data_cal);
973 	g_return_val_if_fail (backend != NULL, FALSE);
974 
975 	async_context = async_context_new (data_cal, invocation);
976 
977 	e_cal_backend_send_objects (
978 		backend,
979 		in_calobj,
980 		in_opflags,
981 		async_context->cancellable,
982 		data_cal_complete_send_objects_cb,
983 		async_context);
984 
985 	g_object_unref (backend);
986 
987 	return TRUE;
988 }
989 
990 static void
data_cal_complete_get_attachment_uris_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)991 data_cal_complete_get_attachment_uris_cb (GObject *source_object,
992                                           GAsyncResult *result,
993                                           gpointer user_data)
994 {
995 	AsyncContext *async_context = user_data;
996 	GQueue queue = G_QUEUE_INIT;
997 	GError *error = NULL;
998 
999 	e_cal_backend_get_attachment_uris_finish (
1000 		E_CAL_BACKEND (source_object), result, &queue, &error);
1001 
1002 	if (error == NULL) {
1003 		gchar **strv;
1004 		gint ii = 0;
1005 
1006 		strv = g_new0 (gchar *, queue.length + 1);
1007 
1008 		while (!g_queue_is_empty (&queue)) {
1009 			gchar *uri;
1010 
1011 			uri = g_queue_pop_head (&queue);
1012 			strv[ii++] = e_util_utf8_make_valid (uri);
1013 			g_free (uri);
1014 		}
1015 
1016 		e_dbus_calendar_complete_get_attachment_uris (
1017 			async_context->dbus_interface,
1018 			async_context->invocation,
1019 			(const gchar * const *) strv);
1020 
1021 		g_strfreev (strv);
1022 	} else {
1023 		data_cal_convert_to_client_error (error);
1024 		g_dbus_method_invocation_take_error (
1025 			async_context->invocation, error);
1026 	}
1027 
1028 	async_context_free (async_context);
1029 }
1030 
1031 static gboolean
data_cal_handle_get_attachment_uris_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_uid,const gchar * in_rid,EDataCal * data_cal)1032 data_cal_handle_get_attachment_uris_cb (EDBusCalendar *dbus_interface,
1033                                         GDBusMethodInvocation *invocation,
1034                                         const gchar *in_uid,
1035                                         const gchar *in_rid,
1036                                         EDataCal *data_cal)
1037 {
1038 	ECalBackend *backend;
1039 	AsyncContext *async_context;
1040 
1041 	/* Recurrence ID is optional.  Its omission is denoted
1042 	 * via D-Bus by an empty string.  Convert it to NULL. */
1043 	if (in_rid != NULL && *in_rid == '\0')
1044 		in_rid = NULL;
1045 
1046 	backend = e_data_cal_ref_backend (data_cal);
1047 	g_return_val_if_fail (backend != NULL, FALSE);
1048 
1049 	async_context = async_context_new (data_cal, invocation);
1050 
1051 	e_cal_backend_get_attachment_uris (
1052 		backend,
1053 		in_uid, in_rid,
1054 		async_context->cancellable,
1055 		data_cal_complete_get_attachment_uris_cb,
1056 		async_context);
1057 
1058 	g_object_unref (backend);
1059 
1060 	return TRUE;
1061 }
1062 
1063 static void
data_cal_complete_discard_alarm_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1064 data_cal_complete_discard_alarm_cb (GObject *source_object,
1065                                     GAsyncResult *result,
1066                                     gpointer user_data)
1067 {
1068 	AsyncContext *async_context = user_data;
1069 	GError *error = NULL;
1070 
1071 	e_cal_backend_discard_alarm_finish (
1072 		E_CAL_BACKEND (source_object), result, &error);
1073 
1074 	if (error == NULL) {
1075 		e_dbus_calendar_complete_discard_alarm (
1076 			async_context->dbus_interface,
1077 			async_context->invocation);
1078 	} else {
1079 		data_cal_convert_to_client_error (error);
1080 		g_dbus_method_invocation_take_error (
1081 			async_context->invocation, error);
1082 	}
1083 
1084 	async_context_free (async_context);
1085 }
1086 
1087 static gboolean
data_cal_handle_discard_alarm_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_uid,const gchar * in_rid,const gchar * in_alarm_uid,guint32 in_opflags,EDataCal * data_cal)1088 data_cal_handle_discard_alarm_cb (EDBusCalendar *dbus_interface,
1089                                   GDBusMethodInvocation *invocation,
1090                                   const gchar *in_uid,
1091                                   const gchar *in_rid,
1092                                   const gchar *in_alarm_uid,
1093 				  guint32 in_opflags,
1094                                   EDataCal *data_cal)
1095 {
1096 	ECalBackend *backend;
1097 	AsyncContext *async_context;
1098 
1099 	/* Recurrence ID is optional.  Its omission is denoted
1100 	 * via D-Bus by an empty string.  Convert it to NULL. */
1101 	if (in_rid != NULL && *in_rid == '\0')
1102 		in_rid = NULL;
1103 
1104 	backend = e_data_cal_ref_backend (data_cal);
1105 	g_return_val_if_fail (backend != NULL, FALSE);
1106 
1107 	async_context = async_context_new (data_cal, invocation);
1108 
1109 	e_cal_backend_discard_alarm (
1110 		backend,
1111 		in_uid, in_rid, in_alarm_uid, in_opflags,
1112 		async_context->cancellable,
1113 		data_cal_complete_discard_alarm_cb,
1114 		async_context);
1115 
1116 	g_object_unref (backend);
1117 
1118 	return TRUE;
1119 }
1120 
1121 static gboolean
data_cal_handle_get_view_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_query,EDataCal * data_cal)1122 data_cal_handle_get_view_cb (EDBusCalendar *dbus_interface,
1123                              GDBusMethodInvocation *invocation,
1124                              const gchar *in_query,
1125                              EDataCal *data_cal)
1126 {
1127 	ECalBackend *backend;
1128 	EDataCalView *view;
1129 	ECalBackendSExp *sexp;
1130 	GDBusConnection *connection;
1131 	gchar *object_path;
1132 	GError *error = NULL;
1133 
1134 	backend = e_data_cal_ref_backend (data_cal);
1135 	g_return_val_if_fail (backend != NULL, FALSE);
1136 
1137 	sexp = e_cal_backend_sexp_new (in_query);
1138 	if (sexp == NULL) {
1139 		g_dbus_method_invocation_return_error_literal (
1140 			invocation,
1141 			E_CLIENT_ERROR,
1142 			E_CLIENT_ERROR_INVALID_QUERY,
1143 			_("Invalid query"));
1144 		g_object_unref (backend);
1145 		return TRUE;
1146 	}
1147 
1148 	object_path = construct_calview_path ();
1149 	connection = g_dbus_method_invocation_get_connection (invocation);
1150 
1151 	view = e_data_cal_view_new (
1152 		backend, sexp, connection, object_path, &error);
1153 
1154 	g_object_unref (sexp);
1155 
1156 	/* Sanity check. */
1157 	g_return_val_if_fail (
1158 		((view != NULL) && (error == NULL)) ||
1159 		((view == NULL) && (error != NULL)), FALSE);
1160 
1161 	if (view != NULL) {
1162 		e_dbus_calendar_complete_get_view (
1163 			dbus_interface, invocation, object_path);
1164 		e_cal_backend_add_view (backend, view);
1165 		g_object_unref (view);
1166 	} else {
1167 		data_cal_convert_to_client_error (error);
1168 		g_prefix_error (&error, "%s", _("Invalid query: "));
1169 		g_dbus_method_invocation_take_error (invocation, error);
1170 	}
1171 
1172 	g_free (object_path);
1173 
1174 	g_object_unref (backend);
1175 
1176 	return TRUE;
1177 }
1178 
1179 static void
data_cal_complete_get_timezone_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1180 data_cal_complete_get_timezone_cb (GObject *source_object,
1181                                    GAsyncResult *result,
1182                                    gpointer user_data)
1183 {
1184 	AsyncContext *async_context = user_data;
1185 	gchar *tzobject;
1186 	GError *error = NULL;
1187 
1188 	/* XXX Should this return an ECalComponent instead? */
1189 	tzobject = e_cal_backend_get_timezone_finish (
1190 		E_CAL_BACKEND (source_object), result, &error);
1191 
1192 	/* Sanity check. */
1193 	g_return_if_fail (
1194 		((tzobject != NULL) && (error == NULL)) ||
1195 		((tzobject == NULL) && (error != NULL)));
1196 
1197 	if (tzobject != NULL) {
1198 		e_dbus_calendar_complete_get_timezone (
1199 			async_context->dbus_interface,
1200 			async_context->invocation,
1201 			tzobject);
1202 
1203 		g_free (tzobject);
1204 	} else {
1205 		data_cal_convert_to_client_error (error);
1206 		g_dbus_method_invocation_take_error (
1207 			async_context->invocation, error);
1208 	}
1209 
1210 	async_context_free (async_context);
1211 }
1212 
1213 static gboolean
data_cal_handle_get_timezone_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_tzid,EDataCal * data_cal)1214 data_cal_handle_get_timezone_cb (EDBusCalendar *dbus_interface,
1215                                  GDBusMethodInvocation *invocation,
1216                                  const gchar *in_tzid,
1217                                  EDataCal *data_cal)
1218 {
1219 	ECalBackend *backend;
1220 	AsyncContext *async_context;
1221 
1222 	backend = e_data_cal_ref_backend (data_cal);
1223 	g_return_val_if_fail (backend != NULL, FALSE);
1224 
1225 	async_context = async_context_new (data_cal, invocation);
1226 
1227 	e_cal_backend_get_timezone (
1228 		backend,
1229 		in_tzid,
1230 		async_context->cancellable,
1231 		data_cal_complete_get_timezone_cb,
1232 		async_context);
1233 
1234 	g_object_unref (backend);
1235 
1236 	return TRUE;
1237 }
1238 
1239 static void
data_cal_complete_add_timezone_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1240 data_cal_complete_add_timezone_cb (GObject *source_object,
1241                                    GAsyncResult *result,
1242                                    gpointer user_data)
1243 {
1244 	AsyncContext *async_context = user_data;
1245 	GError *error = NULL;
1246 
1247 	e_cal_backend_add_timezone_finish (
1248 		E_CAL_BACKEND (source_object), result, &error);
1249 
1250 	if (error == NULL) {
1251 		e_dbus_calendar_complete_add_timezone (
1252 			async_context->dbus_interface,
1253 			async_context->invocation);
1254 	} else {
1255 		data_cal_convert_to_client_error (error);
1256 		g_dbus_method_invocation_take_error (
1257 			async_context->invocation, error);
1258 	}
1259 
1260 	async_context_free (async_context);
1261 }
1262 
1263 static gboolean
data_cal_handle_add_timezone_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,const gchar * in_tzobject,EDataCal * data_cal)1264 data_cal_handle_add_timezone_cb (EDBusCalendar *dbus_interface,
1265                                  GDBusMethodInvocation *invocation,
1266                                  const gchar *in_tzobject,
1267                                  EDataCal *data_cal)
1268 {
1269 	ECalBackend *backend;
1270 	AsyncContext *async_context;
1271 
1272 	backend = e_data_cal_ref_backend (data_cal);
1273 	g_return_val_if_fail (backend != NULL, FALSE);
1274 
1275 	async_context = async_context_new (data_cal, invocation);
1276 
1277 	e_cal_backend_add_timezone (
1278 		backend,
1279 		in_tzobject,
1280 		async_context->cancellable,
1281 		data_cal_complete_add_timezone_cb,
1282 		async_context);
1283 
1284 	g_object_unref (backend);
1285 
1286 	return TRUE;
1287 }
1288 
1289 static void
data_cal_source_unset_last_credentials_required_arguments_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1290 data_cal_source_unset_last_credentials_required_arguments_cb (GObject *source_object,
1291 							      GAsyncResult *result,
1292 							      gpointer user_data)
1293 {
1294 	GError *local_error = NULL;
1295 
1296 	g_return_if_fail (E_IS_SOURCE (source_object));
1297 
1298 	e_source_unset_last_credentials_required_arguments_finish (E_SOURCE (source_object), result, &local_error);
1299 
1300 	if (local_error)
1301 		g_debug ("%s: Call failed: %s", G_STRFUNC, local_error->message);
1302 
1303 	g_clear_error (&local_error);
1304 }
1305 
1306 static gboolean
data_cal_handle_close_cb(EDBusCalendar * dbus_interface,GDBusMethodInvocation * invocation,EDataCal * data_cal)1307 data_cal_handle_close_cb (EDBusCalendar *dbus_interface,
1308                           GDBusMethodInvocation *invocation,
1309                           EDataCal *data_cal)
1310 {
1311 	ECalBackend *backend;
1312 	ESource *source;
1313 	const gchar *sender;
1314 
1315 	/* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED should be set on
1316 	 * the GDBusMessage, but we complete the invocation anyway
1317 	 * and let the D-Bus machinery suppress the reply. */
1318 	e_dbus_calendar_complete_close (dbus_interface, invocation);
1319 
1320 	backend = e_data_cal_ref_backend (data_cal);
1321 	g_return_val_if_fail (backend != NULL, FALSE);
1322 
1323 	source = e_backend_get_source (E_BACKEND (backend));
1324 	e_source_unset_last_credentials_required_arguments (source, NULL,
1325 		data_cal_source_unset_last_credentials_required_arguments_cb, NULL);
1326 
1327 	sender = g_dbus_method_invocation_get_sender (invocation);
1328 	g_signal_emit_by_name (backend, "closed", sender);
1329 
1330 	g_object_unref (backend);
1331 
1332 	return TRUE;
1333 }
1334 
1335 /**
1336  * e_data_cal_respond_open:
1337  * @cal: A calendar client interface.
1338  * @opid: associated operation id
1339  * @error: Operation error, if any, automatically freed if passed it.
1340  *
1341  * Notifies listeners of the completion of the open method call.
1342  *
1343  * Since: 3.2
1344  */
1345 void
e_data_cal_respond_open(EDataCal * cal,guint32 opid,GError * error)1346 e_data_cal_respond_open (EDataCal *cal,
1347                          guint32 opid,
1348                          GError *error)
1349 {
1350 	ECalBackend *backend;
1351 	GSimpleAsyncResult *simple;
1352 
1353 	g_return_if_fail (E_IS_DATA_CAL (cal));
1354 
1355 	backend = e_data_cal_ref_backend (cal);
1356 	g_return_if_fail (backend != NULL);
1357 
1358 	simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
1359 	g_return_if_fail (simple != NULL);
1360 
1361 	/* Translators: This is prefix to a detailed error message */
1362 	g_prefix_error (&error, "%s", _("Cannot open calendar: "));
1363 
1364 	if (error != NULL)
1365 		g_simple_async_result_take_error (simple, error);
1366 
1367 	g_simple_async_result_complete_in_idle (simple);
1368 
1369 	g_object_unref (simple);
1370 	g_object_unref (backend);
1371 }
1372 
1373 /**
1374  * e_data_cal_respond_refresh:
1375  * @cal: A calendar client interface.
1376  * @opid: associated operation id
1377  * @error: Operation error, if any, automatically freed if passed it.
1378  *
1379  * Notifies listeners of the completion of the refresh method call.
1380  *
1381  * Since: 3.2
1382  */
1383 void
e_data_cal_respond_refresh(EDataCal * cal,guint32 opid,GError * error)1384 e_data_cal_respond_refresh (EDataCal *cal,
1385                             guint32 opid,
1386                             GError *error)
1387 {
1388 	ECalBackend *backend;
1389 	GSimpleAsyncResult *simple;
1390 
1391 	g_return_if_fail (E_IS_DATA_CAL (cal));
1392 
1393 	backend = e_data_cal_ref_backend (cal);
1394 	g_return_if_fail (backend != NULL);
1395 
1396 	simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
1397 	g_return_if_fail (simple != NULL);
1398 
1399 	/* Translators: This is prefix to a detailed error message */
1400 	g_prefix_error (&error, "%s", _("Cannot refresh calendar: "));
1401 
1402 	if (error != NULL)
1403 		g_simple_async_result_take_error (simple, error);
1404 
1405 	g_simple_async_result_complete_in_idle (simple);
1406 
1407 	g_object_unref (simple);
1408 	g_object_unref (backend);
1409 }
1410 
1411 /**
1412  * e_data_cal_respond_get_object:
1413  * @cal: A calendar client interface.
1414  * @opid: associated operation id
1415  * @error: Operation error, if any, automatically freed if passed it.
1416  * @object: The object retrieved as an iCalendar string.
1417  *
1418  * Notifies listeners of the completion of the get_object method call.
1419  *
1420  * Since: 3.2
1421  */
1422 void
e_data_cal_respond_get_object(EDataCal * cal,guint32 opid,GError * error,const gchar * object)1423 e_data_cal_respond_get_object (EDataCal *cal,
1424                                guint32 opid,
1425                                GError *error,
1426                                const gchar *object)
1427 {
1428 	ECalBackend *backend;
1429 	GSimpleAsyncResult *simple;
1430 	GQueue *queue = NULL;
1431 
1432 	g_return_if_fail (E_IS_DATA_CAL (cal));
1433 
1434 	backend = e_data_cal_ref_backend (cal);
1435 	g_return_if_fail (backend != NULL);
1436 
1437 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1438 	g_return_if_fail (simple != NULL);
1439 	g_return_if_fail (queue != NULL);
1440 
1441 	/* Translators: This is prefix to a detailed error message */
1442 	g_prefix_error (&error, "%s", _("Cannot retrieve calendar object path: "));
1443 
1444 	if (error == NULL) {
1445 		if (object != NULL) {
1446 			g_queue_push_tail (queue, g_strdup (object));
1447 		} else {
1448 			g_simple_async_result_set_error (
1449 				simple, E_CAL_CLIENT_ERROR,
1450 				E_CAL_CLIENT_ERROR_INVALID_OBJECT,
1451 				"%s", e_cal_client_error_to_string (
1452 				E_CAL_CLIENT_ERROR_INVALID_OBJECT));
1453 		}
1454 	} else {
1455 		g_simple_async_result_take_error (simple, error);
1456 	}
1457 
1458 	g_simple_async_result_complete_in_idle (simple);
1459 
1460 	g_object_unref (simple);
1461 	g_object_unref (backend);
1462 }
1463 
1464 /**
1465  * e_data_cal_respond_get_object_list:
1466  * @cal: A calendar client interface.
1467  * @opid: associated operation id
1468  * @error: Operation error, if any, automatically freed if passed it.
1469  * @objects: (element-type utf8): List of retrieved objects.
1470  *
1471  * Notifies listeners of the completion of the get_object_list method call.
1472  *
1473  * Since: 3.2
1474  */
1475 void
e_data_cal_respond_get_object_list(EDataCal * cal,guint32 opid,GError * error,const GSList * objects)1476 e_data_cal_respond_get_object_list (EDataCal *cal,
1477                                     guint32 opid,
1478                                     GError *error,
1479                                     const GSList *objects)
1480 {
1481 	ECalBackend *backend;
1482 	GSimpleAsyncResult *simple;
1483 	GQueue *queue = NULL;
1484 
1485 	g_return_if_fail (E_IS_DATA_CAL (cal));
1486 
1487 	backend = e_data_cal_ref_backend (cal);
1488 	g_return_if_fail (backend != NULL);
1489 
1490 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1491 	g_return_if_fail (simple != NULL);
1492 	g_return_if_fail (queue != NULL);
1493 
1494 	/* Translators: This is prefix to a detailed error message */
1495 	g_prefix_error (&error, "%s", _("Cannot retrieve calendar object list: "));
1496 
1497 	if (error == NULL) {
1498 		GSList *list, *link;
1499 
1500 		list = (GSList *) objects;
1501 
1502 		for (link = list; link != NULL; link = g_slist_next (link)) {
1503 			const gchar *calobj = link->data;
1504 
1505 			if (calobj != NULL)
1506 				g_queue_push_tail (queue, g_strdup (calobj));
1507 		}
1508 
1509 	} else {
1510 		g_simple_async_result_take_error (simple, error);
1511 	}
1512 
1513 	g_simple_async_result_complete_in_idle (simple);
1514 
1515 	g_object_unref (simple);
1516 	g_object_unref (backend);
1517 }
1518 
1519 /**
1520  * e_data_cal_respond_get_free_busy:
1521  * @cal: A calendar client interface.
1522  * @opid: associated operation id
1523  * @error: Operation error, if any, automatically freed if passed it.
1524  * @freebusy: (element-type utf8): a #GSList of iCalendar strings with all gathered free/busy components.
1525  *
1526  * Notifies listeners of the completion of the get_free_busy method call.
1527  * To pass actual free/busy objects to the client asynchronously
1528  * use e_data_cal_report_free_busy_data(), but the @freebusy should contain
1529  * all the objects being used in e_data_cal_report_free_busy_data().
1530  *
1531  * Since: 3.2
1532  */
1533 void
e_data_cal_respond_get_free_busy(EDataCal * cal,guint32 opid,GError * error,const GSList * freebusy)1534 e_data_cal_respond_get_free_busy (EDataCal *cal,
1535                                   guint32 opid,
1536                                   GError *error,
1537 				  const GSList *freebusy)
1538 {
1539 	ECalBackend *backend;
1540 	GSimpleAsyncResult *simple;
1541 	GQueue *queue = NULL;
1542 	const GSList *link;
1543 
1544 	g_return_if_fail (E_IS_DATA_CAL (cal));
1545 
1546 	backend = e_data_cal_ref_backend (cal);
1547 	g_return_if_fail (backend != NULL);
1548 
1549 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1550 	g_return_if_fail (simple != NULL);
1551 
1552 	/* Translators: This is prefix to a detailed error message */
1553 	g_prefix_error (&error, "%s", _("Cannot retrieve calendar free/busy list: "));
1554 
1555 	if (error != NULL) {
1556 		g_simple_async_result_take_error (simple, error);
1557 	} else {
1558 		for (link = freebusy; link; link = g_slist_next (link)) {
1559 			const gchar *ical_freebusy = link->data;
1560 
1561 			g_queue_push_tail (queue, g_strdup (ical_freebusy));
1562 		}
1563 	}
1564 
1565 	g_simple_async_result_complete_in_idle (simple);
1566 
1567 	g_object_unref (simple);
1568 	g_object_unref (backend);
1569 }
1570 
1571 /**
1572  * e_data_cal_respond_create_objects:
1573  * @cal: A calendar client interface.
1574  * @opid: associated operation id
1575  * @error: Operation error, if any, automatically freed if passed it.
1576  * @uids: (element-type utf8): UIDs of the objects created.
1577  * @new_components: (element-type ECalComponent): The newly created #ECalComponent objects.
1578  *
1579  * Notifies listeners of the completion of the create_objects method call.
1580  *
1581  * Since: 3.6
1582  */
1583 void
e_data_cal_respond_create_objects(EDataCal * cal,guint32 opid,GError * error,const GSList * uids,GSList * new_components)1584 e_data_cal_respond_create_objects (EDataCal *cal,
1585                                    guint32 opid,
1586                                    GError *error,
1587                                    const GSList *uids,
1588                                    GSList *new_components)
1589 {
1590 	ECalBackend *backend;
1591 	GSimpleAsyncResult *simple;
1592 	GQueue *queue = NULL;
1593 
1594 	g_return_if_fail (E_IS_DATA_CAL (cal));
1595 
1596 	backend = e_data_cal_ref_backend (cal);
1597 	g_return_if_fail (backend != NULL);
1598 
1599 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1600 	g_return_if_fail (simple != NULL);
1601 	g_return_if_fail (queue != NULL);
1602 
1603 	/* Translators: This is prefix to a detailed error message */
1604 	g_prefix_error (&error, "%s", _("Cannot create calendar object: "));
1605 
1606 	if (error == NULL) {
1607 		GQueue *inner_queue;
1608 		GSList *list, *link;
1609 
1610 		inner_queue = g_queue_new ();
1611 
1612 		list = (GSList *) uids;
1613 
1614 		for (link = list; link != NULL; link = g_slist_next (link))
1615 			g_queue_push_tail (inner_queue, g_strdup (link->data));
1616 
1617 		g_queue_push_tail (queue, inner_queue);
1618 
1619 		inner_queue = g_queue_new ();
1620 
1621 		list = (GSList *) new_components;
1622 
1623 		for (link = list; link != NULL; link = g_slist_next (link))
1624 			g_queue_push_tail (
1625 				inner_queue,
1626 				g_object_ref (link->data));
1627 
1628 		g_queue_push_tail (queue, inner_queue);
1629 
1630 	} else {
1631 		g_simple_async_result_take_error (simple, error);
1632 	}
1633 
1634 	g_simple_async_result_complete_in_idle (simple);
1635 
1636 	g_object_unref (simple);
1637 	g_object_unref (backend);
1638 }
1639 
1640 /**
1641  * e_data_cal_respond_modify_objects:
1642  * @cal: A calendar client interface.
1643  * @opid: associated operation id
1644  * @error: Operation error, if any, automatically freed if passed it.
1645  * @old_components: (element-type ECalComponent): The old #ECalComponent(s).
1646  * @new_components: (element-type ECalComponent): The new #ECalComponent(s).
1647  *
1648  * Notifies listeners of the completion of the modify_objects method call.
1649  *
1650  * Since: 3.6
1651  */
1652 void
e_data_cal_respond_modify_objects(EDataCal * cal,guint32 opid,GError * error,GSList * old_components,GSList * new_components)1653 e_data_cal_respond_modify_objects (EDataCal *cal,
1654                                    guint32 opid,
1655                                    GError *error,
1656                                    GSList *old_components,
1657                                    GSList *new_components)
1658 {
1659 	ECalBackend *backend;
1660 	GSimpleAsyncResult *simple;
1661 	GQueue *queue = NULL;
1662 
1663 	g_return_if_fail (E_IS_DATA_CAL (cal));
1664 
1665 	backend = e_data_cal_ref_backend (cal);
1666 	g_return_if_fail (backend != NULL);
1667 
1668 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1669 	g_return_if_fail (simple != NULL);
1670 	g_return_if_fail (queue != NULL);
1671 
1672 	/* Translators: This is prefix to a detailed error message */
1673 	g_prefix_error (&error, "%s", _("Cannot modify calendar object: "));
1674 
1675 	if (error == NULL) {
1676 		GQueue *inner_queue;
1677 		GSList *list, *link;
1678 
1679 		/* FIXME Ugh, this is awkward... */
1680 
1681 		inner_queue = g_queue_new ();
1682 
1683 		list = (GSList *) old_components;
1684 
1685 		for (link = list; link != NULL; link = g_slist_next (link)) {
1686 			if (link->data)
1687 				g_object_ref (link->data);
1688 			g_queue_push_tail (
1689 				inner_queue,
1690 				link->data);
1691 		}
1692 
1693 		g_queue_push_tail (queue, inner_queue);
1694 
1695 		inner_queue = g_queue_new ();
1696 
1697 		list = (GSList *) new_components;
1698 
1699 		for (link = list; link != NULL; link = g_slist_next (link))
1700 			g_queue_push_tail (
1701 				inner_queue,
1702 				g_object_ref (link->data));
1703 
1704 		g_queue_push_tail (queue, inner_queue);
1705 
1706 	} else {
1707 		g_simple_async_result_take_error (simple, error);
1708 	}
1709 
1710 	g_simple_async_result_complete_in_idle (simple);
1711 
1712 	g_object_unref (simple);
1713 	g_object_unref (backend);
1714 }
1715 
1716 /**
1717  * e_data_cal_respond_remove_objects:
1718  * @cal: A calendar client interface.
1719  * @opid: associated operation id
1720  * @error: Operation error, if any, automatically freed if passed it.
1721  * @ids: (element-type ECalComponentId): IDs of the removed objects.
1722  * @old_components: (element-type ECalComponent): The old #ECalComponent(s).
1723  * @new_components: (element-type ECalComponent): The new #ECalComponent(s).
1724  *    They will not be NULL only when removing instances of recurring appointments.
1725  *
1726  * Notifies listeners of the completion of the remove_objects method call.
1727  *
1728  * Since: 3.6
1729  */
1730 void
e_data_cal_respond_remove_objects(EDataCal * cal,guint32 opid,GError * error,const GSList * ids,GSList * old_components,GSList * new_components)1731 e_data_cal_respond_remove_objects (EDataCal *cal,
1732                                   guint32 opid,
1733                                   GError *error,
1734                                   const GSList *ids,
1735                                   GSList *old_components,
1736                                   GSList *new_components)
1737 {
1738 	ECalBackend *backend;
1739 	GSimpleAsyncResult *simple;
1740 	GQueue *queue = NULL;
1741 
1742 	g_return_if_fail (E_IS_DATA_CAL (cal));
1743 
1744 	backend = e_data_cal_ref_backend (cal);
1745 	g_return_if_fail (backend != NULL);
1746 
1747 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1748 	g_return_if_fail (simple != NULL);
1749 	g_return_if_fail (queue != NULL);
1750 
1751 	/* Translators: This is prefix to a detailed error message */
1752 	g_prefix_error (&error, "%s", _("Cannot remove calendar object: "));
1753 
1754 	if (error == NULL) {
1755 		GQueue *inner_queue;
1756 		GSList *list, *link;
1757 
1758 		/* FIXME Ugh, this is awkward... */
1759 
1760 		inner_queue = g_queue_new ();
1761 
1762 		list = (GSList *) ids;
1763 
1764 		for (link = list; link != NULL; link = g_slist_next (link))
1765 			g_queue_push_tail (
1766 				inner_queue,
1767 				e_cal_component_id_copy (link->data));
1768 
1769 		g_queue_push_tail (queue, inner_queue);
1770 
1771 		inner_queue = g_queue_new ();
1772 
1773 		list = (GSList *) old_components;
1774 
1775 		for (link = list; link != NULL; link = g_slist_next (link)) {
1776 			if (link->data)
1777 				g_object_ref (link->data);
1778 			g_queue_push_tail (
1779 				inner_queue,
1780 				link->data);
1781 		}
1782 
1783 		g_queue_push_tail (queue, inner_queue);
1784 
1785 		if (new_components != NULL) {
1786 			inner_queue = g_queue_new ();
1787 
1788 			list = (GSList *) new_components;
1789 
1790 			/* XXX Careful here.  Apparently list elements
1791 			 *     can be NULL.  What a horrible API design. */
1792 			for (link = list; link != NULL; link = g_slist_next (link)) {
1793 				if (link->data != NULL)
1794 					g_object_ref (link->data);
1795 				g_queue_push_tail (
1796 					inner_queue, link->data);
1797 			}
1798 
1799 			g_queue_push_tail (queue, inner_queue);
1800 		}
1801 
1802 	} else {
1803 		g_simple_async_result_take_error (simple, error);
1804 	}
1805 
1806 	g_simple_async_result_complete_in_idle (simple);
1807 
1808 	g_object_unref (simple);
1809 	g_object_unref (backend);
1810 }
1811 
1812 /**
1813  * e_data_cal_respond_receive_objects:
1814  * @cal: A calendar client interface.
1815  * @opid: associated operation id
1816  * @error: Operation error, if any, automatically freed if passed it.
1817  *
1818  * Notifies listeners of the completion of the receive_objects method call.
1819  *
1820  * Since: 3.2
1821  */
1822 void
e_data_cal_respond_receive_objects(EDataCal * cal,guint32 opid,GError * error)1823 e_data_cal_respond_receive_objects (EDataCal *cal,
1824                                     guint32 opid,
1825                                     GError *error)
1826 {
1827 	ECalBackend *backend;
1828 	GSimpleAsyncResult *simple;
1829 
1830 	g_return_if_fail (E_IS_DATA_CAL (cal));
1831 
1832 	backend = e_data_cal_ref_backend (cal);
1833 	g_return_if_fail (backend != NULL);
1834 
1835 	simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
1836 	g_return_if_fail (simple != NULL);
1837 
1838 	/* Translators: This is prefix to a detailed error message */
1839 	g_prefix_error (&error, "%s", _("Cannot receive calendar objects: "));
1840 
1841 	if (error != NULL)
1842 		g_simple_async_result_take_error (simple, error);
1843 
1844 	g_simple_async_result_complete_in_idle (simple);
1845 
1846 	g_object_unref (simple);
1847 	g_object_unref (backend);
1848 }
1849 
1850 /**
1851  * e_data_cal_respond_send_objects:
1852  * @cal: A calendar client interface.
1853  * @opid: associated operation id
1854  * @error: Operation error, if any, automatically freed if passed it.
1855  * @users: (element-type utf8): List of users.
1856  * @calobj: An iCalendar string representing the object sent.
1857  *
1858  * Notifies listeners of the completion of the send_objects method call.
1859  *
1860  * Since: 3.2
1861  */
1862 void
e_data_cal_respond_send_objects(EDataCal * cal,guint32 opid,GError * error,const GSList * users,const gchar * calobj)1863 e_data_cal_respond_send_objects (EDataCal *cal,
1864                                  guint32 opid,
1865                                  GError *error,
1866                                  const GSList *users,
1867                                  const gchar *calobj)
1868 {
1869 	ECalBackend *backend;
1870 	GSimpleAsyncResult *simple;
1871 	GQueue *queue = NULL;
1872 
1873 	g_return_if_fail (E_IS_DATA_CAL (cal));
1874 
1875 	backend = e_data_cal_ref_backend (cal);
1876 	g_return_if_fail (backend != NULL);
1877 
1878 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1879 	g_return_if_fail (simple != NULL);
1880 	g_return_if_fail (queue != NULL);
1881 
1882 	/* Translators: This is prefix to a detailed error message */
1883 	g_prefix_error (&error, "%s", _("Cannot send calendar objects: "));
1884 
1885 	if (error == NULL) {
1886 		GSList *list, *link;
1887 
1888 		g_queue_push_tail (queue, g_strdup (calobj));
1889 
1890 		list = (GSList *) users;
1891 
1892 		for (link = list; link != NULL; link = g_slist_next (link))
1893 			g_queue_push_tail (queue, g_strdup (link->data));
1894 
1895 	} else {
1896 		g_simple_async_result_take_error (simple, error);
1897 	}
1898 
1899 	g_simple_async_result_complete_in_idle (simple);
1900 
1901 	g_object_unref (simple);
1902 	g_object_unref (backend);
1903 }
1904 
1905 /**
1906  * e_data_cal_respond_get_attachment_uris:
1907  * @cal: A calendar client interface.
1908  * @opid: associated operation id
1909  * @error: Operation error, if any, automatically freed if passed it.
1910  * @attachment_uris: (element-type utf8): List of retrieved attachment uri's.
1911  *
1912  * Notifies listeners of the completion of the get_attachment_uris method call.
1913  *
1914  * Since: 3.2
1915  **/
1916 void
e_data_cal_respond_get_attachment_uris(EDataCal * cal,guint32 opid,GError * error,const GSList * attachment_uris)1917 e_data_cal_respond_get_attachment_uris (EDataCal *cal,
1918                                         guint32 opid,
1919                                         GError *error,
1920                                         const GSList *attachment_uris)
1921 {
1922 	ECalBackend *backend;
1923 	GSimpleAsyncResult *simple;
1924 	GQueue *queue = NULL;
1925 
1926 	g_return_if_fail (E_IS_DATA_CAL (cal));
1927 
1928 	backend = e_data_cal_ref_backend (cal);
1929 	g_return_if_fail (backend != NULL);
1930 
1931 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
1932 	g_return_if_fail (simple != NULL);
1933 	g_return_if_fail (queue != NULL);
1934 
1935 	/* Translators: This is prefix to a detailed error message */
1936 	g_prefix_error (&error, "%s", _("Could not retrieve attachment uris: "));
1937 
1938 	if (error == NULL) {
1939 		GSList *list, *link;
1940 
1941 		list = (GSList *) attachment_uris;
1942 
1943 		for (link = list; link != NULL; link = g_slist_next (link))
1944 			g_queue_push_tail (queue, g_strdup (link->data));
1945 	} else {
1946 		g_simple_async_result_take_error (simple, error);
1947 	}
1948 
1949 	g_simple_async_result_complete_in_idle (simple);
1950 
1951 	g_object_unref (simple);
1952 	g_object_unref (backend);
1953 }
1954 
1955 /**
1956  * e_data_cal_respond_discard_alarm:
1957  * @cal: A calendar client interface.
1958  * @opid: associated operation id
1959  * @error: Operation error, if any, automatically freed if passed it.
1960  *
1961  * Notifies listeners of the completion of the discard_alarm method call.
1962  *
1963  * Since: 3.2
1964  **/
1965 void
e_data_cal_respond_discard_alarm(EDataCal * cal,guint32 opid,GError * error)1966 e_data_cal_respond_discard_alarm (EDataCal *cal,
1967                                   guint32 opid,
1968                                   GError *error)
1969 {
1970 	ECalBackend *backend;
1971 	GSimpleAsyncResult *simple;
1972 
1973 	g_return_if_fail (E_IS_DATA_CAL (cal));
1974 
1975 	backend = e_data_cal_ref_backend (cal);
1976 	g_return_if_fail (backend != NULL);
1977 
1978 	simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
1979 	g_return_if_fail (simple != NULL);
1980 
1981 	/* Translators: This is prefix to a detailed error message */
1982 	g_prefix_error (&error, "%s", _("Could not discard reminder: "));
1983 
1984 	if (error != NULL)
1985 		g_simple_async_result_take_error (simple, error);
1986 
1987 	g_simple_async_result_complete_in_idle (simple);
1988 
1989 	g_object_unref (simple);
1990 	g_object_unref (backend);
1991 }
1992 
1993 /**
1994  * e_data_cal_respond_get_timezone:
1995  * @cal: A calendar client interface.
1996  * @opid: associated operation id
1997  * @error: Operation error, if any, automatically freed if passed it.
1998  * @tzobject: The requested timezone as an iCalendar string.
1999  *
2000  * Notifies listeners of the completion of the get_timezone method call.
2001  *
2002  * Since: 3.2
2003  */
2004 void
e_data_cal_respond_get_timezone(EDataCal * cal,guint32 opid,GError * error,const gchar * tzobject)2005 e_data_cal_respond_get_timezone (EDataCal *cal,
2006                                  guint32 opid,
2007                                  GError *error,
2008                                  const gchar *tzobject)
2009 {
2010 	ECalBackend *backend;
2011 	GSimpleAsyncResult *simple;
2012 	GQueue *queue = NULL;
2013 
2014 	g_return_if_fail (E_IS_DATA_CAL (cal));
2015 
2016 	backend = e_data_cal_ref_backend (cal);
2017 	g_return_if_fail (backend != NULL);
2018 
2019 	simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
2020 	g_return_if_fail (simple != NULL);
2021 	g_return_if_fail (queue != NULL);
2022 
2023 	/* Translators: This is prefix to a detailed error message */
2024 	g_prefix_error (&error, "%s", _("Could not retrieve calendar time zone: "));
2025 
2026 	if (error == NULL) {
2027 		g_queue_push_tail (queue, g_strdup (tzobject));
2028 	} else {
2029 		g_simple_async_result_take_error (simple, error);
2030 	}
2031 
2032 	g_simple_async_result_complete_in_idle (simple);
2033 
2034 	g_object_unref (simple);
2035 	g_object_unref (backend);
2036 }
2037 
2038 /**
2039  * e_data_cal_respond_add_timezone:
2040  * @cal: A calendar client interface.
2041  * @opid: associated operation id
2042  * @error: Operation error, if any, automatically freed if passed it.
2043  *
2044  * Notifies listeners of the completion of the add_timezone method call.
2045  *
2046  * Since: 3.2
2047  */
2048 void
e_data_cal_respond_add_timezone(EDataCal * cal,guint32 opid,GError * error)2049 e_data_cal_respond_add_timezone (EDataCal *cal,
2050                                  guint32 opid,
2051                                  GError *error)
2052 {
2053 	ECalBackend *backend;
2054 	GSimpleAsyncResult *simple;
2055 
2056 	g_return_if_fail (E_IS_DATA_CAL (cal));
2057 
2058 	backend = e_data_cal_ref_backend (cal);
2059 	g_return_if_fail (backend != NULL);
2060 
2061 	simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
2062 	g_return_if_fail (simple != NULL);
2063 
2064 	/* Translators: This is prefix to a detailed error message */
2065 	g_prefix_error (&error, "%s", _("Could not add calendar time zone: "));
2066 
2067 	if (error != NULL)
2068 		g_simple_async_result_take_error (simple, error);
2069 
2070 	g_simple_async_result_complete_in_idle (simple);
2071 
2072 	g_object_unref (simple);
2073 	g_object_unref (backend);
2074 }
2075 
2076 /**
2077  * e_data_cal_report_error:
2078  * @cal: an #EDataCal
2079  * @message: an error message to report
2080  *
2081  * Emits an error message, thus the clients can be notified about it.
2082  *
2083  * Since: 3.2
2084  **/
2085 void
e_data_cal_report_error(EDataCal * cal,const gchar * message)2086 e_data_cal_report_error (EDataCal *cal,
2087                          const gchar *message)
2088 {
2089 	gchar *valid_utf8;
2090 
2091 	g_return_if_fail (E_IS_DATA_CAL (cal));
2092 	g_return_if_fail (message != NULL);
2093 
2094 	valid_utf8 = e_util_utf8_make_valid (message);
2095 
2096 	e_dbus_calendar_emit_error (cal->priv->dbus_interface, valid_utf8 ? valid_utf8 : message);
2097 
2098 	g_free (valid_utf8);
2099 }
2100 
2101 /**
2102  * e_data_cal_report_free_busy_data:
2103  * @cal: an #EDataCal
2104  * @freebusy: (element-type utf8): a #GSList of free/busy components encoded as string
2105  *
2106  * Reports result of a free/busy query on the @cal.
2107  *
2108  * Since: 3.2
2109  **/
2110 void
e_data_cal_report_free_busy_data(EDataCal * cal,const GSList * freebusy)2111 e_data_cal_report_free_busy_data (EDataCal *cal,
2112                                   const GSList *freebusy)
2113 {
2114 	gchar **strv;
2115 	guint length;
2116 	gint ii = 0;
2117 
2118 	g_return_if_fail (E_IS_DATA_CAL (cal));
2119 
2120 	length = g_slist_length ((GSList *) freebusy);
2121 	strv = g_new0 (gchar *, length + 1);
2122 
2123 	while (freebusy != NULL) {
2124 		strv[ii++] = e_util_utf8_make_valid (freebusy->data);
2125 		freebusy = g_slist_next ((GSList *) freebusy);
2126 	}
2127 
2128 	e_dbus_calendar_emit_free_busy_data (
2129 		cal->priv->dbus_interface,
2130 		(const gchar * const *) strv);
2131 
2132 	g_strfreev (strv);
2133 }
2134 
2135 /**
2136  * e_data_cal_report_backend_property_changed:
2137  * @cal: an #EDataCal
2138  * @prop_name: property name
2139  * @prop_value: new property value
2140  *
2141  * Notifies client about certain property value change
2142  *
2143  * Since: 3.2
2144  **/
2145 void
e_data_cal_report_backend_property_changed(EDataCal * cal,const gchar * prop_name,const gchar * prop_value)2146 e_data_cal_report_backend_property_changed (EDataCal *cal,
2147                                             const gchar *prop_name,
2148                                             const gchar *prop_value)
2149 {
2150 	EDBusCalendar *dbus_interface;
2151 	gchar **strv;
2152 
2153 	g_return_if_fail (E_IS_DATA_CAL (cal));
2154 	g_return_if_fail (prop_name != NULL);
2155 
2156 	if (prop_value == NULL)
2157 		prop_value = "";
2158 
2159 	dbus_interface = cal->priv->dbus_interface;
2160 
2161 	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
2162 		strv = g_strsplit (prop_value, ",", -1);
2163 		e_dbus_calendar_set_capabilities (
2164 			dbus_interface, (const gchar * const *) strv);
2165 		g_strfreev (strv);
2166 	}
2167 
2168 	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION))
2169 		e_dbus_calendar_set_revision (dbus_interface, prop_value);
2170 
2171 	if (g_str_equal (prop_name, E_CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS))
2172 		e_dbus_calendar_set_cal_email_address (dbus_interface, prop_value);
2173 
2174 	if (g_str_equal (prop_name, E_CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS))
2175 		e_dbus_calendar_set_alarm_email_address (dbus_interface, prop_value);
2176 
2177 	if (g_str_equal (prop_name, E_CAL_BACKEND_PROPERTY_DEFAULT_OBJECT))
2178 		e_dbus_calendar_set_default_object (dbus_interface, prop_value);
2179 
2180 	/* Ensure the property change signal on the D-Bus is invoked immediately, not on idle */
2181 	g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (dbus_interface));
2182 
2183 	if (cal->priv->connection && !g_dbus_connection_is_closed (cal->priv->connection))
2184 		g_dbus_connection_flush_sync (cal->priv->connection, NULL, NULL);
2185 
2186 	/* Disregard anything else. */
2187 }
2188 
2189 static void
data_cal_set_backend(EDataCal * cal,ECalBackend * backend)2190 data_cal_set_backend (EDataCal *cal,
2191                       ECalBackend *backend)
2192 {
2193 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
2194 
2195 	g_weak_ref_set (&cal->priv->backend, backend);
2196 }
2197 
2198 static void
data_cal_set_connection(EDataCal * cal,GDBusConnection * connection)2199 data_cal_set_connection (EDataCal *cal,
2200                          GDBusConnection *connection)
2201 {
2202 	g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2203 	g_return_if_fail (cal->priv->connection == NULL);
2204 
2205 	cal->priv->connection = g_object_ref (connection);
2206 }
2207 
2208 static void
data_cal_set_object_path(EDataCal * cal,const gchar * object_path)2209 data_cal_set_object_path (EDataCal *cal,
2210                           const gchar *object_path)
2211 {
2212 	g_return_if_fail (object_path != NULL);
2213 	g_return_if_fail (cal->priv->object_path == NULL);
2214 
2215 	cal->priv->object_path = g_strdup (object_path);
2216 }
2217 
2218 static void
data_cal_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)2219 data_cal_set_property (GObject *object,
2220                        guint property_id,
2221                        const GValue *value,
2222                        GParamSpec *pspec)
2223 {
2224 	switch (property_id) {
2225 		case PROP_BACKEND:
2226 			data_cal_set_backend (
2227 				E_DATA_CAL (object),
2228 				g_value_get_object (value));
2229 			return;
2230 
2231 		case PROP_CONNECTION:
2232 			data_cal_set_connection (
2233 				E_DATA_CAL (object),
2234 				g_value_get_object (value));
2235 			return;
2236 
2237 		case PROP_OBJECT_PATH:
2238 			data_cal_set_object_path (
2239 				E_DATA_CAL (object),
2240 				g_value_get_string (value));
2241 			return;
2242 	}
2243 
2244 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2245 }
2246 
2247 static void
data_cal_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)2248 data_cal_get_property (GObject *object,
2249                        guint property_id,
2250                        GValue *value,
2251                        GParamSpec *pspec)
2252 {
2253 	switch (property_id) {
2254 		case PROP_BACKEND:
2255 			g_value_take_object (
2256 				value,
2257 				e_data_cal_ref_backend (
2258 				E_DATA_CAL (object)));
2259 			return;
2260 
2261 		case PROP_CONNECTION:
2262 			g_value_set_object (
2263 				value,
2264 				e_data_cal_get_connection (
2265 				E_DATA_CAL (object)));
2266 			return;
2267 
2268 		case PROP_OBJECT_PATH:
2269 			g_value_set_string (
2270 				value,
2271 				e_data_cal_get_object_path (
2272 				E_DATA_CAL (object)));
2273 			return;
2274 	}
2275 
2276 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2277 }
2278 
2279 static void
data_cal_dispose(GObject * object)2280 data_cal_dispose (GObject *object)
2281 {
2282 	EDataCalPrivate *priv;
2283 
2284 	priv = E_DATA_CAL (object)->priv;
2285 
2286 	g_weak_ref_set (&priv->backend, NULL);
2287 
2288 	g_clear_object (&priv->connection);
2289 
2290 	g_hash_table_remove_all (priv->sender_table);
2291 
2292 	/* Chain up to parent's dispose() method. */
2293 	G_OBJECT_CLASS (e_data_cal_parent_class)->dispose (object);
2294 }
2295 
2296 static void
data_cal_finalize(GObject * object)2297 data_cal_finalize (GObject *object)
2298 {
2299 	EDataCalPrivate *priv;
2300 
2301 	priv = E_DATA_CAL (object)->priv;
2302 
2303 	g_free (priv->object_path);
2304 
2305 	g_mutex_clear (&priv->sender_lock);
2306 	g_weak_ref_clear (&priv->backend);
2307 	g_hash_table_destroy (priv->sender_table);
2308 
2309 	g_clear_object (&priv->dbus_interface);
2310 
2311 	/* Chain up to parent's finalize() method. */
2312 	G_OBJECT_CLASS (e_data_cal_parent_class)->finalize (object);
2313 }
2314 
2315 static void
data_cal_constructed(GObject * object)2316 data_cal_constructed (GObject *object)
2317 {
2318 	EDataCal *cal = E_DATA_CAL (object);
2319 	ECalBackend *backend;
2320 	const gchar *prop_name;
2321 	gchar *prop_value;
2322 
2323 	/* Chain up to parent's constructed() method. */
2324 	G_OBJECT_CLASS (e_data_cal_parent_class)->constructed (object);
2325 
2326 	backend = e_data_cal_ref_backend (cal);
2327 	g_warn_if_fail (backend != NULL);
2328 
2329 	/* Attach ourselves to the ECalBackend. */
2330 	e_cal_backend_set_data_cal (backend, cal);
2331 
2332 	e_binding_bind_property (
2333 		backend, "cache-dir",
2334 		cal->priv->dbus_interface, "cache-dir",
2335 		G_BINDING_SYNC_CREATE);
2336 
2337 	e_binding_bind_property (
2338 		backend, "online",
2339 		cal->priv->dbus_interface, "online",
2340 		G_BINDING_SYNC_CREATE);
2341 
2342 	e_binding_bind_property (
2343 		backend, "writable",
2344 		cal->priv->dbus_interface, "writable",
2345 		G_BINDING_SYNC_CREATE);
2346 
2347 	/* XXX Initialize the rest of the properties. */
2348 
2349 	prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
2350 	prop_value = e_cal_backend_get_backend_property (backend, prop_name);
2351 	e_data_cal_report_backend_property_changed (
2352 		cal, prop_name, prop_value);
2353 	g_free (prop_value);
2354 
2355 	prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
2356 	prop_value = e_cal_backend_get_backend_property (backend, prop_name);
2357 	e_data_cal_report_backend_property_changed (
2358 		cal, prop_name, prop_value);
2359 	g_free (prop_value);
2360 
2361 	prop_name = E_CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
2362 	prop_value = e_cal_backend_get_backend_property (backend, prop_name);
2363 	e_data_cal_report_backend_property_changed (
2364 		cal, prop_name, prop_value);
2365 	g_free (prop_value);
2366 
2367 	prop_name = E_CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
2368 	prop_value = e_cal_backend_get_backend_property (backend, prop_name);
2369 	e_data_cal_report_backend_property_changed (
2370 		cal, prop_name, prop_value);
2371 	g_free (prop_value);
2372 
2373 	prop_name = E_CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
2374 	prop_value = e_cal_backend_get_backend_property (backend, prop_name);
2375 	e_data_cal_report_backend_property_changed (
2376 		cal, prop_name, prop_value);
2377 	g_free (prop_value);
2378 
2379 	g_object_unref (backend);
2380 }
2381 
2382 static gboolean
data_cal_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)2383 data_cal_initable_init (GInitable *initable,
2384                         GCancellable *cancellable,
2385                         GError **error)
2386 {
2387 	EDataCal *cal;
2388 
2389 	cal = E_DATA_CAL (initable);
2390 
2391 	return g_dbus_interface_skeleton_export (
2392 		G_DBUS_INTERFACE_SKELETON (cal->priv->dbus_interface),
2393 		cal->priv->connection,
2394 		cal->priv->object_path,
2395 		error);
2396 }
2397 
2398 static void
e_data_cal_class_init(EDataCalClass * class)2399 e_data_cal_class_init (EDataCalClass *class)
2400 {
2401 	GObjectClass *object_class;
2402 
2403 	object_class = G_OBJECT_CLASS (class);
2404 	object_class->set_property = data_cal_set_property;
2405 	object_class->get_property = data_cal_get_property;
2406 	object_class->dispose = data_cal_dispose;
2407 	object_class->finalize = data_cal_finalize;
2408 	object_class->constructed = data_cal_constructed;
2409 
2410 	g_object_class_install_property (
2411 		object_class,
2412 		PROP_BACKEND,
2413 		g_param_spec_object (
2414 			"backend",
2415 			"Backend",
2416 			"The backend driving this connection",
2417 			E_TYPE_CAL_BACKEND,
2418 			G_PARAM_READWRITE |
2419 			G_PARAM_CONSTRUCT_ONLY |
2420 			G_PARAM_STATIC_STRINGS));
2421 
2422 	g_object_class_install_property (
2423 		object_class,
2424 		PROP_CONNECTION,
2425 		g_param_spec_object (
2426 			"connection",
2427 			"Connection",
2428 			"The GDBusConnection on which to "
2429 			"export the calendar interface",
2430 			G_TYPE_DBUS_CONNECTION,
2431 			G_PARAM_READWRITE |
2432 			G_PARAM_CONSTRUCT_ONLY |
2433 			G_PARAM_STATIC_STRINGS));
2434 
2435 	g_object_class_install_property (
2436 		object_class,
2437 		PROP_OBJECT_PATH,
2438 		g_param_spec_string (
2439 			"object-path",
2440 			"Object Path",
2441 			"The object path at which to "
2442 			"export the calendar interface",
2443 			NULL,
2444 			G_PARAM_READWRITE |
2445 			G_PARAM_CONSTRUCT_ONLY |
2446 			G_PARAM_STATIC_STRINGS));
2447 }
2448 
2449 static void
e_data_cal_initable_init(GInitableIface * iface)2450 e_data_cal_initable_init (GInitableIface *iface)
2451 {
2452 	iface->init = data_cal_initable_init;
2453 }
2454 
2455 static void
e_data_cal_init(EDataCal * data_cal)2456 e_data_cal_init (EDataCal *data_cal)
2457 {
2458 	EDBusCalendar *dbus_interface;
2459 
2460 	data_cal->priv = e_data_cal_get_instance_private (data_cal);
2461 
2462 	dbus_interface = e_dbus_calendar_skeleton_new ();
2463 	data_cal->priv->dbus_interface = dbus_interface;
2464 
2465 	g_mutex_init (&data_cal->priv->sender_lock);
2466 	g_weak_ref_init (&data_cal->priv->backend, NULL);
2467 
2468 	data_cal->priv->sender_table = g_hash_table_new_full (
2469 		(GHashFunc) g_str_hash,
2470 		(GEqualFunc) g_str_equal,
2471 		(GDestroyNotify) g_free,
2472 		(GDestroyNotify) g_ptr_array_unref);
2473 
2474 	g_signal_connect (
2475 		dbus_interface, "handle-retrieve-properties",
2476 		G_CALLBACK (data_cal_handle_retrieve_properties_cb), data_cal);
2477 	g_signal_connect (
2478 		dbus_interface, "handle-open",
2479 		G_CALLBACK (data_cal_handle_open_cb), data_cal);
2480 	g_signal_connect (
2481 		dbus_interface, "handle-refresh",
2482 		G_CALLBACK (data_cal_handle_refresh_cb), data_cal);
2483 	g_signal_connect (
2484 		dbus_interface, "handle-get-object",
2485 		G_CALLBACK (data_cal_handle_get_object_cb), data_cal);
2486 	g_signal_connect (
2487 		dbus_interface, "handle-get-object-list",
2488 		G_CALLBACK (data_cal_handle_get_object_list_cb), data_cal);
2489 	g_signal_connect (
2490 		dbus_interface, "handle-get-free-busy",
2491 		G_CALLBACK (data_cal_handle_get_free_busy_cb), data_cal);
2492 	g_signal_connect (
2493 		dbus_interface, "handle-create-objects",
2494 		G_CALLBACK (data_cal_handle_create_objects_cb), data_cal);
2495 	g_signal_connect (
2496 		dbus_interface, "handle-modify-objects",
2497 		G_CALLBACK (data_cal_handle_modify_objects_cb), data_cal);
2498 	g_signal_connect (
2499 		dbus_interface, "handle-remove-objects",
2500 		G_CALLBACK (data_cal_handle_remove_objects_cb), data_cal);
2501 	g_signal_connect (
2502 		dbus_interface, "handle-receive-objects",
2503 		G_CALLBACK (data_cal_handle_receive_objects_cb), data_cal);
2504 	g_signal_connect (
2505 		dbus_interface, "handle-send-objects",
2506 		G_CALLBACK (data_cal_handle_send_objects_cb), data_cal);
2507 	g_signal_connect (
2508 		dbus_interface, "handle-get-attachment-uris",
2509 		G_CALLBACK (data_cal_handle_get_attachment_uris_cb), data_cal);
2510 	g_signal_connect (
2511 		dbus_interface, "handle-discard-alarm",
2512 		G_CALLBACK (data_cal_handle_discard_alarm_cb), data_cal);
2513 	g_signal_connect (
2514 		dbus_interface, "handle-get-view",
2515 		G_CALLBACK (data_cal_handle_get_view_cb), data_cal);
2516 	g_signal_connect (
2517 		dbus_interface, "handle-get-timezone",
2518 		G_CALLBACK (data_cal_handle_get_timezone_cb), data_cal);
2519 	g_signal_connect (
2520 		dbus_interface, "handle-add-timezone",
2521 		G_CALLBACK (data_cal_handle_add_timezone_cb), data_cal);
2522 	g_signal_connect (
2523 		dbus_interface, "handle-close",
2524 		G_CALLBACK (data_cal_handle_close_cb), data_cal);
2525 }
2526 
2527 /**
2528  * e_data_cal_new:
2529  * @backend: (type ECalBackend): an #ECalBackend
2530  * @connection: a #GDBusConnection
2531  * @object_path: object path for the D-Bus interface
2532  * @error: return location for a #GError, or %NULL
2533  *
2534  * Creates a new #EDataCal and exports the Calendar D-Bus interface
2535  * on @connection at @object_path.  The #EDataCal handles incoming remote
2536  * method invocations and forwards them to the @backend.  If the Calendar
2537  * interface fails to export, the function sets @error and returns %NULL.
2538  *
2539  * Returns: (transfer full) (nullable): an #EDataCal, or %NULL on error
2540  **/
2541 EDataCal *
e_data_cal_new(ECalBackend * backend,GDBusConnection * connection,const gchar * object_path,GError ** error)2542 e_data_cal_new (ECalBackend *backend,
2543                 GDBusConnection *connection,
2544                 const gchar *object_path,
2545                 GError **error)
2546 {
2547 	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
2548 	g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2549 	g_return_val_if_fail (object_path != NULL, NULL);
2550 
2551 	return g_initable_new (
2552 		E_TYPE_DATA_CAL, NULL, error,
2553 		"backend", backend,
2554 		"connection", connection,
2555 		"object-path", object_path,
2556 		NULL);
2557 }
2558 
2559 /**
2560  * e_data_cal_ref_backend:
2561  * @cal: an #EDataCal
2562  *
2563  * Returns the #ECalBackend to which incoming remote method invocations
2564  * are being forwarded.
2565  *
2566  * The returned #ECalBackend is referenced for thread-safety and should
2567  * be unreferenced with g_object_unref() when finished with it.
2568  *
2569  * Returns: (type ECalBackend) (transfer full) (nullable): an #ECalBackend
2570  *
2571  * Since: 3.10
2572  **/
2573 ECalBackend *
e_data_cal_ref_backend(EDataCal * cal)2574 e_data_cal_ref_backend (EDataCal *cal)
2575 {
2576 	g_return_val_if_fail (E_IS_DATA_CAL (cal), NULL);
2577 
2578 	return g_weak_ref_get (&cal->priv->backend);
2579 }
2580 
2581 /**
2582  * e_data_cal_get_connection:
2583  * @cal: an #EDataCal
2584  *
2585  * Returns the #GDBusConnection on which the Calendar D-Bus interface
2586  * is exported.
2587  *
2588  * Returns: (transfer none): the #GDBusConnection
2589  *
2590  * Since: 3.8
2591  **/
2592 GDBusConnection *
e_data_cal_get_connection(EDataCal * cal)2593 e_data_cal_get_connection (EDataCal *cal)
2594 {
2595 	g_return_val_if_fail (E_IS_DATA_CAL (cal), NULL);
2596 
2597 	return cal->priv->connection;
2598 }
2599 
2600 /**
2601  * e_data_cal_get_object_path:
2602  * @cal: an #EDataCal
2603  *
2604  * Returns the object path at which the Calendar D-Bus interface is
2605  * exported.
2606  *
2607  * Returns: the object path
2608  *
2609  * Since: 3.8
2610  **/
2611 const gchar *
e_data_cal_get_object_path(EDataCal * cal)2612 e_data_cal_get_object_path (EDataCal *cal)
2613 {
2614 	g_return_val_if_fail (E_IS_DATA_CAL (cal), NULL);
2615 
2616 	return cal->priv->object_path;
2617 }
2618 
2619