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