896285a1facc77c332e577f2488819f734172cb7
[platform/upstream/evolution-data-server.git] / calendar / libedata-cal / e-data-cal.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar client interface object
3  *
4  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5  * Copyright (C) 2009 Intel Corporation
6  *
7  * Authors: Federico Mena-Quintero <federico@ximian.com>
8  *          Rodrigo Moya <rodrigo@ximian.com>
9  *          Ross Burton <ross@linux.intel.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of version 2 of the GNU Lesser General Public
13  * License as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <libical/ical.h>
30 #include <glib/gi18n-lib.h>
31 #include <unistd.h>
32
33 #include <libedataserver/libedataserver.h>
34
35 #include "e-data-cal.h"
36 #include "e-gdbus-cal.h"
37 #include "e-cal-backend.h"
38 #include "e-cal-backend-sexp.h"
39
40 #define E_DATA_CAL_GET_PRIVATE(obj) \
41         (G_TYPE_INSTANCE_GET_PRIVATE \
42         ((obj), E_TYPE_DATA_CAL, EDataCalPrivate))
43
44 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
45 #define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
46
47 struct _EDataCalPrivate {
48         EGdbusCal *gdbus_object;
49
50         ECalBackend *backend;
51
52         GStaticRecMutex pending_ops_lock;
53         GHashTable *pending_ops; /* opid to GCancellable for still running operations */
54 };
55
56 enum {
57         PROP_0,
58         PROP_BACKEND
59 };
60
61 static EOperationPool *ops_pool = NULL;
62
63 typedef enum {
64         OP_OPEN,
65         OP_REMOVE,
66         OP_REFRESH,
67         OP_GET_BACKEND_PROPERTY,
68         OP_SET_BACKEND_PROPERTY,
69         OP_GET_OBJECT,
70         OP_GET_OBJECT_LIST,
71         OP_GET_FREE_BUSY,
72         OP_CREATE_OBJECTS,
73         OP_MODIFY_OBJECTS,
74         OP_REMOVE_OBJECTS,
75         OP_RECEIVE_OBJECTS,
76         OP_SEND_OBJECTS,
77         OP_GET_ATTACHMENT_URIS,
78         OP_DISCARD_ALARM,
79         OP_GET_VIEW,
80         OP_GET_TIMEZONE,
81         OP_ADD_TIMEZONE,
82         OP_CANCEL_OPERATION,
83         OP_CANCEL_ALL,
84         OP_CLOSE
85 } OperationID;
86
87 typedef struct {
88         OperationID op;
89         guint32 id; /* operation id */
90         EDataCal *cal; /* calendar */
91         GCancellable *cancellable;
92
93         union {
94                 /* OP_OPEN */
95                 gboolean only_if_exists;
96                 /* OP_GET_OBJECT */
97                 /* OP_GET_ATTACHMENT_URIS */
98                 struct _ur {
99                         gchar *uid;
100                         gchar *rid;
101                 } ur;
102                 /* OP_DISCARD_ALARM */
103                 struct _ura {
104                         gchar *uid;
105                         gchar *rid;
106                         gchar *auid;
107                 } ura;
108                 /* OP_GET_OBJECT_LIST */
109                 /* OP_GET_VIEW */
110                 gchar *sexp;
111                 /* OP_GET_FREE_BUSY */
112                 struct _free_busy {
113                         time_t start, end;
114                         GSList *users;
115                 } fb;
116                 /* OP_CREATE_OBJECTS */
117                 GSList *calobjs;
118                 /* OP_RECEIVE_OBJECTS */
119                 /* OP_SEND_OBJECTS */
120                 struct _co {
121                         gchar *calobj;
122                 } co;
123                 /* OP_MODIFY_OBJECTS */
124                 struct _mo {
125                         GSList *calobjs;
126                         EDataCalObjModType mod;
127                 } mo;
128                 /* OP_REMOVE_OBJECTS */
129                 struct _ro {
130                         GSList *ids;
131                         EDataCalObjModType mod;
132                 } ro;
133                 /* OP_GET_TIMEZONE */
134                 gchar *tzid;
135                 /* OP_ADD_TIMEZONE */
136                 gchar *tzobject;
137                 /* OP_CANCEL_OPERATION */
138                 guint opid;
139                 /* OP_GET_BACKEND_PROPERTY */
140                 gchar *prop_name;
141                 /* OP_SET_BACKEND_PROPERTY */
142                 struct _sbp {
143                         gchar *prop_name;
144                         gchar *prop_value;
145                 } sbp;
146
147                 /* OP_REMOVE */
148                 /* OP_REFRESH */
149                 /* OP_CANCEL_ALL */
150                 /* OP_CLOSE */
151         } d;
152 } OperationData;
153
154 G_DEFINE_TYPE (EDataCal, e_data_cal, G_TYPE_OBJECT);
155
156 /* Function to get a new EDataCalView path, used by get_view below */
157 static gchar *
158 construct_calview_path (void)
159 {
160         static guint counter = 1;
161         return g_strdup_printf ("/org/gnome/evolution/dataserver/CalendarView/%d/%d", getpid (), counter++);
162 }
163
164 static void
165 cancel_ops_cb (gpointer opid,
166                gpointer cancellable,
167                gpointer user_data)
168 {
169         g_return_if_fail (cancellable != NULL);
170
171         g_cancellable_cancel (cancellable);
172 }
173
174 static void
175 operation_thread (gpointer data,
176                   gpointer user_data)
177 {
178         OperationData *op = data;
179         ECalBackend *backend;
180
181         backend = e_data_cal_get_backend (op->cal);
182
183         switch (op->op) {
184         case OP_OPEN:
185                 e_cal_backend_open (backend, op->cal, op->id, op->cancellable, op->d.only_if_exists);
186                 break;
187         case OP_REMOVE:
188                 e_cal_backend_remove (backend, op->cal, op->id, op->cancellable);
189                 break;
190         case OP_REFRESH:
191                 e_cal_backend_refresh (backend, op->cal, op->id, op->cancellable);
192                 break;
193         case OP_GET_BACKEND_PROPERTY:
194                 e_cal_backend_get_backend_property (backend, op->cal, op->id, op->cancellable, op->d.prop_name);
195                 g_free (op->d.prop_name);
196                 break;
197         case OP_SET_BACKEND_PROPERTY:
198                 e_cal_backend_set_backend_property (backend, op->cal, op->id, op->cancellable, op->d.sbp.prop_name, op->d.sbp.prop_value);
199                 g_free (op->d.sbp.prop_name);
200                 g_free (op->d.sbp.prop_value);
201                 break;
202         case OP_GET_OBJECT:
203                 e_cal_backend_get_object (backend, op->cal, op->id, op->cancellable, op->d.ur.uid, op->d.ur.rid && *op->d.ur.rid ? op->d.ur.rid : NULL);
204                 g_free (op->d.ur.uid);
205                 g_free (op->d.ur.rid);
206                 break;
207         case OP_GET_OBJECT_LIST:
208                 e_cal_backend_get_object_list (backend, op->cal, op->id, op->cancellable, op->d.sexp);
209                 g_free (op->d.sexp);
210                 break;
211         case OP_GET_FREE_BUSY:
212                 e_cal_backend_get_free_busy (backend, op->cal, op->id, op->cancellable, op->d.fb.users, op->d.fb.start, op->d.fb.end);
213                 g_slist_free_full (op->d.fb.users, g_free);
214                 break;
215         case OP_CREATE_OBJECTS:
216                 e_cal_backend_create_objects (backend, op->cal, op->id, op->cancellable, op->d.calobjs);
217                 g_slist_free_full (op->d.calobjs, g_free);
218                 break;
219         case OP_MODIFY_OBJECTS:
220                 e_cal_backend_modify_objects (backend, op->cal, op->id, op->cancellable, op->d.mo.calobjs, op->d.mo.mod);
221                 g_slist_free_full (op->d.mo.calobjs, g_free);
222                 break;
223         case OP_REMOVE_OBJECTS:
224                 e_cal_backend_remove_objects (backend, op->cal, op->id, op->cancellable, op->d.ro.ids, op->d.ro.mod);
225                 g_slist_free_full (op->d.ro.ids, (GDestroyNotify) e_cal_component_free_id);
226                 break;
227         case OP_RECEIVE_OBJECTS:
228                 e_cal_backend_receive_objects (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
229                 g_free (op->d.co.calobj);
230                 break;
231         case OP_SEND_OBJECTS:
232                 e_cal_backend_send_objects (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
233                 g_free (op->d.co.calobj);
234                 break;
235         case OP_GET_ATTACHMENT_URIS:
236                 e_cal_backend_get_attachment_uris (backend, op->cal, op->id, op->cancellable, op->d.ur.uid, op->d.ur.rid && *op->d.ur.rid ? op->d.ur.rid : NULL);
237                 g_free (op->d.ur.uid);
238                 g_free (op->d.ur.rid);
239                 break;
240         case OP_DISCARD_ALARM:
241                 e_cal_backend_discard_alarm (backend, op->cal, op->id, op->cancellable, op->d.ura.uid, op->d.ura.rid && *op->d.ura.rid ? op->d.ura.rid : NULL, op->d.ura.auid);
242                 g_free (op->d.ura.uid);
243                 g_free (op->d.ura.rid);
244                 g_free (op->d.ura.auid);
245                 break;
246         case OP_GET_VIEW:
247                 if (op->d.sexp) {
248                         EDataCalView *view;
249                         ECalBackendSExp *obj_sexp;
250                         gchar *path;
251                         GError *error = NULL;
252
253                         /* we handle this entirely here, since it doesn't require any
254                          * backend involvement now that we have e_cal_view_start to
255                          * actually kick off the search. */
256
257                         obj_sexp = e_cal_backend_sexp_new (op->d.sexp);
258                         if (!obj_sexp) {
259                                 g_free (op->d.sexp);
260                                 e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (InvalidQuery), NULL);
261                                 break;
262                         }
263
264                         view = e_data_cal_view_new (backend, obj_sexp);
265                         g_object_unref (obj_sexp);
266                         if (!view) {
267                                 g_free (op->d.sexp);
268                                 e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (OtherError), NULL);
269                                 break;
270                         }
271
272                         path = construct_calview_path ();
273                         e_data_cal_view_register_gdbus_object (view, e_gdbus_cal_stub_get_connection (op->cal->priv->gdbus_object), path, &error);
274
275                         if (error) {
276                                 g_object_unref (view);
277                                 g_free (op->d.sexp);
278                                 e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR_EX (OtherError, error->message), NULL);
279                                 g_error_free (error);
280                                 g_free (path);
281
282                                 break;
283                         }
284
285                         e_cal_backend_add_view (backend, view);
286
287                         e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (Success), path);
288
289                         g_free (path);
290                 }
291                 g_free (op->d.sexp);
292                 break;
293         case OP_GET_TIMEZONE:
294                 e_cal_backend_get_timezone (backend, op->cal, op->id, op->cancellable, op->d.tzid);
295                 g_free (op->d.tzid);
296                 break;
297         case OP_ADD_TIMEZONE:
298                 e_cal_backend_add_timezone (backend, op->cal, op->id, op->cancellable, op->d.tzobject);
299                 g_free (op->d.tzobject);
300                 break;
301         case OP_CANCEL_OPERATION:
302                 g_static_rec_mutex_lock (&op->cal->priv->pending_ops_lock);
303
304                 if (g_hash_table_lookup (op->cal->priv->pending_ops, GUINT_TO_POINTER (op->d.opid))) {
305                         GCancellable *cancellable = g_hash_table_lookup (op->cal->priv->pending_ops, GUINT_TO_POINTER (op->d.opid));
306
307                         g_cancellable_cancel (cancellable);
308                 }
309
310                 g_static_rec_mutex_unlock (&op->cal->priv->pending_ops_lock);
311                 break;
312         case OP_CLOSE:
313                 /* close just cancels all pending ops and frees data cal */
314                 e_cal_backend_remove_client (backend, op->cal);
315         case OP_CANCEL_ALL:
316                 g_static_rec_mutex_lock (&op->cal->priv->pending_ops_lock);
317                 g_hash_table_foreach (op->cal->priv->pending_ops, cancel_ops_cb, NULL);
318                 g_static_rec_mutex_unlock (&op->cal->priv->pending_ops_lock);
319                 break;
320         }
321
322         g_object_unref (op->cal);
323         g_object_unref (op->cancellable);
324         g_slice_free (OperationData, op);
325 }
326
327 static OperationData *
328 op_new (OperationID op,
329         EDataCal *cal)
330 {
331         OperationData *data;
332
333         data = g_slice_new0 (OperationData);
334         data->op = op;
335         data->cal = g_object_ref (cal);
336         data->id = e_operation_pool_reserve_opid (ops_pool);
337         data->cancellable = g_cancellable_new ();
338
339         g_static_rec_mutex_lock (&cal->priv->pending_ops_lock);
340         g_hash_table_insert (cal->priv->pending_ops, GUINT_TO_POINTER (data->id), g_object_ref (data->cancellable));
341         g_static_rec_mutex_unlock (&cal->priv->pending_ops_lock);
342
343         return data;
344 }
345
346 static void
347 op_complete (EDataCal *cal,
348              guint32 opid)
349 {
350         g_return_if_fail (cal != NULL);
351
352         e_operation_pool_release_opid (ops_pool, opid);
353
354         g_static_rec_mutex_lock (&cal->priv->pending_ops_lock);
355         g_hash_table_remove (cal->priv->pending_ops, GUINT_TO_POINTER (opid));
356         g_static_rec_mutex_unlock (&cal->priv->pending_ops_lock);
357 }
358
359 /* Create the EDataCal error quark */
360 GQuark
361 e_data_cal_error_quark (void)
362 {
363         #define ERR_PREFIX "org.gnome.evolution.dataserver.Calendar."
364
365         static const GDBusErrorEntry entries[] = {
366                 { Success,                              ERR_PREFIX "Success" },
367                 { Busy,                                 ERR_PREFIX "Busy" },
368                 { RepositoryOffline,                    ERR_PREFIX "RepositoryOffline" },
369                 { PermissionDenied,                     ERR_PREFIX "PermissionDenied" },
370                 { InvalidRange,                         ERR_PREFIX "InvalidRange" },
371                 { ObjectNotFound,                       ERR_PREFIX "ObjectNotFound" },
372                 { InvalidObject,                        ERR_PREFIX "InvalidObject" },
373                 { ObjectIdAlreadyExists,                ERR_PREFIX "ObjectIdAlreadyExists" },
374                 { AuthenticationFailed,                 ERR_PREFIX "AuthenticationFailed" },
375                 { AuthenticationRequired,               ERR_PREFIX "AuthenticationRequired" },
376                 { UnsupportedField,                     ERR_PREFIX "UnsupportedField" },
377                 { UnsupportedMethod,                    ERR_PREFIX "UnsupportedMethod" },
378                 { UnsupportedAuthenticationMethod,      ERR_PREFIX "UnsupportedAuthenticationMethod" },
379                 { TLSNotAvailable,                      ERR_PREFIX "TLSNotAvailable" },
380                 { NoSuchCal,                            ERR_PREFIX "NoSuchCal" },
381                 { UnknownUser,                          ERR_PREFIX "UnknownUser" },
382                 { OfflineUnavailable,                   ERR_PREFIX "OfflineUnavailable" },
383                 { SearchSizeLimitExceeded,              ERR_PREFIX "SearchSizeLimitExceeded" },
384                 { SearchTimeLimitExceeded,              ERR_PREFIX "SearchTimeLimitExceeded" },
385                 { InvalidQuery,                         ERR_PREFIX "InvalidQuery" },
386                 { QueryRefused,                         ERR_PREFIX "QueryRefused" },
387                 { CouldNotCancel,                       ERR_PREFIX "CouldNotCancel" },
388                 { OtherError,                           ERR_PREFIX "OtherError" },
389                 { InvalidServerVersion,                 ERR_PREFIX "InvalidServerVersion" },
390                 { InvalidArg,                           ERR_PREFIX "InvalidArg" },
391                 { NotSupported,                         ERR_PREFIX "NotSupported" },
392                 { NotOpened,                            ERR_PREFIX "NotOpened" }
393         };
394
395         #undef ERR_PREFIX
396
397         static volatile gsize quark_volatile = 0;
398
399         g_dbus_error_register_error_domain ("e-data-cal-error", &quark_volatile, entries, G_N_ELEMENTS (entries));
400
401         return (GQuark) quark_volatile;
402 }
403
404 /**
405  * e_data_cal_status_to_string:
406  *
407  * Since: 2.32
408  **/
409 const gchar *
410 e_data_cal_status_to_string (EDataCalCallStatus status)
411 {
412         gint i;
413         static struct _statuses {
414                 EDataCalCallStatus status;
415                 const gchar *msg;
416         } statuses[] = {
417                 { Success,                              N_("Success") },
418                 { Busy,                                 N_("Backend is busy") },
419                 { RepositoryOffline,                    N_("Repository offline") },
420                 { PermissionDenied,                     N_("Permission denied") },
421                 { InvalidRange,                         N_("Invalid range") },
422                 { ObjectNotFound,                       N_("Object not found") },
423                 { InvalidObject,                        N_("Invalid object") },
424                 { ObjectIdAlreadyExists,                N_("Object ID already exists") },
425                 { AuthenticationFailed,                 N_("Authentication Failed") },
426                 { AuthenticationRequired,               N_("Authentication Required") },
427                 { UnsupportedField,                     N_("Unsupported field") },
428                 { UnsupportedMethod,                    N_("Unsupported method") },
429                 { UnsupportedAuthenticationMethod,      N_("Unsupported authentication method") },
430                 { TLSNotAvailable,                      N_("TLS not available") },
431                 { NoSuchCal,                            N_("Calendar does not exist") },
432                 { UnknownUser,                          N_("Unknown user") },
433                 { OfflineUnavailable,                   N_("Not available in offline mode") },
434                 { SearchSizeLimitExceeded,              N_("Search size limit exceeded") },
435                 { SearchTimeLimitExceeded,              N_("Search time limit exceeded") },
436                 { InvalidQuery,                         N_("Invalid query") },
437                 { QueryRefused,                         N_("Query refused") },
438                 { CouldNotCancel,                       N_("Could not cancel") },
439                 /* { OtherError,                        N_("Other error") }, */
440                 { InvalidServerVersion,                 N_("Invalid server version") },
441                 { InvalidArg,                           N_("Invalid argument") },
442                 /* Translators: The string for NOT_SUPPORTED error */
443                 { NotSupported,                         N_("Not supported") },
444                 { NotOpened,                            N_("Backend is not opened yet") }
445         };
446
447         for (i = 0; i < G_N_ELEMENTS (statuses); i++) {
448                 if (statuses[i].status == status)
449                         return _(statuses[i].msg);
450         }
451
452         return _("Other error");
453 }
454
455 /**
456  * e_data_cal_create_error:
457  * @status: #EDataCalStatus code
458  * @custom_msg: Custom message to use for the error. When NULL,
459  *              then uses a default message based on the @status code.
460  *
461  * Returns: NULL, when the @status is Success,
462  *          or a newly allocated GError, which should be freed
463  *          with g_error_free() call.
464  *
465  * Since: 2.32
466  **/
467 GError *
468 e_data_cal_create_error (EDataCalCallStatus status,
469                          const gchar *custom_msg)
470 {
471         if (status == Success)
472                 return NULL;
473
474         return g_error_new_literal (E_DATA_CAL_ERROR, status, custom_msg ? custom_msg : e_data_cal_status_to_string (status));
475 }
476
477 /**
478  * e_data_cal_create_error_fmt:
479  *
480  * Similar as e_data_cal_create_error(), only here, instead of custom_msg,
481  * is used a printf() format to create a custom_msg for the error.
482  *
483  * Since: 2.32
484  **/
485 GError *
486 e_data_cal_create_error_fmt (EDataCalCallStatus status,
487                              const gchar *custom_msg_fmt,
488                              ...)
489 {
490         GError *error;
491         gchar *custom_msg;
492         va_list ap;
493
494         if (!custom_msg_fmt)
495                 return e_data_cal_create_error (status, NULL);
496
497         va_start (ap, custom_msg_fmt);
498         custom_msg = g_strdup_vprintf (custom_msg_fmt, ap);
499         va_end (ap);
500
501         error = e_data_cal_create_error (status, custom_msg);
502
503         g_free (custom_msg);
504
505         return error;
506 }
507
508 /**
509  * e_data_cal_register_gdbus_object:
510  *
511  * Registers GDBus object of this EDataCal.
512  *
513  * Since: 2.32
514  **/
515 guint
516 e_data_cal_register_gdbus_object (EDataCal *cal,
517                                   GDBusConnection *connection,
518                                   const gchar *object_path,
519                                   GError **error)
520 {
521         g_return_val_if_fail (cal != NULL, 0);
522         g_return_val_if_fail (E_IS_DATA_CAL (cal), 0);
523         g_return_val_if_fail (connection != NULL, 0);
524         g_return_val_if_fail (object_path != NULL, 0);
525
526         return e_gdbus_cal_register_object (cal->priv->gdbus_object, connection, object_path, error);
527 }
528
529 static gboolean
530 impl_Cal_open (EGdbusCal *object,
531                GDBusMethodInvocation *invocation,
532                gboolean in_only_if_exists,
533                EDataCal *cal)
534 {
535         OperationData *op;
536
537         op = op_new (OP_OPEN, cal);
538         op->d.only_if_exists = in_only_if_exists;
539
540         e_gdbus_cal_complete_open (cal->priv->gdbus_object, invocation, op->id);
541         e_operation_pool_push (ops_pool, op);
542
543         return TRUE;
544 }
545
546 static gboolean
547 impl_Cal_remove (EGdbusCal *object,
548                  GDBusMethodInvocation *invocation,
549                  EDataCal *cal)
550 {
551         OperationData *op;
552
553         op = op_new (OP_REMOVE, cal);
554
555         e_gdbus_cal_complete_remove (cal->priv->gdbus_object, invocation, op->id);
556         e_operation_pool_push (ops_pool, op);
557
558         return TRUE;
559 }
560
561 static gboolean
562 impl_Cal_refresh (EGdbusCal *object,
563                   GDBusMethodInvocation *invocation,
564                   EDataCal *cal)
565 {
566         OperationData *op;
567
568         op = op_new (OP_REFRESH, cal);
569
570         e_gdbus_cal_complete_refresh (cal->priv->gdbus_object, invocation, op->id);
571         e_operation_pool_push (ops_pool, op);
572
573         return TRUE;
574 }
575
576 static gboolean
577 impl_Cal_get_backend_property (EGdbusCal *object,
578                                GDBusMethodInvocation *invocation,
579                                const gchar *in_prop_name,
580                                EDataCal *cal)
581 {
582         OperationData *op;
583
584         op = op_new (OP_GET_BACKEND_PROPERTY, cal);
585         op->d.prop_name = g_strdup (in_prop_name);
586
587         e_gdbus_cal_complete_get_backend_property (cal->priv->gdbus_object, invocation, op->id);
588         e_operation_pool_push (ops_pool, op);
589
590         return TRUE;
591 }
592
593 static gboolean
594 impl_Cal_set_backend_property (EGdbusCal *object,
595                                GDBusMethodInvocation *invocation,
596                                const gchar * const *in_prop_name_value,
597                                EDataCal *cal)
598 {
599         OperationData *op;
600
601         op = op_new (OP_SET_BACKEND_PROPERTY, cal);
602         g_return_val_if_fail (e_gdbus_cal_decode_set_backend_property (in_prop_name_value, &op->d.sbp.prop_name, &op->d.sbp.prop_value), FALSE);
603
604         e_gdbus_cal_complete_set_backend_property (cal->priv->gdbus_object, invocation, op->id);
605         e_operation_pool_push (ops_pool, op);
606
607         return TRUE;
608 }
609
610 static gboolean
611 impl_Cal_get_object (EGdbusCal *object,
612                      GDBusMethodInvocation *invocation,
613                      const gchar * const *in_uid_rid,
614                      EDataCal *cal)
615 {
616         OperationData *op;
617
618         op = op_new (OP_GET_OBJECT, cal);
619         g_return_val_if_fail (e_gdbus_cal_decode_get_object (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
620
621         e_gdbus_cal_complete_get_object (cal->priv->gdbus_object, invocation, op->id);
622         e_operation_pool_push (ops_pool, op);
623
624         return TRUE;
625 }
626
627 static gboolean
628 impl_Cal_get_object_list (EGdbusCal *object,
629                           GDBusMethodInvocation *invocation,
630                           const gchar *in_sexp,
631                           EDataCal *cal)
632 {
633         OperationData *op;
634
635         op = op_new (OP_GET_OBJECT_LIST, cal);
636         op->d.sexp = g_strdup (in_sexp);
637
638         e_gdbus_cal_complete_get_object_list (cal->priv->gdbus_object, invocation, op->id);
639         e_operation_pool_push (ops_pool, op);
640
641         return TRUE;
642 }
643
644 static gboolean
645 impl_Cal_get_free_busy (EGdbusCal *object,
646                         GDBusMethodInvocation *invocation,
647                         const gchar * const *in_start_end_userlist,
648                         EDataCal *cal)
649 {
650         OperationData *op;
651         guint start, end;
652
653         op = op_new (OP_GET_FREE_BUSY, cal);
654         g_return_val_if_fail (e_gdbus_cal_decode_get_free_busy (in_start_end_userlist, &start, &end, &op->d.fb.users), FALSE);
655
656         op->d.fb.start = (time_t) start;
657         op->d.fb.end = (time_t) end;
658
659         e_gdbus_cal_complete_get_free_busy (cal->priv->gdbus_object, invocation, op->id);
660         e_operation_pool_push (ops_pool, op);
661
662         return TRUE;
663 }
664
665 static gboolean
666 impl_Cal_create_objects (EGdbusCal *object,
667                          GDBusMethodInvocation *invocation,
668                          const gchar * const *in_calobjs,
669                          EDataCal *cal)
670 {
671         OperationData *op;
672
673         op = op_new (OP_CREATE_OBJECTS, cal);
674         op->d.calobjs = e_util_strv_to_slist (in_calobjs);
675
676         e_gdbus_cal_complete_create_objects (cal->priv->gdbus_object, invocation, op->id);
677         e_operation_pool_push (ops_pool, op);
678
679         return TRUE;
680 }
681
682 static gboolean
683 impl_Cal_modify_objects (EGdbusCal *object,
684                          GDBusMethodInvocation *invocation,
685                          const gchar * const *in_mod_calobjs,
686                          EDataCal *cal)
687 {
688         OperationData *op;
689         guint mod;
690
691         op = op_new (OP_MODIFY_OBJECTS, cal);
692         g_return_val_if_fail (e_gdbus_cal_decode_modify_objects (in_mod_calobjs, &op->d.mo.calobjs, &mod), FALSE);
693         op->d.mo.mod = mod;
694
695         e_gdbus_cal_complete_modify_objects (cal->priv->gdbus_object, invocation, op->id);
696         e_operation_pool_push (ops_pool, op);
697
698         return TRUE;
699 }
700
701 static gboolean
702 impl_Cal_remove_objects (EGdbusCal *object,
703                          GDBusMethodInvocation *invocation,
704                          const gchar * const *in_mod_ids,
705                          EDataCal *cal)
706 {
707         OperationData *op;
708         guint mod = 0;
709
710         op = op_new (OP_REMOVE_OBJECTS, cal);
711         g_return_val_if_fail (e_gdbus_cal_decode_remove_objects (in_mod_ids, &op->d.ro.ids, &mod), FALSE);
712         op->d.ro.mod = mod;
713
714         e_gdbus_cal_complete_remove_objects (cal->priv->gdbus_object, invocation, op->id);
715         e_operation_pool_push (ops_pool, op);
716
717         return TRUE;
718 }
719
720 static gboolean
721 impl_Cal_receive_objects (EGdbusCal *object,
722                           GDBusMethodInvocation *invocation,
723                           const gchar *in_calobj,
724                           EDataCal *cal)
725 {
726         OperationData *op;
727
728         op = op_new (OP_RECEIVE_OBJECTS, cal);
729         op->d.co.calobj = g_strdup (in_calobj);
730
731         e_gdbus_cal_complete_receive_objects (cal->priv->gdbus_object, invocation, op->id);
732         e_operation_pool_push (ops_pool, op);
733
734         return TRUE;
735 }
736
737 static gboolean
738 impl_Cal_send_objects (EGdbusCal *object,
739                        GDBusMethodInvocation *invocation,
740                        const gchar *in_calobj,
741                        EDataCal *cal)
742 {
743         OperationData *op;
744
745         op = op_new (OP_SEND_OBJECTS, cal);
746         op->d.co.calobj = g_strdup (in_calobj);
747
748         e_gdbus_cal_complete_send_objects (cal->priv->gdbus_object, invocation, op->id);
749         e_operation_pool_push (ops_pool, op);
750
751         return TRUE;
752 }
753
754 static gboolean
755 impl_Cal_get_attachment_uris (EGdbusCal *object,
756                               GDBusMethodInvocation *invocation,
757                               const gchar * const *in_uid_rid,
758                               EDataCal *cal)
759 {
760         OperationData *op;
761
762         op = op_new (OP_GET_ATTACHMENT_URIS, cal);
763         g_return_val_if_fail (e_gdbus_cal_decode_get_attachment_uris (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
764
765         e_gdbus_cal_complete_get_attachment_uris (cal->priv->gdbus_object, invocation, op->id);
766         e_operation_pool_push (ops_pool, op);
767
768         return TRUE;
769 }
770
771 static gboolean
772 impl_Cal_discard_alarm (EGdbusCal *object,
773                         GDBusMethodInvocation *invocation,
774                         const gchar * const *in_uid_rid_auid,
775                         EDataCal *cal)
776 {
777         OperationData *op;
778
779         op = op_new (OP_DISCARD_ALARM, cal);
780         g_return_val_if_fail (e_gdbus_cal_decode_discard_alarm (in_uid_rid_auid, &op->d.ura.uid, &op->d.ura.rid, &op->d.ura.auid), FALSE);
781
782         e_gdbus_cal_complete_discard_alarm (cal->priv->gdbus_object, invocation, op->id);
783         e_operation_pool_push (ops_pool, op);
784
785         return TRUE;
786 }
787
788 static gboolean
789 impl_Cal_get_view (EGdbusCal *object,
790                    GDBusMethodInvocation *invocation,
791                    const gchar *in_sexp,
792                    EDataCal *cal)
793 {
794         OperationData *op;
795
796         op = op_new (OP_GET_VIEW, cal);
797         op->d.sexp = g_strdup (in_sexp);
798
799         e_gdbus_cal_complete_get_view (cal->priv->gdbus_object, invocation, op->id);
800         e_operation_pool_push (ops_pool, op);
801
802         return TRUE;
803 }
804
805 static gboolean
806 impl_Cal_get_timezone (EGdbusCal *object,
807                        GDBusMethodInvocation *invocation,
808                        const gchar *in_tzid,
809                        EDataCal *cal)
810 {
811         OperationData *op;
812
813         op = op_new (OP_GET_TIMEZONE, cal);
814         op->d.tzid = g_strdup (in_tzid);
815
816         e_gdbus_cal_complete_get_timezone (cal->priv->gdbus_object, invocation, op->id);
817         e_operation_pool_push (ops_pool, op);
818
819         return TRUE;
820 }
821
822 static gboolean
823 impl_Cal_add_timezone (EGdbusCal *object,
824                        GDBusMethodInvocation *invocation,
825                        const gchar *in_tzobject,
826                        EDataCal *cal)
827 {
828         OperationData *op;
829
830         op = op_new (OP_ADD_TIMEZONE, cal);
831         op->d.tzobject = g_strdup (in_tzobject);
832
833         e_gdbus_cal_complete_add_timezone (cal->priv->gdbus_object, invocation, op->id);
834         e_operation_pool_push (ops_pool, op);
835
836         return TRUE;
837 }
838
839 static gboolean
840 impl_Cal_cancel_operation (EGdbusCal *object,
841                            GDBusMethodInvocation *invocation,
842                            guint in_opid,
843                            EDataCal *cal)
844 {
845         OperationData *op;
846
847         op = op_new (OP_CANCEL_OPERATION, cal);
848         op->d.opid = in_opid;
849
850         e_gdbus_cal_complete_cancel_operation (cal->priv->gdbus_object, invocation, NULL);
851         e_operation_pool_push (ops_pool, op);
852
853         return TRUE;
854 }
855
856 static gboolean
857 impl_Cal_cancel_all (EGdbusCal *object,
858                      GDBusMethodInvocation *invocation,
859                      EDataCal *cal)
860 {
861         OperationData *op;
862
863         op = op_new (OP_CANCEL_ALL, cal);
864
865         e_gdbus_cal_complete_cancel_all (cal->priv->gdbus_object, invocation, NULL);
866         e_operation_pool_push (ops_pool, op);
867
868         return TRUE;
869 }
870
871 static gboolean
872 impl_Cal_close (EGdbusCal *object,
873                 GDBusMethodInvocation *invocation,
874                 EDataCal *cal)
875 {
876         OperationData *op;
877
878         op = op_new (OP_CLOSE, cal);
879         /* unref here makes sure the cal is freed in a separate thread */
880         g_object_unref (cal);
881
882         e_gdbus_cal_complete_close (cal->priv->gdbus_object, invocation, NULL);
883         e_operation_pool_push (ops_pool, op);
884
885         return TRUE;
886 }
887
888 /* free returned pointer with g_strfreev() */
889 static gchar **
890 gslist_to_strv (const GSList *lst)
891 {
892         gchar **seq;
893         const GSList *l;
894         gint i;
895
896         seq = g_new0 (gchar *, g_slist_length ((GSList *) lst) + 1);
897         for (l = lst, i = 0; l; l = l->next, i++) {
898                 seq[i] = e_util_utf8_make_valid (l->data);
899         }
900
901         return seq;
902 }
903
904 /**
905  * e_data_cal_respond_open:
906  * @cal: A calendar client interface.
907  * @error: Operation error, if any, automatically freed if passed it.
908  *
909  * Notifies listeners of the completion of the open method call.
910  *
911  * Since: 3.2
912  */
913 void
914 e_data_cal_respond_open (EDataCal *cal,
915                          guint32 opid,
916                          GError *error)
917 {
918         op_complete (cal, opid);
919
920         /* Translators: This is prefix to a detailed error message */
921         g_prefix_error (&error, "%s", _("Cannot open calendar: "));
922
923         e_gdbus_cal_emit_open_done (cal->priv->gdbus_object, opid, error);
924
925         if (error)
926                 g_error_free (error);
927 }
928
929 /**
930  * e_data_cal_respond_remove:
931  * @cal: A calendar client interface.
932  * @error: Operation error, if any, automatically freed if passed it.
933  *
934  * Notifies listeners of the completion of the remove method call.
935  *
936  * Since: 3.2
937  */
938 void
939 e_data_cal_respond_remove (EDataCal *cal,
940                            guint32 opid,
941                            GError *error)
942 {
943         op_complete (cal, opid);
944
945         /* Translators: This is prefix to a detailed error message */
946         g_prefix_error (&error, "%s", _("Cannot remove calendar: "));
947
948         e_gdbus_cal_emit_remove_done (cal->priv->gdbus_object, opid, error);
949
950         if (error)
951                 g_error_free (error);
952         else
953                 e_cal_backend_set_is_removed (cal->priv->backend, TRUE);
954 }
955
956 /**
957  * e_data_cal_respond_refresh:
958  * @cal: A calendar client interface.
959  * @error: Operation error, if any, automatically freed if passed it.
960  *
961  * Notifies listeners of the completion of the refresh method call.
962  *
963  * Since: 3.2
964  */
965 void
966 e_data_cal_respond_refresh (EDataCal *cal,
967                             guint32 opid,
968                             GError *error)
969 {
970         op_complete (cal, opid);
971
972         /* Translators: This is prefix to a detailed error message */
973         g_prefix_error (&error, "%s", _("Cannot refresh calendar: "));
974
975         e_gdbus_cal_emit_refresh_done (cal->priv->gdbus_object, opid, error);
976
977         if (error)
978                 g_error_free (error);
979 }
980
981 /**
982  * e_data_cal_respond_get_backend_property:
983  * @cal: A calendar client interface.
984  * @error: Operation error, if any, automatically freed if passed it.
985  * @prop_value: Value of a property
986  *
987  * Notifies listeners of the completion of the get_backend_property method call.
988  *
989  * Since: 3.2
990  */
991 void
992 e_data_cal_respond_get_backend_property (EDataCal *cal,
993                                          guint32 opid,
994                                          GError *error,
995                                          const gchar *prop_value)
996 {
997         gchar *gdbus_prop_value = NULL;
998
999         op_complete (cal, opid);
1000
1001         /* Translators: This is prefix to a detailed error message */
1002         g_prefix_error (&error, "%s", _("Cannot retrieve backend property: "));
1003
1004         e_gdbus_cal_emit_get_backend_property_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (prop_value, &gdbus_prop_value));
1005
1006         g_free (gdbus_prop_value);
1007         if (error)
1008                 g_error_free (error);
1009 }
1010
1011 /**
1012  * e_data_cal_respond_set_backend_property:
1013  * @cal: A calendar client interface.
1014  * @error: Operation error, if any, automatically freed if passed it.
1015  *
1016  * Notifies listeners of the completion of the set_backend_property method call.
1017  *
1018  * Since: 3.2
1019  */
1020 void
1021 e_data_cal_respond_set_backend_property (EDataCal *cal,
1022                                          guint32 opid,
1023                                          GError *error)
1024 {
1025         op_complete (cal, opid);
1026
1027         /* Translators: This is prefix to a detailed error message */
1028         g_prefix_error (&error, "%s", _("Cannot set backend property: "));
1029
1030         e_gdbus_cal_emit_set_backend_property_done (cal->priv->gdbus_object, opid, error);
1031
1032         if (error)
1033                 g_error_free (error);
1034 }
1035
1036 /**
1037  * e_data_cal_respond_get_object:
1038  * @cal: A calendar client interface.
1039  * @error: Operation error, if any, automatically freed if passed it.
1040  * @object: The object retrieved as an iCalendar string.
1041  *
1042  * Notifies listeners of the completion of the get_object method call.
1043  *
1044  * Since: 3.2
1045  */
1046 void
1047 e_data_cal_respond_get_object (EDataCal *cal,
1048                                guint32 opid,
1049                                GError *error,
1050                                const gchar *object)
1051 {
1052         gchar *gdbus_object = NULL;
1053
1054         op_complete (cal, opid);
1055
1056         /* Translators: This is prefix to a detailed error message */
1057         g_prefix_error (&error, "%s", _("Cannot retrieve calendar object path: "));
1058
1059         e_gdbus_cal_emit_get_object_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (object, &gdbus_object));
1060
1061         g_free (gdbus_object);
1062         if (error)
1063                 g_error_free (error);
1064 }
1065
1066 /**
1067  * e_data_cal_respond_get_object_list:
1068  * @cal: A calendar client interface.
1069  * @error: Operation error, if any, automatically freed if passed it.
1070  * @objects: List of retrieved objects.
1071  *
1072  * Notifies listeners of the completion of the get_object_list method call.
1073  *
1074  * Since: 3.2
1075  */
1076 void
1077 e_data_cal_respond_get_object_list (EDataCal *cal,
1078                                     guint32 opid,
1079                                     GError *error,
1080                                     const GSList *objects)
1081 {
1082         gchar **strv_objects;
1083
1084         op_complete (cal, opid);
1085
1086         /* Translators: This is prefix to a detailed error message */
1087         g_prefix_error (&error, "%s", _("Cannot retrieve calendar object list: "));
1088
1089         strv_objects = gslist_to_strv (objects);
1090
1091         e_gdbus_cal_emit_get_object_list_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_objects);
1092
1093         g_strfreev (strv_objects);
1094         if (error)
1095                 g_error_free (error);
1096 }
1097
1098 /**
1099  * e_data_cal_respond_get_free_busy:
1100  * @cal: A calendar client interface.
1101  * @error: Operation error, if any, automatically freed if passed it.
1102  *
1103  * Notifies listeners of the completion of the get_free_busy method call.
1104  * To pass actual free/busy objects to the client use e_data_cal_report_free_busy_data().
1105  *
1106  * Since: 3.2
1107  */
1108 void
1109 e_data_cal_respond_get_free_busy (EDataCal *cal,
1110                                   guint32 opid,
1111                                   GError *error)
1112 {
1113         op_complete (cal, opid);
1114
1115         /* Translators: This is prefix to a detailed error message */
1116         g_prefix_error (&error, "%s", _("Cannot retrieve calendar free/busy list: "));
1117
1118         e_gdbus_cal_emit_get_free_busy_done (cal->priv->gdbus_object, opid, error);
1119
1120         if (error)
1121                 g_error_free (error);
1122 }
1123
1124 /**
1125  * e_data_cal_respond_create_objects:
1126  * @cal: A calendar client interface.
1127  * @error: Operation error, if any, automatically freed if passed it.
1128  * @uids: UIDs of the objects created.
1129  * @new_components: The newly created #ECalComponent objects.
1130  *
1131  * Notifies listeners of the completion of the create_objects method call.
1132  *
1133  * Since: 3.6
1134  */
1135 void
1136 e_data_cal_respond_create_objects (EDataCal *cal,
1137                                    guint32 opid,
1138                                    GError *error,
1139                                    const GSList *uids,
1140                                    /* const */ GSList *new_components)
1141 {
1142         gchar **array = NULL;
1143         const GSList *l;
1144         gint i = 0;
1145
1146         op_complete (cal, opid);
1147
1148         array = g_new0 (gchar *, g_slist_length ((GSList *) uids) + 1);
1149         for (l = uids; l != NULL; l = l->next) {
1150                 array[i++] = e_util_utf8_make_valid (l->data);
1151         }
1152
1153         /* Translators: This is prefix to a detailed error message */
1154         g_prefix_error (&error, "%s", _("Cannot create calendar object: "));
1155
1156         e_gdbus_cal_emit_create_objects_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) array);
1157
1158         g_strfreev (array);
1159         if (error)
1160                 g_error_free (error);
1161         else {
1162                 for (l = new_components; l; l = l->next) {
1163                         e_cal_backend_notify_component_created (cal->priv->backend, l->data);
1164                 }
1165         }
1166 }
1167
1168 /**
1169  * e_data_cal_respond_modify_objects:
1170  * @cal: A calendar client interface.
1171  * @error: Operation error, if any, automatically freed if passed it.
1172  * @old_components: The old #ECalComponents.
1173  * @new_components: The new #ECalComponents.
1174  *
1175  * Notifies listeners of the completion of the modify_objects method call.
1176  *
1177  * Since: 3.6
1178  */
1179 void
1180 e_data_cal_respond_modify_objects (EDataCal *cal,
1181                                    guint32 opid,
1182                                    GError *error,
1183                                    /* const */ GSList *old_components,
1184                                    /* const */ GSList *new_components)
1185 {
1186         op_complete (cal, opid);
1187
1188         /* Translators: This is prefix to a detailed error message */
1189         g_prefix_error (&error, "%s", _("Cannot modify calendar object: "));
1190
1191         e_gdbus_cal_emit_modify_objects_done (cal->priv->gdbus_object, opid, error);
1192
1193         if (error)
1194                 g_error_free (error);
1195         else {
1196                 const GSList *lold = old_components, *lnew = new_components;
1197                 while (lold && lnew) {
1198                         e_cal_backend_notify_component_modified (cal->priv->backend, lold->data, lnew->data);
1199                         lold = lold->next;
1200                         lnew = lnew->next;
1201                 }
1202         }
1203 }
1204
1205 /**
1206  * e_data_cal_respond_remove_objects:
1207  * @cal: A calendar client interface.
1208  * @error: Operation error, if any, automatically freed if passed it.
1209  * @ids: IDs of the removed objects.
1210  * @old_components: The old #ECalComponents.
1211  * @new_components: The new #ECalComponents. They will not be NULL only
1212  * when removing instances of recurring appointments.
1213  *
1214  * Notifies listeners of the completion of the remove_objects method call.
1215  *
1216  * Since: 3.6
1217  */
1218 void
1219 e_data_cal_respond_remove_objects (EDataCal *cal,
1220                                   guint32 opid,
1221                                   GError *error,
1222                                   const GSList *ids,
1223                                   /* const */ GSList *old_components,
1224                                   /* const */ GSList *new_components)
1225 {
1226         op_complete (cal, opid);
1227
1228         /* Translators: This is prefix to a detailed error message */
1229         g_prefix_error (&error, "%s", _("Cannot remove calendar object: "));
1230
1231         e_gdbus_cal_emit_remove_objects_done (cal->priv->gdbus_object, opid, error);
1232
1233         if (error)
1234                 g_error_free (error);
1235         else {
1236                 const GSList *lid = ids, *lold = old_components, *lnew = new_components;
1237                 while (lid && lold) {
1238                         e_cal_backend_notify_component_removed (cal->priv->backend, lid->data, lold->data, lnew ? lnew->data : NULL);
1239
1240                         lid = lid->next;
1241                         lold = lold->next;
1242
1243                         if (lnew)
1244                                 lnew = lnew->next;
1245                 }
1246         }
1247 }
1248
1249 /**
1250  * e_data_cal_respond_receive_objects:
1251  * @cal: A calendar client interface.
1252  * @error: Operation error, if any, automatically freed if passed it.
1253  *
1254  * Notifies listeners of the completion of the receive_objects method call.
1255  *
1256  * Since: 3.2
1257  */
1258 void
1259 e_data_cal_respond_receive_objects (EDataCal *cal,
1260                                     guint32 opid,
1261                                     GError *error)
1262 {
1263         op_complete (cal, opid);
1264
1265         /* Translators: This is prefix to a detailed error message */
1266         g_prefix_error (&error, "%s", _("Cannot receive calendar objects: "));
1267
1268         e_gdbus_cal_emit_receive_objects_done (cal->priv->gdbus_object, opid, error);
1269
1270         if (error)
1271                 g_error_free (error);
1272 }
1273
1274 /**
1275  * e_data_cal_respond_send_objects:
1276  * @cal: A calendar client interface.
1277  * @error: Operation error, if any, automatically freed if passed it.
1278  * @users: List of users.
1279  * @calobj: An iCalendar string representing the object sent.
1280  *
1281  * Notifies listeners of the completion of the send_objects method call.
1282  *
1283  * Since: 3.2
1284  */
1285 void
1286 e_data_cal_respond_send_objects (EDataCal *cal,
1287                                  guint32 opid,
1288                                  GError *error,
1289                                  const GSList *users,
1290                                  const gchar *calobj)
1291 {
1292         gchar **strv_users_calobj;
1293
1294         op_complete (cal, opid);
1295
1296         /* Translators: This is prefix to a detailed error message */
1297         g_prefix_error (&error, "%s", _("Cannot send calendar objects: "));
1298
1299         strv_users_calobj = e_gdbus_cal_encode_send_objects (calobj, users);
1300
1301         e_gdbus_cal_emit_send_objects_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_users_calobj);
1302
1303         g_strfreev (strv_users_calobj);
1304         if (error)
1305                 g_error_free (error);
1306 }
1307
1308 /**
1309  * e_data_cal_respond_get_attachment_uris:
1310  * @cal: A calendar client interface.
1311  * @error: Operation error, if any, automatically freed if passed it.
1312  * @attachment_uris: List of retrieved attachment uri's.
1313  *
1314  * Notifies listeners of the completion of the get_attachment_uris method call.
1315  *
1316  * Since: 3.2
1317  **/
1318 void
1319 e_data_cal_respond_get_attachment_uris (EDataCal *cal,
1320                                         guint32 opid,
1321                                         GError *error,
1322                                         const GSList *attachment_uris)
1323 {
1324         gchar **strv_attachment_uris;
1325
1326         op_complete (cal, opid);
1327
1328         /* Translators: This is prefix to a detailed error message */
1329         g_prefix_error (&error, "%s", _("Could not retrieve attachment uris: "));
1330
1331         strv_attachment_uris = gslist_to_strv (attachment_uris);
1332
1333         e_gdbus_cal_emit_get_attachment_uris_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_attachment_uris);
1334
1335         g_strfreev (strv_attachment_uris);
1336         if (error)
1337                 g_error_free (error);
1338 }
1339
1340 /**
1341  * e_data_cal_respond_discard_alarm:
1342  * @cal: A calendar client interface.
1343  * @error: Operation error, if any, automatically freed if passed it.
1344  *
1345  * Notifies listeners of the completion of the discard_alarm method call.
1346  *
1347  * Since: 3.2
1348  **/
1349 void
1350 e_data_cal_respond_discard_alarm (EDataCal *cal,
1351                                   guint32 opid,
1352                                   GError *error)
1353 {
1354         op_complete (cal, opid);
1355
1356         /* Translators: This is prefix to a detailed error message */
1357         g_prefix_error (&error, "%s", _("Could not discard reminder: "));
1358
1359         e_gdbus_cal_emit_discard_alarm_done (cal->priv->gdbus_object, opid, error);
1360
1361         if (error)
1362                 g_error_free (error);
1363 }
1364
1365 /**
1366  * e_data_cal_respond_get_view:
1367  * @cal: A calendar client interface.
1368  * @error: Operation error, if any, automatically freed if passed it.
1369  * @view_path: The new live view path.
1370  *
1371  * Notifies listeners of the completion of the get_view method call.
1372  *
1373  * Since: 3.2
1374  */
1375 void
1376 e_data_cal_respond_get_view (EDataCal *cal,
1377                              guint32 opid,
1378                              GError *error,
1379                              const gchar *view_path)
1380 {
1381         gchar *gdbus_view_path = NULL;
1382
1383         op_complete (cal, opid);
1384
1385         /* Translators: This is prefix to a detailed error message */
1386         g_prefix_error (&error, "%s", _("Could not get calendar view path: "));
1387
1388         e_gdbus_cal_emit_get_view_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (view_path, &gdbus_view_path));
1389
1390         g_free (gdbus_view_path);
1391         if (error)
1392                 g_error_free (error);
1393 }
1394
1395 /**
1396  * e_data_cal_respond_get_timezone:
1397  * @cal: A calendar client interface.
1398  * @error: Operation error, if any, automatically freed if passed it.
1399  * @tzobject: The requested timezone as an iCalendar string.
1400  *
1401  * Notifies listeners of the completion of the get_timezone method call.
1402  *
1403  * Since: 3.2
1404  */
1405 void
1406 e_data_cal_respond_get_timezone (EDataCal *cal,
1407                                  guint32 opid,
1408                                  GError *error,
1409                                  const gchar *tzobject)
1410 {
1411         gchar *gdbus_tzobject = NULL;
1412
1413         op_complete (cal, opid);
1414
1415         /* Translators: This is prefix to a detailed error message */
1416         g_prefix_error (&error, "%s", _("Could not retrieve calendar time zone: "));
1417
1418         e_gdbus_cal_emit_get_timezone_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (tzobject, &gdbus_tzobject));
1419
1420         g_free (gdbus_tzobject);
1421         if (error)
1422                 g_error_free (error);
1423 }
1424
1425 /**
1426  * e_data_cal_respond_add_timezone:
1427  * @cal: A calendar client interface.
1428  * @error: Operation error, if any, automatically freed if passed it.
1429  *
1430  * Notifies listeners of the completion of the add_timezone method call.
1431  *
1432  * Since: 3.2
1433  */
1434 void
1435 e_data_cal_respond_add_timezone (EDataCal *cal,
1436                                  guint32 opid,
1437                                  GError *error)
1438 {
1439         op_complete (cal, opid);
1440
1441         /* Translators: This is prefix to a detailed error message */
1442         g_prefix_error (&error, "%s", _("Could not add calendar time zone: "));
1443
1444         e_gdbus_cal_emit_add_timezone_done (cal->priv->gdbus_object, opid, error);
1445
1446         if (error)
1447                 g_error_free (error);
1448 }
1449
1450 /**
1451  * e_data_cal_report_error:
1452  *
1453  * FIXME: Document me.
1454  *
1455  * Since: 3.2
1456  **/
1457 void
1458 e_data_cal_report_error (EDataCal *cal,
1459                          const gchar *message)
1460 {
1461         g_return_if_fail (cal != NULL);
1462         g_return_if_fail (message != NULL);
1463
1464         e_gdbus_cal_emit_backend_error (cal->priv->gdbus_object, message);
1465 }
1466
1467 /**
1468  * e_data_cal_report_readonly:
1469  *
1470  * FIXME: Document me.
1471  *
1472  * Since: 3.2
1473  **/
1474 void
1475 e_data_cal_report_readonly (EDataCal *cal,
1476                             gboolean readonly)
1477 {
1478         g_return_if_fail (cal != NULL);
1479
1480         e_gdbus_cal_emit_readonly (cal->priv->gdbus_object, readonly);
1481 }
1482
1483 /**
1484  * e_data_cal_report_online:
1485  *
1486  * FIXME: Document me.
1487  *
1488  * Since: 3.2
1489  **/
1490 void
1491 e_data_cal_report_online (EDataCal *cal,
1492                           gboolean is_online)
1493 {
1494         g_return_if_fail (cal != NULL);
1495
1496         e_gdbus_cal_emit_online (cal->priv->gdbus_object, is_online);
1497 }
1498
1499 /**
1500  * e_data_cal_report_opened:
1501  *
1502  * Reports to associated client that opening phase of the cal is finished.
1503  * error being NULL means successfully, otherwise reports an error which
1504  * happened during opening phase. By opening phase is meant a process
1505  * including successfull authentication to the server/storage.
1506  *
1507  * Since: 3.2
1508  **/
1509 void
1510 e_data_cal_report_opened (EDataCal *cal,
1511                           const GError *error)
1512 {
1513         gchar **strv_error;
1514
1515         strv_error = e_gdbus_templates_encode_error (error);
1516
1517         e_gdbus_cal_emit_opened (cal->priv->gdbus_object, (const gchar * const *) strv_error);
1518
1519         g_strfreev (strv_error);
1520 }
1521
1522 /**
1523  * e_data_cal_report_free_busy_data:
1524  *
1525  * FIXME: Document me.
1526  *
1527  * Since: 3.2
1528  **/
1529 void
1530 e_data_cal_report_free_busy_data (EDataCal *cal,
1531                                   const GSList *freebusy)
1532 {
1533         gchar **strv_freebusy;
1534
1535         g_return_if_fail (cal != NULL);
1536
1537         strv_freebusy = gslist_to_strv (freebusy);
1538
1539         e_gdbus_cal_emit_free_busy_data (cal->priv->gdbus_object, (const gchar * const *) strv_freebusy);
1540
1541         g_strfreev (strv_freebusy);
1542 }
1543
1544 /**
1545  * e_data_cal_report_backend_property_changed:
1546  *
1547  * Notifies client about certain property value change 
1548  *
1549  * Since: 3.2
1550  **/
1551 void
1552 e_data_cal_report_backend_property_changed (EDataCal *cal,
1553                                             const gchar *prop_name,
1554                                             const gchar *prop_value)
1555 {
1556         gchar **strv;
1557
1558         g_return_if_fail (cal != NULL);
1559         g_return_if_fail (prop_name != NULL);
1560         g_return_if_fail (*prop_name != '\0');
1561         g_return_if_fail (prop_value != NULL);
1562
1563         strv = e_gdbus_templates_encode_two_strings (prop_name, prop_value);
1564         g_return_if_fail (strv != NULL);
1565
1566         e_gdbus_cal_emit_backend_property_changed (cal->priv->gdbus_object, (const gchar * const *) strv);
1567
1568         g_strfreev (strv);
1569 }
1570
1571 static void
1572 data_cal_set_backend (EDataCal *cal,
1573                       ECalBackend *backend)
1574 {
1575         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1576         g_return_if_fail (cal->priv->backend == NULL);
1577
1578         cal->priv->backend = g_object_ref (backend);
1579 }
1580
1581 static void
1582 data_cal_set_property (GObject *object,
1583                        guint property_id,
1584                        const GValue *value,
1585                        GParamSpec *pspec)
1586 {
1587         switch (property_id) {
1588                 case PROP_BACKEND:
1589                         data_cal_set_backend (
1590                                 E_DATA_CAL (object),
1591                                 g_value_get_object (value));
1592                         return;
1593         }
1594
1595         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1596 }
1597
1598 static void
1599 data_cal_get_property (GObject *object,
1600                        guint property_id,
1601                        GValue *value,
1602                        GParamSpec *pspec)
1603 {
1604         switch (property_id) {
1605                 case PROP_BACKEND:
1606                         g_value_set_object (
1607                                 value,
1608                                 e_data_cal_get_backend (
1609                                 E_DATA_CAL (object)));
1610                         return;
1611         }
1612
1613         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1614 }
1615
1616 static void
1617 data_cal_dispose (GObject *object)
1618 {
1619         EDataCalPrivate *priv;
1620
1621         priv = E_DATA_CAL_GET_PRIVATE (object);
1622
1623         if (priv->backend) {
1624                 g_object_unref (priv->backend);
1625                 priv->backend = NULL;
1626         }
1627
1628         /* Chain up to parent's dispose() method. */
1629         G_OBJECT_CLASS (e_data_cal_parent_class)->dispose (object);
1630 }
1631
1632 static void
1633 data_cal_finalize (GObject *object)
1634 {
1635         EDataCalPrivate *priv;
1636
1637         priv = E_DATA_CAL_GET_PRIVATE (object);
1638
1639         if (priv->pending_ops) {
1640                 g_hash_table_destroy (priv->pending_ops);
1641                 priv->pending_ops = NULL;
1642         }
1643
1644         g_static_rec_mutex_free (&priv->pending_ops_lock);
1645
1646         if (priv->gdbus_object) {
1647                 g_object_unref (priv->gdbus_object);
1648                 priv->gdbus_object = NULL;
1649         }
1650
1651         /* Chain up to parent's finalize() method. */
1652         G_OBJECT_CLASS (e_data_cal_parent_class)->finalize (object);
1653 }
1654
1655 static void
1656 e_data_cal_class_init (EDataCalClass *class)
1657 {
1658         GObjectClass *object_class;
1659
1660         g_type_class_add_private (class, sizeof (EDataCalPrivate));
1661
1662         object_class = G_OBJECT_CLASS (class);
1663         object_class->set_property = data_cal_set_property;
1664         object_class->get_property = data_cal_get_property;
1665         object_class->dispose = data_cal_dispose;
1666         object_class->finalize = data_cal_finalize;
1667
1668         g_object_class_install_property (
1669                 object_class,
1670                 PROP_BACKEND,
1671                 g_param_spec_object (
1672                         "backend",
1673                         "Backend",
1674                         "The backend driving this connection",
1675                         E_TYPE_CAL_BACKEND,
1676                         G_PARAM_READWRITE |
1677                         G_PARAM_CONSTRUCT_ONLY |
1678                         G_PARAM_STATIC_STRINGS));
1679
1680         if (!ops_pool)
1681                 ops_pool = e_operation_pool_new (10, operation_thread, NULL);
1682 }
1683
1684 static void
1685 e_data_cal_init (EDataCal *ecal)
1686 {
1687         EGdbusCal *gdbus_object;
1688
1689         ecal->priv = E_DATA_CAL_GET_PRIVATE (ecal);
1690
1691         ecal->priv->gdbus_object = e_gdbus_cal_stub_new ();
1692         ecal->priv->pending_ops = g_hash_table_new_full (
1693                 g_direct_hash, g_direct_equal, NULL, g_object_unref);
1694         g_static_rec_mutex_init (&ecal->priv->pending_ops_lock);
1695
1696         gdbus_object = ecal->priv->gdbus_object;
1697         g_signal_connect (
1698                 gdbus_object, "handle-open",
1699                 G_CALLBACK (impl_Cal_open), ecal);
1700         g_signal_connect (
1701                 gdbus_object, "handle-remove",
1702                 G_CALLBACK (impl_Cal_remove), ecal);
1703         g_signal_connect (
1704                 gdbus_object, "handle-refresh",
1705                 G_CALLBACK (impl_Cal_refresh), ecal);
1706         g_signal_connect (
1707                 gdbus_object, "handle-get-backend-property",
1708                 G_CALLBACK (impl_Cal_get_backend_property), ecal);
1709         g_signal_connect (
1710                 gdbus_object, "handle-set-backend-property",
1711                 G_CALLBACK (impl_Cal_set_backend_property), ecal);
1712         g_signal_connect (
1713                 gdbus_object, "handle-get-object",
1714                 G_CALLBACK (impl_Cal_get_object), ecal);
1715         g_signal_connect (
1716                 gdbus_object, "handle-get-object-list",
1717                 G_CALLBACK (impl_Cal_get_object_list), ecal);
1718         g_signal_connect (
1719                 gdbus_object, "handle-get-free-busy",
1720                 G_CALLBACK (impl_Cal_get_free_busy), ecal);
1721         g_signal_connect (
1722                 gdbus_object, "handle-create-objects",
1723                 G_CALLBACK (impl_Cal_create_objects), ecal);
1724         g_signal_connect (
1725                 gdbus_object, "handle-modify-objects",
1726                 G_CALLBACK (impl_Cal_modify_objects), ecal);
1727         g_signal_connect (
1728                 gdbus_object, "handle-remove-objects",
1729                 G_CALLBACK (impl_Cal_remove_objects), ecal);
1730         g_signal_connect (
1731                 gdbus_object, "handle-receive-objects",
1732                 G_CALLBACK (impl_Cal_receive_objects), ecal);
1733         g_signal_connect (
1734                 gdbus_object, "handle-send-objects",
1735                 G_CALLBACK (impl_Cal_send_objects), ecal);
1736         g_signal_connect (
1737                 gdbus_object, "handle-get-attachment-uris",
1738                 G_CALLBACK (impl_Cal_get_attachment_uris), ecal);
1739         g_signal_connect (
1740                 gdbus_object, "handle-discard-alarm",
1741                 G_CALLBACK (impl_Cal_discard_alarm), ecal);
1742         g_signal_connect (
1743                 gdbus_object, "handle-get-view",
1744                 G_CALLBACK (impl_Cal_get_view), ecal);
1745         g_signal_connect (
1746                 gdbus_object, "handle-get-timezone",
1747                 G_CALLBACK (impl_Cal_get_timezone), ecal);
1748         g_signal_connect (
1749                 gdbus_object, "handle-add-timezone",
1750                 G_CALLBACK (impl_Cal_add_timezone), ecal);
1751         g_signal_connect (
1752                 gdbus_object, "handle-cancel-operation",
1753                 G_CALLBACK (impl_Cal_cancel_operation), ecal);
1754         g_signal_connect (
1755                 gdbus_object, "handle-cancel-all",
1756                 G_CALLBACK (impl_Cal_cancel_all), ecal);
1757         g_signal_connect (
1758                 gdbus_object, "handle-close",
1759                 G_CALLBACK (impl_Cal_close), ecal);
1760 }
1761
1762 EDataCal *
1763 e_data_cal_new (ECalBackend *backend)
1764 {
1765         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1766
1767         return g_object_new (E_TYPE_DATA_CAL, "backend", backend, NULL);
1768 }
1769
1770 ECalBackend *
1771 e_data_cal_get_backend (EDataCal *cal)
1772 {
1773         g_return_val_if_fail (E_IS_DATA_CAL (cal), NULL);
1774
1775         return cal->priv->backend;
1776 }
1777