Whitespace cleanups.
[platform/upstream/evolution-data-server.git] / calendar / libedata-cal / e-cal-backend-sync.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Author:
4  *   Chris Toshok (toshok@ximian.com)
5  *
6  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7  */
8
9 #ifdef CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include "e-cal-backend-sync.h"
14 #include "libedataserver/e-data-server-util.h"
15 #include <libical/icaltz-util.h>
16
17 #define E_CAL_BACKEND_SYNC_GET_PRIVATE(obj) \
18         (G_TYPE_INSTANCE_GET_PRIVATE \
19         ((obj), E_TYPE_CAL_BACKEND_SYNC, ECalBackendSyncPrivate))
20
21 G_DEFINE_TYPE (ECalBackendSync, e_cal_backend_sync, E_TYPE_CAL_BACKEND)
22
23 struct _ECalBackendSyncPrivate {
24         GMutex *sync_mutex;
25
26         gboolean mutex_lock;
27 };
28
29 #define LOCK_WRAPPER(func, args) G_STMT_START {                                                                 \
30         gboolean locked = backend->priv->mutex_lock;                                                            \
31         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func, NotSupported);           \
32         if (locked)                                                                                             \
33                 g_mutex_lock (backend->priv->sync_mutex);                                                       \
34         (* E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func) args;                                                  \
35         if (locked)                                                                                             \
36                 g_mutex_unlock (backend->priv->sync_mutex);                                                     \
37         } G_STMT_END
38
39 #define LOCK_WRAPPER_RET_VAL(func, args) G_STMT_START {                                                         \
40         gboolean locked = backend->priv->mutex_lock;                                                            \
41         e_return_data_cal_error_val_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func, NotSupported);       \
42         if (locked)                                                                                             \
43                 g_mutex_lock (backend->priv->sync_mutex);                                                       \
44         res = (* E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func) args;                                            \
45         if (locked)                                                                                             \
46                 g_mutex_unlock (backend->priv->sync_mutex);                                                     \
47         } G_STMT_END
48
49 /**
50  * e_cal_backend_sync_set_lock:
51  * @backend: An ECalBackendSync object.
52  * @lock: Lock mode.
53  *
54  * Sets the lock mode on the ECalBackendSync object. If TRUE, the backend
55  * will create a locking mutex for every operation, so that only one can
56  * happen at a time. If FALSE, no lock would be done and many operations
57  * can happen at the same time.
58  */
59 void
60 e_cal_backend_sync_set_lock (ECalBackendSync *backend,
61                              gboolean lock)
62 {
63         g_return_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend));
64
65         backend->priv->mutex_lock = lock;
66 }
67
68 /**
69  * e_cal_backend_sync_open:
70  * @backend: An ECalBackendSync object.
71  * @cal: An EDataCal object.
72  * @cancellable: a #GCancellable for the operation
73  * @only_if_exists: Whether to open the calendar if and only if it already exists
74  * or just create it when it does not exist.
75  * @error: Out parameter for a #GError.
76  *
77  * Calls the open_sync method on the given backend.
78  */
79 void
80 e_cal_backend_sync_open (ECalBackendSync *backend,
81                          EDataCal *cal,
82                          GCancellable *cancellable,
83                          gboolean only_if_exists,
84                          GError **error)
85 {
86         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
87
88         LOCK_WRAPPER (open_sync, (backend, cal, cancellable, only_if_exists, error));
89 }
90
91 /**
92  * e_cal_backend_sync_authenticate_user:
93  * @backend: an #ECalBackendSync
94  * @cancellable: a #GCancellable for the operation
95  * @credentials: an #ECredentials to authenticate with
96  * @error: #GError to set, when something fails
97  *
98  * Authenticates @backend with given @credentials.
99  *
100  * Since: 3.2
101  **/
102 void
103 e_cal_backend_sync_authenticate_user (ECalBackendSync *backend,
104                                       GCancellable *cancellable,
105                                       ECredentials *credentials,
106                                       GError **error)
107 {
108         e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
109         e_return_data_cal_error_if_fail (credentials, InvalidArg);
110
111         LOCK_WRAPPER (authenticate_user_sync, (backend, cancellable, credentials, error));
112 }
113
114 /**
115  * e_cal_backend_sync_remove:
116  * @backend: An ECalBackendSync object.
117  * @cal: An EDataCal object.
118  * @cancellable: a #GCancellable for the operation
119  * @error: Out parameter for a #GError.
120  *
121  * Calls the remove_sync method on the given backend.
122  */
123 void
124 e_cal_backend_sync_remove (ECalBackendSync *backend,
125                            EDataCal *cal,
126                            GCancellable *cancellable,
127                            GError **error)
128 {
129         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
130
131         LOCK_WRAPPER (remove_sync, (backend, cal, cancellable, error));
132 }
133
134 /**
135  * e_cal_backend_sync_refresh:
136  * @backend: An ECalBackendSync object.
137  * @cal: An EDataCal object.
138  * @cancellable: a #GCancellable for the operation
139  * @error: Out parameter for a #GError.
140  *
141  * Calls the refresh_sync method on the given backend.
142  *
143  * Since: 2.30
144  */
145 void
146 e_cal_backend_sync_refresh (ECalBackendSync *backend,
147                             EDataCal *cal,
148                             GCancellable *cancellable,
149                             GError **error)
150 {
151         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
152         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->refresh_sync != NULL, UnsupportedMethod);
153
154         LOCK_WRAPPER (refresh_sync, (backend, cal, cancellable, error));
155 }
156
157 /**
158  * e_cal_backend_sync_get_backend_property:
159  * @backend: An ECalBackendSync object.
160  * @cal: An EDataCal object.
161  * @cancellable: a #GCancellable for the operation
162  * @prop_name: Property name whose value to retrieve.
163  * @prop_value: Return value of the @prop_name.
164  * @error: Out parameter for a #GError.
165  *
166  * Calls the get_backend_property_sync method on the given backend.
167  *
168  * Returns whether processed this property. Returning FALSE means to pass
169  * the call to the ECalBackend parent class, thus neither @error should be
170  * set in this case.
171  *
172  * Since: 3.2
173  **/
174 gboolean
175 e_cal_backend_sync_get_backend_property (ECalBackendSync *backend,
176                                          EDataCal *cal,
177                                          GCancellable *cancellable,
178                                          const gchar *prop_name,
179                                          gchar **prop_value,
180                                          GError **error)
181 {
182         gboolean res = FALSE;
183
184         e_return_data_cal_error_val_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
185         e_return_data_cal_error_val_if_fail (prop_name, InvalidArg);
186         e_return_data_cal_error_val_if_fail (prop_value, InvalidArg);
187
188         LOCK_WRAPPER_RET_VAL (get_backend_property_sync, (backend, cal, cancellable, prop_name, prop_value, error));
189
190         return res;
191 }
192
193 /**
194  * e_cal_backend_sync_set_backend_property:
195  * @backend: An ECalBackendSync object.
196  * @cal: An EDataCal object.
197  * @cancellable: a #GCancellable for the operation
198  * @prop_name: Property name to set.
199  * @prop_value: New value of the @prop_name.
200  * @error: Out parameter for a #GError.
201  *
202  * Calls the set_backend_property_sync method on the given backend.
203  *
204  * Returns whether processed this property. Returning FALSE means to pass
205  * the call to the ECalBackend parent class, thus neither @error should be
206  * set in this case.
207  *
208  * Since: 3.2
209  **/
210 gboolean
211 e_cal_backend_sync_set_backend_property (ECalBackendSync *backend,
212                                          EDataCal *cal,
213                                          GCancellable *cancellable,
214                                          const gchar *prop_name,
215                                          const gchar *prop_value,
216                                          GError **error)
217 {
218         gboolean res = FALSE;
219
220         e_return_data_cal_error_val_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
221         e_return_data_cal_error_val_if_fail (prop_name, InvalidArg);
222         e_return_data_cal_error_val_if_fail (prop_value, InvalidArg);
223
224         LOCK_WRAPPER_RET_VAL (set_backend_property_sync, (backend, cal, cancellable, prop_name, prop_value, error));
225
226         return res;
227 }
228
229 /**
230  * e_cal_backend_sync_get_object:
231  * @backend: An ECalBackendSync object.
232  * @cal: An EDataCal object.
233  * @cancellable: a #GCancellable for the operation
234  * @uid: UID of the object to get.
235  * @rid: Recurrence ID of the specific instance to get, or NULL if getting the
236  * master object.
237  * @calobj: Placeholder for returned object.
238  * @error: Out parameter for a #GError.
239  *
240  * Calls the get_object_sync method on the given backend.
241  */
242 void
243 e_cal_backend_sync_get_object (ECalBackendSync *backend,
244                                EDataCal *cal,
245                                GCancellable *cancellable,
246                                const gchar *uid,
247                                const gchar *rid,
248                                gchar **calobj,
249                                GError **error)
250 {
251         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
252         e_return_data_cal_error_if_fail (calobj, InvalidArg);
253
254         LOCK_WRAPPER (get_object_sync, (backend, cal, cancellable, uid, rid, calobj, error));
255 }
256
257 /**
258  * e_cal_backend_sync_get_object_list:
259  * @backend: An ECalBackendSync object.
260  * @cal: An EDataCal object.
261  * @cancellable: a #GCancellable for the operation
262  * @sexp: Search query.
263  * @calobjs: Placeholder for list of returned objects.
264  * @error: Out parameter for a #GError.
265  *
266  * Calls the get_object_list_sync method on the given backend.
267  */
268 void
269 e_cal_backend_sync_get_object_list (ECalBackendSync *backend,
270                                     EDataCal *cal,
271                                     GCancellable *cancellable,
272                                     const gchar *sexp,
273                                     GSList **calobjs,
274                                     GError **error)
275 {
276         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
277         e_return_data_cal_error_if_fail (calobjs, InvalidArg);
278
279         LOCK_WRAPPER (get_object_list_sync, (backend, cal, cancellable, sexp, calobjs, error));
280 }
281
282 /**
283  * e_cal_backend_sync_get_free_busy:
284  * @backend: An ECalBackendSync object.
285  * @cal: An EDataCal object.
286  * @cancellable: a #GCancellable for the operation
287  * @users: List of users to get F/B info from.
288  * @start: Time range start.
289  * @end: Time range end.
290  * @freebusyobjects: Placeholder for F/B information.
291  * @error: Out parameter for a #GError.
292  *
293  * Calls the get_free_busy_sync method on the given backend.
294  */
295 void
296 e_cal_backend_sync_get_free_busy (ECalBackendSync *backend,
297                                   EDataCal *cal,
298                                   GCancellable *cancellable,
299                                   const GSList *users,
300                                   time_t start,
301                                   time_t end,
302                                   GSList **freebusyobjects,
303                                   GError **error)
304 {
305         e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
306
307         LOCK_WRAPPER (get_free_busy_sync, (backend, cal, cancellable, users, start, end, freebusyobjects, error));
308 }
309
310 /**
311  * e_cal_backend_sync_create_objects:
312  * @backend: An ECalBackendSync object.
313  * @cal: An EDataCal object.
314  * @cancellable: a #GCancellable for the operation
315  * @calobjs: The objects to be added.
316  * @uids: Placeholder for server-generated UIDs.
317  * @new_components: (out) (transfer full): Placeholder for returned #ECalComponent objects.
318  * @error: Out parameter for a #GError.
319  *
320  * Calls the create_objects_sync method on the given backend.
321  */
322 void
323 e_cal_backend_sync_create_objects (ECalBackendSync *backend,
324                                    EDataCal *cal,
325                                    GCancellable *cancellable,
326                                    const GSList *calobjs,
327                                    GSList **uids,
328                                    GSList **new_components,
329                                    GError **error)
330 {
331         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
332         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->create_objects_sync != NULL, UnsupportedMethod);
333
334         LOCK_WRAPPER (create_objects_sync, (backend, cal, cancellable, calobjs, uids, new_components, error));
335 }
336
337 /**
338  * e_cal_backend_sync_modify_objects:
339  * @backend: An ECalBackendSync object.
340  * @cal: An EDataCal object.
341  * @cancellable: a #GCancellable for the operation
342  * @calobjs: Objects to be modified.
343  * @mod: Type of modification to be done.
344  * @old_components: (out) (transfer full): Placeholder for returning the old components as they were stored on the
345  * backend.
346  * @new_components: (out) (transfer full): Placeholder for returning the new components as they have been stored
347  * on the backend.
348  * @error: Out parameter for a #GError.
349  *
350  * Calls the modify_objects_sync method on the given backend.
351  */
352 void
353 e_cal_backend_sync_modify_objects (ECalBackendSync *backend,
354                                                                    EDataCal *cal,
355                                                                    GCancellable *cancellable,
356                                                                    const GSList *calobjs,
357                                                                    CalObjModType mod,
358                                                                    GSList **old_components,
359                                                                    GSList **new_components,
360                                                                    GError **error)
361 {
362         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
363         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_objects_sync != NULL, UnsupportedMethod);
364
365         LOCK_WRAPPER (modify_objects_sync, (backend, cal, cancellable, calobjs, mod, old_components, new_components, error));
366 }
367
368 /**
369  * e_cal_backend_sync_remove_objects:
370  * @backend: An ECalBackendSync object.
371  * @cal: An EDataCal object.
372  * @cancellable: a #GCancellable for the operation
373  * @ids: List of #ECalComponentId objects identifying the objects to remove.
374  * @mod: Type of removal.
375  * @old_components: (out) (transfer full): Placeholder for returning the old components as they were stored on the
376  * backend.
377  * @new_components: (out) (transfer full): Placeholder for returning the new components as they have been stored
378  * on the backend (when removing individual instances). If removing whole objects,
379  * they will be set to %NULL.
380  * @error: Out parameter for a #GError.
381  *
382  * Calls the remove_objects_sync method on the given backend.
383  */
384 void
385 e_cal_backend_sync_remove_objects (ECalBackendSync *backend,
386                                    EDataCal *cal,
387                                    GCancellable *cancellable,
388                                    const GSList *ids,
389                                    CalObjModType mod,
390                                    GSList **old_components,
391                                    GSList **new_components,
392                                    GError **error)
393 {
394         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
395         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_objects_sync != NULL, UnsupportedMethod);
396
397         LOCK_WRAPPER (remove_objects_sync, (backend, cal, cancellable, ids, mod, old_components, new_components, error));
398 }
399
400 /**
401  * e_cal_backend_sync_receive_objects:
402  * @backend: An ECalBackendSync object.
403  * @cal: An EDataCal object.
404  * @cancellable: a #GCancellable for the operation
405  * @calobj: iCalendar object to receive.
406  * @error: Out parameter for a #GError.
407  *
408  * Calls the receive_objects_sync method on the given backend.
409  */
410 void
411 e_cal_backend_sync_receive_objects (ECalBackendSync *backend,
412                                     EDataCal *cal,
413                                     GCancellable *cancellable,
414                                     const gchar *calobj,
415                                     GError **error)
416 {
417         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
418         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->receive_objects_sync != NULL, UnsupportedMethod);
419
420         LOCK_WRAPPER (receive_objects_sync, (backend, cal, cancellable, calobj, error));
421 }
422
423 /**
424  * e_cal_backend_sync_send_objects:
425  * @backend: An ECalBackendSync object.
426  * @cal: An EDataCal object.
427  * @cancellable: a #GCancellable for the operation
428  * @calobj: The iCalendar object to send.
429  * @users: List of users to send notifications to.
430  * @modified_calobj: Placeholder for the iCalendar object after being modified.
431  * @error: Out parameter for a #GError.
432  *
433  * Calls the send_objects_sync method on the given backend.
434  */
435 void
436 e_cal_backend_sync_send_objects (ECalBackendSync *backend,
437                                  EDataCal *cal,
438                                  GCancellable *cancellable,
439                                  const gchar *calobj,
440                                  GSList **users,
441                                  gchar **modified_calobj,
442                                  GError **error)
443 {
444         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
445         e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->send_objects_sync != NULL, UnsupportedMethod);
446
447         LOCK_WRAPPER (send_objects_sync, (backend, cal, cancellable, calobj, users, modified_calobj, error));
448 }
449
450 /**
451  * e_cal_backend_sync_get_attachment_uris:
452  * @backend: An ECalBackendSync object.
453  * @cal: An EDataCal object.
454  * @cancellable: a #GCancellable for the operation
455  * @uid: Unique id of the calendar object.
456  * @rid: Recurrence id of the calendar object.
457  * @attachments: Placeholder for list of returned attachment uris.
458  * @error: Out parameter for a #GError.
459  *
460  * Calls the get_attachment_uris_sync method on the given backend.
461  *
462  * Since: 3.2
463  */
464 void
465 e_cal_backend_sync_get_attachment_uris (ECalBackendSync *backend,
466                                         EDataCal *cal,
467                                         GCancellable *cancellable,
468                                         const gchar *uid,
469                                         const gchar *rid,
470                                         GSList **attachments,
471                                         GError **error)
472 {
473         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
474         e_return_data_cal_error_if_fail (attachments, InvalidArg);
475
476         LOCK_WRAPPER (get_attachment_uris_sync, (backend, cal, cancellable, uid, rid, attachments, error));
477 }
478
479 /**
480  * e_cal_backend_sync_discard_alarm:
481  * @backend: An ECalBackendSync object.
482  * @cal: An EDataCal object.
483  * @cancellable: a #GCancellable for the operation
484  * @uid: Unique id of the calendar object.
485  * @rid: Recurrence id of the calendar object.
486  * @auid: Alarm ID to remove.
487  * @error: Out parameter for a #GError.
488  *
489  * Calls the discard_alarm_sync method on the given backend.
490  **/
491 void
492 e_cal_backend_sync_discard_alarm (ECalBackendSync *backend,
493                                   EDataCal *cal,
494                                   GCancellable *cancellable,
495                                   const gchar *uid,
496                                   const gchar *rid,
497                                   const gchar *auid,
498                                   GError **error)
499 {
500         e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
501         e_return_data_cal_error_if_fail (uid, InvalidArg);
502         e_return_data_cal_error_if_fail (auid, InvalidArg);
503
504         LOCK_WRAPPER (discard_alarm_sync, (backend, cal, cancellable, uid, rid, auid, error));
505 }
506
507 /**
508  * e_cal_backend_sync_get_timezone:
509  * @backend: An ECalBackendSync object.
510  * @cal: An EDataCal object.
511  * @cancellable: a #GCancellable for the operation
512  * @tzid: ID of the timezone to retrieve.
513  * @tzobject: Placeholder for the returned timezone.
514  * @error: Out parameter for a #GError.
515  *
516  * Calls the get_timezone_sync method on the given backend.
517  * This method is not mandatory on the backend, because here
518  * is used internal_get_timezone call to fetch timezone from
519  * it and that is transformed to a string. In other words,
520  * any object deriving from ECalBackendSync can implement only
521  * internal_get_timezone and can skip implementation of
522  * get_timezone_sync completely.
523  */
524 void
525 e_cal_backend_sync_get_timezone (ECalBackendSync *backend,
526                                  EDataCal *cal,
527                                  GCancellable *cancellable,
528                                  const gchar *tzid,
529                                  gchar **tzobject,
530                                  GError **error)
531 {
532         e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
533
534         if (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->get_timezone_sync) {
535                 LOCK_WRAPPER (get_timezone_sync, (backend, cal, cancellable, tzid, tzobject, error));
536         }
537
538         if (tzobject && !*tzobject) {
539                 icaltimezone *zone = NULL;
540
541                 if (backend->priv->mutex_lock)
542                         g_mutex_lock (backend->priv->sync_mutex);
543                 zone = e_cal_backend_internal_get_timezone (E_CAL_BACKEND (backend), tzid);
544                 if (backend->priv->mutex_lock)
545                         g_mutex_unlock (backend->priv->sync_mutex);
546
547                 if (!zone) {
548                         g_propagate_error (error, e_data_cal_create_error (ObjectNotFound, NULL));
549                 } else {
550                         icalcomponent *icalcomp;
551
552                         icalcomp = icaltimezone_get_component (zone);
553
554                         if (!icalcomp) {
555                                 g_propagate_error (error, e_data_cal_create_error (InvalidObject, NULL));
556                         } else {
557                                 *tzobject = icalcomponent_as_ical_string_r (icalcomp);
558                         }
559                 }
560         }
561 }
562
563 /**
564  * e_cal_backend_sync_add_timezone:
565  * @backend: An ECalBackendSync object.
566  * @cal: An EDataCal object.
567  * @cancellable: a #GCancellable for the operation
568  * @tzobject: VTIMEZONE object to be added.
569  * @error: Out parameter for a #GError.
570  *
571  * Calls the add_timezone_sync method on the given backend.
572  */
573 void
574 e_cal_backend_sync_add_timezone (ECalBackendSync *backend,
575                                  EDataCal *cal,
576                                  GCancellable *cancellable,
577                                  const gchar *tzobject,
578                                  GError **error)
579 {
580         e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
581
582         LOCK_WRAPPER (add_timezone_sync, (backend, cal, cancellable, tzobject, error));
583 }
584
585 static void
586 cal_backend_open (ECalBackend *backend,
587                   EDataCal *cal,
588                   guint32 opid,
589                   GCancellable *cancellable,
590                   gboolean only_if_exists)
591 {
592         GError *error = NULL;
593
594         e_cal_backend_sync_open (E_CAL_BACKEND_SYNC (backend), cal, cancellable, only_if_exists, &error);
595
596         e_data_cal_respond_open (cal, opid, error);
597 }
598
599 static void
600 cal_backend_authenticate_user (ECalBackend *backend,
601                                GCancellable *cancellable,
602                                ECredentials *credentials)
603 {
604         GError *error = NULL;
605
606         e_cal_backend_sync_authenticate_user (E_CAL_BACKEND_SYNC (backend), cancellable, credentials, &error);
607
608         e_cal_backend_notify_opened (backend, error);
609 }
610
611 static void
612 cal_backend_remove (ECalBackend *backend,
613                     EDataCal *cal,
614                     guint32 opid,
615                     GCancellable *cancellable)
616 {
617         GError *error = NULL;
618
619         e_cal_backend_sync_remove (E_CAL_BACKEND_SYNC (backend), cal, cancellable, &error);
620
621         e_data_cal_respond_remove (cal, opid, error);
622 }
623
624 static void
625 cal_backend_refresh (ECalBackend *backend,
626                      EDataCal *cal,
627                      guint32 opid,
628                      GCancellable *cancellable)
629 {
630         GError *error = NULL;
631
632         e_cal_backend_sync_refresh (E_CAL_BACKEND_SYNC (backend), cal, cancellable, &error);
633
634         e_data_cal_respond_refresh (cal, opid, error);
635 }
636
637 static void
638 cal_backend_get_backend_property (ECalBackend *backend,
639                                   EDataCal *cal,
640                                   guint32 opid,
641                                   GCancellable *cancellable,
642                                   const gchar *prop_name)
643 {
644         GError *error = NULL;
645         gchar *prop_value = NULL;
646
647         if (e_cal_backend_sync_get_backend_property (E_CAL_BACKEND_SYNC (backend), cal, cancellable, prop_name, &prop_value, &error))
648                 e_data_cal_respond_get_backend_property (cal, opid, error, prop_value);
649         else
650                 (* E_CAL_BACKEND_CLASS (e_cal_backend_sync_parent_class)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
651
652         g_free (prop_value);
653 }
654
655 static void
656 cal_backend_set_backend_property (ECalBackend *backend,
657                                   EDataCal *cal,
658                                   guint32 opid,
659                                   GCancellable *cancellable,
660                                   const gchar *prop_name,
661                                   const gchar *prop_value)
662 {
663         GError *error = NULL;
664
665         if (e_cal_backend_sync_set_backend_property (E_CAL_BACKEND_SYNC (backend), cal, cancellable, prop_name, prop_value, &error))
666                 e_data_cal_respond_set_backend_property (cal, opid, error);
667         else
668                 (* E_CAL_BACKEND_CLASS (e_cal_backend_sync_parent_class)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
669 }
670
671 static void
672 cal_backend_get_object (ECalBackend *backend,
673                         EDataCal *cal,
674                         guint32 opid,
675                         GCancellable *cancellable,
676                         const gchar *uid,
677                         const gchar *rid)
678 {
679         GError *error = NULL;
680         gchar *calobj = NULL;
681
682         e_cal_backend_sync_get_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, &calobj, &error);
683
684         e_data_cal_respond_get_object (cal, opid, error, calobj);
685
686         g_free (calobj);
687 }
688
689 static void
690 cal_backend_get_object_list (ECalBackend *backend,
691                              EDataCal *cal,
692                              guint32 opid,
693                              GCancellable *cancellable,
694                              const gchar *sexp)
695 {
696         GError *error = NULL;
697         GSList *calobjs = NULL;
698
699         e_cal_backend_sync_get_object_list (E_CAL_BACKEND_SYNC (backend), cal, cancellable, sexp, &calobjs, &error);
700
701         e_data_cal_respond_get_object_list (cal, opid, error, calobjs);
702
703         g_slist_foreach (calobjs, (GFunc) g_free, NULL);
704         g_slist_free (calobjs);
705 }
706
707 static void
708 cal_backend_get_free_busy (ECalBackend *backend,
709                            EDataCal *cal,
710                            guint32 opid,
711                            GCancellable *cancellable,
712                            const GSList *users,
713                            time_t start,
714                            time_t end)
715 {
716         GError *error = NULL;
717         GSList *freebusyobjs = NULL;
718
719         e_cal_backend_sync_get_free_busy (E_CAL_BACKEND_SYNC (backend), cal, cancellable, users, start, end, &freebusyobjs, &error);
720
721         if (freebusyobjs)
722                 e_data_cal_report_free_busy_data (cal, freebusyobjs);
723         e_data_cal_respond_get_free_busy (cal, opid, error);
724
725         g_slist_foreach (freebusyobjs, (GFunc) g_free, NULL);
726         g_slist_free (freebusyobjs);
727 }
728
729 static GSList *
730 ecalcomponent_slist_from_strings (const GSList *strings)
731 {
732         GSList *ecalcomps = NULL;
733         const GSList *l;
734
735         for (l = strings; l; l = l->next) {
736                 ECalComponent *component = e_cal_component_new_from_string (l->data);
737                 ecalcomps = g_slist_prepend (ecalcomps, component);
738         }
739
740         return g_slist_reverse (ecalcomps);
741 }
742
743 static void
744 cal_backend_create_objects (ECalBackend *backend,
745                             EDataCal *cal,
746                             guint32 opid,
747                             GCancellable *cancellable,
748                             const GSList *calobjs)
749 {
750         GError *error = NULL;
751         GSList *uids = NULL;
752         GSList *new_components = NULL;
753
754         e_cal_backend_sync_create_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobjs, &uids, &new_components, &error);
755
756         if (!new_components)
757                 new_components = ecalcomponent_slist_from_strings (calobjs);
758
759         e_data_cal_respond_create_objects (cal, opid, error, uids, new_components);
760
761         g_slist_free_full (uids, g_free);
762         e_util_free_nullable_object_slist (new_components);
763 }
764
765 static void
766 cal_backend_modify_objects (ECalBackend *backend,
767                             EDataCal *cal,
768                             guint32 opid,
769                             GCancellable *cancellable,
770                             const GSList *calobjs,
771                             CalObjModType mod)
772 {
773         GError *error = NULL;
774         GSList *old_components = NULL, *new_components = NULL;
775
776         e_cal_backend_sync_modify_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobjs, mod, &old_components, &new_components, &error);
777
778         if (!old_components)
779                 old_components = ecalcomponent_slist_from_strings (calobjs);
780
781         e_data_cal_respond_modify_objects (cal, opid, error, old_components, new_components);
782
783         e_util_free_nullable_object_slist (old_components);
784         e_util_free_nullable_object_slist (new_components);
785 }
786
787 static void
788 cal_backend_remove_objects (ECalBackend *backend,
789                             EDataCal *cal,
790                             guint32 opid,
791                             GCancellable *cancellable,
792                             const GSList *ids,
793                             CalObjModType mod)
794 {
795         GError *error = NULL;
796         GSList *old_components = NULL, *new_components = NULL;
797
798         e_cal_backend_sync_remove_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, ids, mod, &old_components, &new_components, &error);
799
800         e_data_cal_respond_remove_objects (cal, opid, error, ids, old_components, new_components);
801
802         e_util_free_nullable_object_slist (old_components);
803         e_util_free_nullable_object_slist (new_components);
804 }
805
806 static void
807 cal_backend_receive_objects (ECalBackend *backend,
808                              EDataCal *cal,
809                              guint32 opid,
810                              GCancellable *cancellable,
811                              const gchar *calobj)
812 {
813         GError *error = NULL;
814
815         e_cal_backend_sync_receive_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &error);
816
817         e_data_cal_respond_receive_objects (cal, opid, error);
818 }
819
820 static void
821 cal_backend_send_objects (ECalBackend *backend,
822                           EDataCal *cal,
823                           guint32 opid,
824                           GCancellable *cancellable,
825                           const gchar *calobj)
826 {
827         GError *error = NULL;
828         GSList *users = NULL;
829         gchar *modified_calobj = NULL;
830
831         e_cal_backend_sync_send_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &users, &modified_calobj, &error);
832
833         e_data_cal_respond_send_objects (cal, opid, error, users, modified_calobj ? modified_calobj : calobj);
834
835         g_slist_foreach (users, (GFunc) g_free, NULL);
836         g_slist_free (users);
837         g_free (modified_calobj);
838 }
839
840 static void
841 cal_backend_get_attachment_uris (ECalBackend *backend,
842                                  EDataCal *cal,
843                                  guint32 opid,
844                                  GCancellable *cancellable,
845                                  const gchar *uid,
846                                  const gchar *rid)
847 {
848         GError *error = NULL;
849         GSList *attachments = NULL;
850
851         e_cal_backend_sync_get_attachment_uris (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, &attachments, &error);
852
853         e_data_cal_respond_get_attachment_uris (cal, opid, error, attachments);
854
855         g_slist_foreach (attachments, (GFunc) g_free, NULL);
856         g_slist_free (attachments);
857 }
858
859 static void
860 cal_backend_discard_alarm (ECalBackend *backend,
861                            EDataCal *cal,
862                            guint32 opid,
863                            GCancellable *cancellable,
864                            const gchar *uid,
865                            const gchar *rid,
866                            const gchar *auid)
867 {
868         GError *error = NULL;
869
870         e_cal_backend_sync_discard_alarm (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, auid, &error);
871
872         e_data_cal_respond_discard_alarm (cal, opid, error);
873 }
874
875 static void
876 cal_backend_get_timezone (ECalBackend *backend,
877                           EDataCal *cal,
878                           guint32 opid,
879                           GCancellable *cancellable,
880                           const gchar *tzid)
881 {
882         GError *error = NULL;
883         gchar *object = NULL;
884
885         e_cal_backend_sync_get_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, tzid, &object, &error);
886
887         if (!object && tzid) {
888                 /* fallback if tzid contains only the location of timezone */
889                 gint i, slashes = 0;
890
891                 for (i = 0; tzid[i]; i++) {
892                         if (tzid[i] == '/')
893                                 slashes++;
894                 }
895
896                 if (slashes == 1) {
897                         icalcomponent *icalcomp = NULL, *free_comp = NULL;
898
899                         icaltimezone *zone = icaltimezone_get_builtin_timezone (tzid);
900                         if (!zone) {
901                                 /* Try fetching the timezone from zone directory. There are some timezones like MST, US/Pacific etc. which do not appear in
902                                 zone.tab, so they will not be available in the libical builtin timezone */
903                                 icalcomp = free_comp = icaltzutil_fetch_timezone (tzid);
904                         }
905
906                         if (zone)
907                                 icalcomp = icaltimezone_get_component (zone);
908
909                         if (icalcomp) {
910                                 icalcomponent *clone = icalcomponent_new_clone (icalcomp);
911                                 icalproperty *prop;
912
913                                 prop = icalcomponent_get_first_property (clone, ICAL_TZID_PROPERTY);
914                                 if (prop) {
915                                         /* change tzid to our, because the component has the buildin tzid */
916                                         icalproperty_set_tzid (prop, tzid);
917
918                                         object = icalcomponent_as_ical_string_r (clone);
919                                         g_clear_error (&error);
920                                 }
921                                 icalcomponent_free (clone);
922                         }
923
924                         if (free_comp)
925                                 icalcomponent_free (free_comp);
926                 }
927
928                 /* also cache this timezone to backend */
929                 if (object)
930                         e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, object, NULL);
931         }
932
933         e_data_cal_respond_get_timezone  (cal, opid, error, object);
934
935         g_free (object);
936 }
937
938 static void
939 cal_backend_add_timezone (ECalBackend *backend,
940                           EDataCal *cal,
941                           guint32 opid,
942                           GCancellable *cancellable,
943                           const gchar *tzobject)
944 {
945         GError *error = NULL;
946
947         e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, tzobject, &error);
948
949         e_data_cal_respond_add_timezone (cal, opid, error);
950 }
951
952 /* The default implementation is looking for timezone in the ical's builtin timezones,
953  * and if that fails, then it tries to extract the location from the tzid and get the
954  * timezone based on it. If even that fails, then it's returning UTC timezone.
955  * That means, that any object deriving from ECalBackendSync is supposed to implement
956  * this function for checking for a timezone in its own timezone cache, and if that
957  * fails, then call parent's object internal_get_timezone, and that's all.
958  */
959 static icaltimezone *
960 cal_backend_internal_get_timezone (ECalBackend *backend,
961                                    const gchar *tzid)
962 {
963         icaltimezone *zone = NULL;
964
965         if (!tzid || !*tzid)
966                 return NULL;
967
968         zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
969
970         if (!zone) {
971                 const gchar *s, *slash1 = NULL, *slash2 = NULL;
972
973                 /* get builtin by a location, if any */
974                 for (s = tzid; *s; s++) {
975                         if (*s == '/') {
976                                 slash1 = slash2;
977                                 slash2 = s;
978                         }
979                 }
980
981                 if (slash1)
982                         zone = icaltimezone_get_builtin_timezone (slash1 + 1);
983                 else if (slash2)
984                         zone = icaltimezone_get_builtin_timezone (tzid);
985         }
986
987         if (!zone)
988                 zone = icaltimezone_get_utc_timezone ();
989
990         return zone;
991 }
992
993 static gboolean
994 cal_backend_sync_get_backend_property (ECalBackendSync *backend,
995                                        EDataCal *cal,
996                                        GCancellable *cancellable,
997                                        const gchar *prop_name,
998                                        gchar **prop_value,
999                                        GError **error)
1000 {
1001         /* to indicate to pass to the ECalBackend parent class */
1002         return FALSE;
1003 }
1004
1005 static gboolean
1006 cal_backend_sync_set_backend_property (ECalBackendSync *backend,
1007                                        EDataCal *cal,
1008                                        GCancellable *cancellable,
1009                                        const gchar *prop_name,
1010                                        const gchar *prop_value,
1011                                        GError **error)
1012 {
1013         /* to indicate to pass to the ECalBackend parent class */
1014         return FALSE;
1015 }
1016
1017 static void
1018 e_cal_backend_sync_finalize (GObject *object)
1019 {
1020         ECalBackendSyncPrivate *priv;
1021
1022         priv = E_CAL_BACKEND_SYNC_GET_PRIVATE (object);
1023
1024         g_mutex_free (priv->sync_mutex);
1025
1026         /* Chain up to parent's finalize() method. */
1027         G_OBJECT_CLASS (e_cal_backend_sync_parent_class)->finalize (object);
1028 }
1029
1030 static void
1031 e_cal_backend_sync_class_init (ECalBackendSyncClass *class)
1032 {
1033         GObjectClass *object_class;
1034         ECalBackendClass *backend_class;
1035
1036         g_type_class_add_private (class, sizeof (ECalBackendSyncPrivate));
1037
1038         object_class = G_OBJECT_CLASS (class);
1039         object_class->finalize = e_cal_backend_sync_finalize;
1040
1041         backend_class = E_CAL_BACKEND_CLASS (class);
1042         backend_class->open                     = cal_backend_open;
1043         backend_class->authenticate_user        = cal_backend_authenticate_user;
1044         backend_class->remove                   = cal_backend_remove;
1045         backend_class->refresh                  = cal_backend_refresh;
1046         backend_class->get_backend_property     = cal_backend_get_backend_property;
1047         backend_class->set_backend_property     = cal_backend_set_backend_property;
1048         backend_class->get_object               = cal_backend_get_object;
1049         backend_class->get_object_list          = cal_backend_get_object_list;
1050         backend_class->get_free_busy            = cal_backend_get_free_busy;
1051         backend_class->create_objects           = cal_backend_create_objects;
1052         backend_class->modify_objects           = cal_backend_modify_objects;
1053         backend_class->remove_objects           = cal_backend_remove_objects;
1054         backend_class->receive_objects          = cal_backend_receive_objects;
1055         backend_class->send_objects             = cal_backend_send_objects;
1056         backend_class->get_attachment_uris      = cal_backend_get_attachment_uris;
1057         backend_class->discard_alarm            = cal_backend_discard_alarm;
1058         backend_class->get_timezone             = cal_backend_get_timezone;
1059         backend_class->add_timezone             = cal_backend_add_timezone;
1060         backend_class->internal_get_timezone    = cal_backend_internal_get_timezone;
1061
1062         class->get_backend_property_sync        = cal_backend_sync_get_backend_property;
1063         class->set_backend_property_sync        = cal_backend_sync_set_backend_property;
1064 }
1065
1066 static void
1067 e_cal_backend_sync_init (ECalBackendSync *backend)
1068 {
1069         backend->priv = E_CAL_BACKEND_SYNC_GET_PRIVATE (backend);
1070         backend->priv->sync_mutex = g_mutex_new ();
1071 }
1072