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