Fixes #332911
[platform/upstream/evolution-data-server.git] / calendar / libedata-cal / e-cal-backend.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - generic backend class
3  *
4  * Copyright (C) 2000 Ximian, Inc.
5  * Copyright (C) 2000 Ximian, Inc.
6  *
7  * Authors: Federico Mena-Quintero <federico@ximian.com>
8  *          JP Rosevear <jpr@ximian.com>
9  *          Rodrigo Moya <rodrigo@ximian.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
23  */
24
25 #include <config.h>
26 #include <libxml/parser.h>
27 #include <libxml/parserInternals.h>
28 #include <libxml/xmlmemory.h>
29
30 #include "e-cal-backend.h"
31
32 \f
33
34 /* Private part of the CalBackend structure */
35 struct _ECalBackendPrivate {
36         /* The source for this backend */
37         ESource *source;
38
39         /* URI, from source. This is cached, since we return const. */
40         char *uri;
41
42         /* The kind of components for this backend */
43         icalcomponent_kind kind;
44         
45         /* List of Cal objects */
46         GMutex *clients_mutex;
47         GList *clients;
48
49         GMutex *queries_mutex;
50         EList *queries;
51
52         /* ECalBackend to pass notifications on to */
53         ECalBackend *notification_proxy;
54 };
55
56 /* Property IDs */
57 enum props {
58         PROP_0,
59         PROP_SOURCE,
60         PROP_URI,
61         PROP_KIND
62 };
63
64 /* Signal IDs */
65 enum {
66         LAST_CLIENT_GONE,
67         OPENED,
68         REMOVED,
69         LAST_SIGNAL
70 };
71 static guint e_cal_backend_signals[LAST_SIGNAL];
72
73 static void e_cal_backend_class_init (ECalBackendClass *class);
74 static void e_cal_backend_init (ECalBackend *backend);
75 static void e_cal_backend_finalize (GObject *object);
76
77 #define CLASS(backend) (E_CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (backend)))
78
79 static GObjectClass *parent_class;
80
81 \f
82
83 /**
84  * e_cal_backend_get_type:
85  *
86  * Registers the #ECalBackend class if necessary, and returns the type ID
87  * associated to it.
88  *
89  * Return value: The type ID of the #ECalBackend class.
90  **/
91 GType
92 e_cal_backend_get_type (void)
93 {
94         static GType e_cal_backend_type = 0;
95
96         if (!e_cal_backend_type) {
97                 static GTypeInfo info = {
98                         sizeof (ECalBackendClass),
99                         (GBaseInitFunc) NULL,
100                         (GBaseFinalizeFunc) NULL,
101                         (GClassInitFunc) e_cal_backend_class_init,
102                         NULL, NULL,
103                         sizeof (ECalBackend),
104                         0,
105                         (GInstanceInitFunc) e_cal_backend_init,
106                 };
107                 e_cal_backend_type = g_type_register_static (G_TYPE_OBJECT, "ECalBackend", &info, 0);
108         }
109
110         return e_cal_backend_type;
111 }
112
113 static void
114 e_cal_backend_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
115 {
116         ECalBackend *backend;
117         ECalBackendPrivate *priv;
118         
119         backend = E_CAL_BACKEND (object);
120         priv = backend->priv;
121         
122         switch (property_id) {
123         case PROP_SOURCE:
124                 {
125                         ESource *new_source;
126
127                         new_source = g_value_get_object (value);
128                         if (new_source)
129                                 g_object_ref (new_source);
130
131                         if (priv->source)
132                                 g_object_unref (priv->source);
133
134                         priv->source = new_source;
135
136                         /* Cache the URI */
137                         if (new_source) {
138                                 g_free (priv->uri);
139                                 priv->uri = e_source_get_uri (priv->source);
140                         }
141                 }
142                 break;
143         case PROP_URI:
144                 if (!priv->source) {
145                         g_free (priv->uri);
146                         priv->uri = g_value_dup_string (value);
147                 }
148                 break;
149         case PROP_KIND:
150                 priv->kind = g_value_get_ulong (value);
151                 break;
152         default:
153                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154                 break;
155         }
156 }
157
158 static void
159 e_cal_backend_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
160 {
161         ECalBackend *backend;
162         ECalBackendPrivate *priv;
163         
164         backend = E_CAL_BACKEND (object);
165         priv = backend->priv;
166
167         switch (property_id) {
168         case PROP_SOURCE:
169                 g_value_set_object (value, e_cal_backend_get_source (backend));
170                 break;
171         case PROP_URI:
172                 g_value_set_string (value, e_cal_backend_get_uri (backend));
173                 break;
174         case PROP_KIND:
175                 g_value_set_ulong (value, e_cal_backend_get_kind (backend));
176                 break;
177         default:
178                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
179                 break;
180         }
181 }
182
183 /* Class initialization function for the calendar backend */
184 static void
185 e_cal_backend_class_init (ECalBackendClass *class)
186 {
187         GObjectClass *object_class;
188
189         parent_class = (GObjectClass *) g_type_class_peek_parent (class);
190
191         object_class = (GObjectClass *) class;
192
193         object_class->set_property = e_cal_backend_set_property;
194         object_class->get_property = e_cal_backend_get_property;
195         object_class->finalize = e_cal_backend_finalize;
196
197         g_object_class_install_property (object_class, PROP_SOURCE, 
198                                          g_param_spec_object ("source", NULL, NULL, E_TYPE_SOURCE,
199                                                               G_PARAM_READABLE | G_PARAM_WRITABLE
200                                                               | G_PARAM_CONSTRUCT_ONLY));
201
202         g_object_class_install_property (object_class, PROP_URI, 
203                                          g_param_spec_string ("uri", NULL, NULL, "",
204                                                               G_PARAM_READABLE | G_PARAM_WRITABLE
205                                                               | G_PARAM_CONSTRUCT_ONLY));
206
207         g_object_class_install_property (object_class, PROP_KIND, 
208                                          g_param_spec_ulong ("kind", NULL, NULL, 
209                                                              ICAL_NO_COMPONENT, ICAL_XLICMIMEPART_COMPONENT, 
210                                                              ICAL_NO_COMPONENT,
211                                                              G_PARAM_READABLE | G_PARAM_WRITABLE
212                                                              | G_PARAM_CONSTRUCT_ONLY));        
213         e_cal_backend_signals[LAST_CLIENT_GONE] =
214                 g_signal_new ("last_client_gone",
215                               G_TYPE_FROM_CLASS (class),
216                               G_SIGNAL_RUN_FIRST,
217                               G_STRUCT_OFFSET (ECalBackendClass, last_client_gone),
218                               NULL, NULL,
219                               g_cclosure_marshal_VOID__VOID,
220                               G_TYPE_NONE, 0);
221         e_cal_backend_signals[OPENED] =
222                 g_signal_new ("opened",
223                               G_TYPE_FROM_CLASS (class),
224                               G_SIGNAL_RUN_FIRST,
225                               G_STRUCT_OFFSET (ECalBackendClass, opened),
226                               NULL, NULL,
227                               g_cclosure_marshal_VOID__ENUM,
228                               G_TYPE_NONE, 1,
229                               G_TYPE_INT);
230         e_cal_backend_signals[REMOVED] =
231                 g_signal_new ("removed",
232                               G_TYPE_FROM_CLASS (class),
233                               G_SIGNAL_RUN_FIRST,
234                               G_STRUCT_OFFSET (ECalBackendClass, removed),
235                               NULL, NULL,
236                               g_cclosure_marshal_VOID__ENUM,
237                               G_TYPE_NONE, 1,
238                               G_TYPE_INT);
239
240         class->last_client_gone = NULL;
241         class->opened = NULL;
242         class->obj_updated = NULL;
243
244         class->get_cal_address = NULL;
245         class->get_alarm_email_address = NULL;
246         class->get_static_capabilities = NULL;
247         class->open = NULL;
248         class->is_loaded = NULL;
249         class->is_read_only = NULL;
250         class->start_query = NULL;
251         class->get_mode = NULL;
252         class->set_mode = NULL; 
253         class->get_object = NULL;
254         class->get_default_object = NULL;
255         class->get_object_list = NULL;
256         class->get_free_busy = NULL;
257         class->get_changes = NULL;
258         class->discard_alarm = NULL;
259         class->create_object = NULL;
260         class->modify_object = NULL;
261         class->remove_object = NULL;
262         class->receive_objects = NULL;
263         class->send_objects = NULL;
264         class->get_timezone = NULL;
265         class->add_timezone = NULL;
266         class->set_default_timezone = NULL;
267 }
268
269 /* Object initialization func for the calendar backend */
270 void
271 e_cal_backend_init (ECalBackend *backend)
272 {
273         ECalBackendPrivate *priv;
274
275         priv = g_new0 (ECalBackendPrivate, 1);
276         backend->priv = priv;
277
278         priv->clients = NULL;
279         priv->clients_mutex = g_mutex_new ();
280
281         /* FIXME bonobo_object_ref/unref? */
282         priv->queries = e_list_new((EListCopyFunc) g_object_ref, (EListFreeFunc) g_object_unref, NULL);
283         priv->queries_mutex = g_mutex_new ();
284 }
285
286 void
287 e_cal_backend_finalize (GObject *object)
288 {
289         ECalBackend *backend = (ECalBackend *)object;
290         ECalBackendPrivate *priv;
291
292         priv = backend->priv;
293
294         g_assert (priv->clients == NULL);
295
296         g_object_unref (priv->queries);
297
298         g_mutex_free (priv->clients_mutex);
299         g_mutex_free (priv->queries_mutex);
300
301         g_free (priv);
302
303         G_OBJECT_CLASS (parent_class)->finalize (object);
304 }
305
306 \f
307
308 /**
309  * e_cal_backend_get_source:
310  * @backend: An #ECalBackend object.
311  *
312  * Gets the #ESource associated with the given backend.
313  *
314  * Return value: The #ESource for the backend.
315  */
316 ESource *
317 e_cal_backend_get_source (ECalBackend *backend)
318 {
319         ECalBackendPrivate *priv;
320         
321         g_return_val_if_fail (backend != NULL, NULL);
322         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
323
324         priv = backend->priv;
325         
326         return priv->source;
327 }
328
329 /**
330  * e_cal_backend_get_uri:
331  * @backend: A calendar backend.
332  *
333  * Queries the URI of a calendar backend, which must already have an open
334  * calendar.
335  *
336  * Return value: The URI where the calendar is stored.
337  **/
338 const char *
339 e_cal_backend_get_uri (ECalBackend *backend)
340 {
341         ECalBackendPrivate *priv;
342         
343         g_return_val_if_fail (backend != NULL, NULL);
344         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
345
346         priv = backend->priv;
347         
348         return priv->uri;
349 }
350
351 /**
352  * e_cal_backend_get_kind:
353  * @backend: An #ECalBackend object.
354  *
355  * Gets the kind of components the given backend stores.
356  *
357  * Return value: The kind of components for this backend.
358  */
359 icalcomponent_kind
360 e_cal_backend_get_kind (ECalBackend *backend)
361 {
362         ECalBackendPrivate *priv;
363         
364         g_return_val_if_fail (backend != NULL, ICAL_NO_COMPONENT);
365         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
366
367         priv = backend->priv;
368         
369         return priv->kind;
370 }
371
372 static void
373 cal_destroy_cb (gpointer data, GObject *where_cal_was)
374 {
375         ECalBackend *backend = E_CAL_BACKEND (data);
376
377         e_cal_backend_remove_client (backend, (EDataCal *) where_cal_was);
378 }
379
380 static void
381 listener_died_cb (gpointer cnx, gpointer data)
382 {
383         EDataCal *cal = E_DATA_CAL (data);
384
385         e_cal_backend_remove_client (e_data_cal_get_backend (cal), cal);
386 }
387
388 static void
389 last_client_gone (ECalBackend *backend)
390 {
391         g_signal_emit (backend, e_cal_backend_signals[LAST_CLIENT_GONE], 0);
392 }
393
394 /**
395  * e_cal_backend_add_client:
396  * @backend: An ECalBackend object.
397  * @cal: An EDataCal object.
398  *
399  * Adds a new client to the given backend. For any event, the backend will
400  * notify all clients added via this function.
401  */
402 void
403 e_cal_backend_add_client (ECalBackend *backend, EDataCal *cal)
404 {
405         ECalBackendPrivate *priv;
406         
407         g_return_if_fail (backend != NULL);
408         g_return_if_fail (E_IS_CAL_BACKEND (backend));
409         g_return_if_fail (cal != NULL);
410         g_return_if_fail (E_IS_DATA_CAL (cal));
411
412         priv = backend->priv;
413         
414         bonobo_object_set_immortal (BONOBO_OBJECT (cal), TRUE);
415
416         g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
417
418         ORBit_small_listen_for_broken (e_data_cal_get_listener (cal), G_CALLBACK (listener_died_cb), cal);
419
420         g_mutex_lock (priv->clients_mutex);
421         priv->clients = g_list_append (priv->clients, cal);
422         g_mutex_unlock (priv->clients_mutex);
423 }
424
425 /**
426  * e_cal_backend_remove_client:
427  * @backend: An #ECalBackend object.
428  * @cal: An #EDataCal object.
429  *
430  * Removes a client from the list of connected clients to the given backend.
431  */
432 void
433 e_cal_backend_remove_client (ECalBackend *backend, EDataCal *cal)
434 {
435         ECalBackendPrivate *priv;
436         
437         /* XXX this needs a bit more thinking wrt the mutex - we
438            should be holding it when we check to see if clients is
439            NULL */
440         g_return_if_fail (backend != NULL);
441         g_return_if_fail (E_IS_CAL_BACKEND (backend));
442         g_return_if_fail (cal != NULL);
443         g_return_if_fail (E_IS_DATA_CAL (cal));
444
445         priv = backend->priv;
446
447         /* Disconnect */
448         g_mutex_lock (priv->clients_mutex);
449         priv->clients = g_list_remove (priv->clients, cal);
450         g_mutex_unlock (priv->clients_mutex);
451
452         /* When all clients go away, notify the parent factory about it so that
453          * it may decide whether to kill the backend or not.
454          */
455         if (!priv->clients)
456                 last_client_gone (backend);
457 }
458
459 /**
460  * e_cal_backend_add_query:
461  * @backend: An #ECalBackend object.
462  * @query: An #EDataCalView object.
463  *
464  * Adds a query to the list of live queries being run by the given backend.
465  * Doing so means that any listener on the query will get notified of any
466  * change that affect the live query.
467  */
468 void
469 e_cal_backend_add_query (ECalBackend *backend, EDataCalView *query)
470 {
471         g_return_if_fail (backend != NULL);
472         g_return_if_fail (E_IS_CAL_BACKEND (backend));
473
474         g_mutex_lock (backend->priv->queries_mutex);
475
476         e_list_append (backend->priv->queries, query);
477         
478         g_mutex_unlock (backend->priv->queries_mutex);
479 }
480
481 /**
482  * e_cal_backend_get_queries:
483  * @backend: An #ECalBackend object.
484  *
485  * Gets the list of live queries being run on the given backend.
486  *
487  * Return value: The list of live queries.
488  */
489 EList *
490 e_cal_backend_get_queries (ECalBackend *backend)
491 {
492         g_return_val_if_fail (backend != NULL, NULL);
493         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
494
495         return backend->priv->queries;
496 }
497
498
499 /**
500  * e_cal_backend_get_cal_address:
501  * @backend: A calendar backend.
502  *
503  * Queries the cal address associated with a calendar backend, which
504  * must already have an open calendar.
505  **/
506 void
507 e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal)
508 {
509         g_return_if_fail (backend != NULL);
510         g_return_if_fail (E_IS_CAL_BACKEND (backend));
511
512         g_assert (CLASS (backend)->get_cal_address != NULL);
513         (* CLASS (backend)->get_cal_address) (backend, cal);
514 }
515
516 void
517 e_cal_backend_notify_readonly (ECalBackend *backend, gboolean read_only)
518 {
519         ECalBackendPrivate *priv;
520         GList *l;
521
522         priv = backend->priv;
523
524         if (priv->notification_proxy) {
525                 e_cal_backend_notify_readonly (priv->notification_proxy, read_only);
526                 return;
527         }
528         for (l = priv->clients; l; l = l->next)
529                 e_data_cal_notify_read_only (l->data, GNOME_Evolution_Calendar_Success, read_only);
530 }
531
532 void
533 e_cal_backend_notify_cal_address (ECalBackend *backend, char *address)
534 {
535         ECalBackendPrivate *priv;
536         GList *l;
537
538         priv = backend->priv;
539
540         for (l = priv->clients; l; l = l->next)
541                 e_data_cal_notify_cal_address (l->data, GNOME_Evolution_Calendar_Success, address);
542 }
543
544 /**
545  * e_cal_backend_get_alarm_email_address:
546  * @backend: An #ECalBackend object.
547  * @cal: An #EDataCal object.
548  *
549  * Calls the get_alarm_email_address method on the given backend.
550  */
551 void
552 e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal)
553 {
554         g_return_if_fail (backend != NULL);
555         g_return_if_fail (E_IS_CAL_BACKEND (backend));
556
557         g_assert (CLASS (backend)->get_alarm_email_address != NULL);
558         (* CLASS (backend)->get_alarm_email_address) (backend, cal);
559 }
560
561 /**
562  *e_cal_backend_get_alarm_email_address:
563  * @backend: An #ECalBackend object.
564  * @cal: An #EDataCal object.
565  *
566  * Calls the get_ldap_attribute method of the given backend.
567  */
568 void
569 e_cal_backend_get_ldap_attribute (ECalBackend *backend, EDataCal *cal)
570 {
571         g_return_if_fail (backend != NULL);
572         g_return_if_fail (E_IS_CAL_BACKEND (backend));
573
574         g_assert (CLASS (backend)->get_ldap_attribute != NULL);
575         (* CLASS (backend)->get_ldap_attribute) (backend, cal);
576 }
577
578 /**
579  * e_cal_backend_get_alarm_email_address:
580  * @backend: An #ECalBackend object.
581  * @cal: An #EDataCal object.
582  *
583  * Calls the get_static_capabilities method on the given backend.
584  */
585 void
586 e_cal_backend_get_static_capabilities (ECalBackend *backend, EDataCal *cal)
587 {
588         g_return_if_fail (backend != NULL);
589         g_return_if_fail (E_IS_CAL_BACKEND (backend));
590
591         g_assert (CLASS (backend)->get_static_capabilities != NULL);
592         (* CLASS (backend)->get_static_capabilities) (backend, cal);
593 }
594
595 /**
596  * e_cal_backend_open:
597  * @backend: A calendar backend.
598  * @cal: An #EDataCal object.
599  * @only_if_exists: Whether the calendar should be opened only if it already
600  * exists.  If FALSE, a new calendar will be created when the specified @uri
601  * does not exist.
602  * @username: User name to use for authentication (if needed).
603  * @password: Password for @username.
604  *
605  * Opens a calendar backend with data from a calendar stored at the specified
606  * URI.
607  */
608 void
609 e_cal_backend_open (ECalBackend *backend, EDataCal *cal, gboolean only_if_exists,
610                     const char *username, const char *password)
611 {
612         g_return_if_fail (backend != NULL);
613         g_return_if_fail (E_IS_CAL_BACKEND (backend));
614
615         g_assert (CLASS (backend)->open != NULL);
616         (* CLASS (backend)->open) (backend, cal, only_if_exists, username, password);
617 }
618
619 /**
620  * e_cal_backend_remove:
621  * @backend: A calendar backend.
622  * @cal: An #EDataCal object.
623  *
624  * Removes the calendar being accessed by the given backend.
625  */
626 void
627 e_cal_backend_remove (ECalBackend *backend, EDataCal *cal)
628 {
629         g_return_if_fail (backend != NULL);
630         g_return_if_fail (E_IS_CAL_BACKEND (backend));
631
632         g_assert (CLASS (backend)->remove != NULL);
633         (* CLASS (backend)->remove) (backend, cal);
634 }
635
636 /**
637  * e_cal_backend_is_loaded:
638  * @backend: A calendar backend.
639  * 
640  * Queries whether a calendar backend has been loaded yet.
641  * 
642  * Return value: TRUE if the backend has been loaded with data, FALSE
643  * otherwise.
644  */
645 gboolean
646 e_cal_backend_is_loaded (ECalBackend *backend)
647 {
648         gboolean result;
649
650         g_return_val_if_fail (backend != NULL, FALSE);
651         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
652
653         g_assert (CLASS (backend)->is_loaded != NULL);
654         result = (* CLASS (backend)->is_loaded) (backend);
655
656         return result;
657 }
658
659 /**
660  * e_cal_backend_is_read_only
661  * @backend: A calendar backend.
662  * @cal: An #EDataCal object.
663  *
664  * Queries whether a calendar backend is read only or not.
665  *
666  */
667 void
668 e_cal_backend_is_read_only (ECalBackend *backend, EDataCal *cal)
669 {
670         g_return_if_fail (backend != NULL);
671         g_return_if_fail (E_IS_CAL_BACKEND (backend));
672
673         g_assert (CLASS (backend)->is_read_only != NULL);
674         (* CLASS (backend)->is_read_only) (backend, cal);
675 }
676
677 /**
678  * e_cal_backend_start_query:
679  * @backend: A calendar backend.
680  * @query: The query to be started.
681  *
682  * Starts a new live query on the given backend.
683  */
684 void 
685 e_cal_backend_start_query (ECalBackend *backend, EDataCalView *query)
686 {
687         g_return_if_fail (backend != NULL);
688         g_return_if_fail (E_IS_CAL_BACKEND (backend));
689
690         g_assert (CLASS (backend)->start_query != NULL);
691         (* CLASS (backend)->start_query) (backend, query);
692 }
693
694 /**
695  * e_cal_backend_get_mode:
696  * @backend: A calendar backend. 
697  * 
698  * Queries whether a calendar backend is connected remotely.
699  * 
700  * Return value: The current mode the calendar is in
701  **/
702 CalMode
703 e_cal_backend_get_mode (ECalBackend *backend)
704 {
705         CalMode result;
706
707         g_return_val_if_fail (backend != NULL, FALSE);
708         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
709
710         g_assert (CLASS (backend)->get_mode != NULL);
711         result = (* CLASS (backend)->get_mode) (backend);
712
713         return result;
714 }
715
716
717 /**
718  * e_cal_backend_set_mode:
719  * @backend: A calendar backend
720  * @mode: Mode to change to
721  * 
722  * Sets the mode of the calendar 
723  */
724 void
725 e_cal_backend_set_mode (ECalBackend *backend, CalMode mode)
726 {
727         g_return_if_fail (backend != NULL);
728         g_return_if_fail (E_IS_CAL_BACKEND (backend));
729
730         g_assert (CLASS (backend)->set_mode != NULL);
731         (* CLASS (backend)->set_mode) (backend, mode);
732 }
733
734 /**
735  * e_cal_backend_get_default_object:
736  * @backend: A calendar backend.
737  * @cal: An #EDataCal object.
738  *
739  * Calls the get_default_object method on the given backend.
740  */
741 void
742 e_cal_backend_get_default_object (ECalBackend *backend, EDataCal *cal)
743 {
744         g_return_if_fail (backend != NULL);
745         g_return_if_fail (E_IS_CAL_BACKEND (backend));
746
747         g_assert (CLASS (backend)->get_default_object != NULL);
748         (* CLASS (backend)->get_default_object) (backend, cal);
749 }
750
751 /**
752  * e_cal_backend_get_object:
753  * @backend: A calendar backend.
754  * @cal: An #EDataCal object.
755  * @uid: Unique identifier for a calendar object.
756  * @rid: ID for the object's recurrence to get.
757  *
758  * Queries a calendar backend for a calendar object based on its unique
759  * identifier and its recurrence ID (if a recurrent appointment).
760  */
761 void
762 e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, const char *uid, const char *rid)
763 {
764         g_return_if_fail (backend != NULL);
765         g_return_if_fail (E_IS_CAL_BACKEND (backend));
766         g_return_if_fail (uid != NULL);
767
768         g_assert (CLASS (backend)->get_object != NULL);
769         (* CLASS (backend)->get_object) (backend, cal, uid, rid);
770 }
771
772 /**
773  * e_cal_backend_get_object_list:
774  * @backend: A calendar backend.
775  * @cal: An #EDataCal object.
776  * @sexp: Expression to search for.
777  * 
778  * Calls the get_object_list method on the given backend.
779  */
780 void
781 e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, const char *sexp)
782 {
783         g_return_if_fail (backend != NULL);
784         g_return_if_fail (E_IS_CAL_BACKEND (backend));
785
786         g_assert (CLASS (backend)->get_object_list != NULL);
787         (* CLASS (backend)->get_object_list) (backend, cal, sexp);
788 }
789
790 /**
791  * e_cal_backend_get_attachment_list:
792  * @backend: A calendar backend.
793  * @cal: An #EDataCal object.
794  * @uid: Unique identifier for a calendar object.
795  * @rid: ID for the object's recurrence to get.
796  *
797  * Queries a calendar backend for attachments present in a calendar object based 
798  * on its unique identifier and its recurrence ID (if a recurrent appointment).
799  */
800 void
801 e_cal_backend_get_attachment_list (ECalBackend *backend, EDataCal *cal, const char *uid, const char *rid)
802 {
803         g_return_if_fail (backend != NULL);
804         g_return_if_fail (E_IS_CAL_BACKEND (backend));
805         g_return_if_fail (uid != NULL);
806
807         g_assert (CLASS (backend)->get_object != NULL);
808         (* CLASS (backend)->get_attachment_list) (backend, cal, uid, rid);
809 }
810
811 /**
812  * e_cal_backend_get_free_busy:
813  * @backend: A calendar backend.
814  * @cal: An #EDataCal object.
815  * @users: List of users to get free/busy information for.
816  * @start: Start time for query.
817  * @end: End time for query.
818  * 
819  * Gets a free/busy object for the given time interval
820  */
821 void
822 e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, GList *users, time_t start, time_t end)
823 {
824         g_return_if_fail (backend != NULL);
825         g_return_if_fail (E_IS_CAL_BACKEND (backend));
826         g_return_if_fail (start != -1 && end != -1);
827         g_return_if_fail (start <= end);
828
829         g_assert (CLASS (backend)->get_free_busy != NULL);
830         (* CLASS (backend)->get_free_busy) (backend, cal, users, start, end);
831 }
832
833 /**
834  * e_cal_backend_get_changes:
835  * @backend: A calendar backend.
836  * @cal: An #EDataCal object.
837  * @change_id: A unique uid for the callers change list
838  * 
839  * Builds a sequence of objects and the type of change that occurred on them since
840  * the last time the give change_id was seen
841  */
842 void
843 e_cal_backend_get_changes (ECalBackend *backend, EDataCal *cal, const char *change_id) 
844 {
845         g_return_if_fail (backend != NULL);
846         g_return_if_fail (E_IS_CAL_BACKEND (backend));
847         g_return_if_fail (change_id != NULL);
848
849         g_assert (CLASS (backend)->get_changes != NULL);
850         (* CLASS (backend)->get_changes) (backend, cal, change_id);
851 }
852
853 /**
854  * e_cal_backend_discard_alarm
855  * @backend: A calendar backend.
856  * @cal: An #EDataCal object.
857  * @uid: UID of the component to discard the alarm from.
858  * @auid: Alarm ID.
859  *
860  * Discards an alarm from the given component. This allows the specific backend
861  * to do whatever is needed to really discard the alarm.
862  */
863 void
864 e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, const char *uid, const char *auid)
865 {
866         g_return_if_fail (backend != NULL);
867         g_return_if_fail (E_IS_CAL_BACKEND (backend));
868         g_return_if_fail (uid != NULL);
869         g_return_if_fail (auid != NULL);
870
871         g_assert (CLASS (backend)->discard_alarm != NULL);
872         (* CLASS (backend)->discard_alarm) (backend, cal, uid, auid);
873 }
874
875 /**
876  * e_cal_backend_create_object:
877  * @backend: A calendar backend.
878  * @cal: An #EDataCal object.
879  * @calobj: The object to create.
880  *
881  * Calls the create_object method on the given backend.
882  */
883 void
884 e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, const char *calobj)
885 {
886         g_return_if_fail (backend != NULL);
887         g_return_if_fail (E_IS_CAL_BACKEND (backend));
888         g_return_if_fail (calobj != NULL);
889
890         if (CLASS (backend)->create_object)
891                 (* CLASS (backend)->create_object) (backend, cal, calobj);
892         else
893                 e_data_cal_notify_object_created (cal, GNOME_Evolution_Calendar_PermissionDenied, NULL, NULL);
894 }
895
896 /**
897  * e_cal_backend_modify_object:
898  * @backend: A calendar backend.
899  * @cal: An #EDataCal object.
900  * @calobj: Object to be modified.
901  * @mod: Type of modification.
902  *
903  * Calls the modify_object method on the given backend.
904  */
905 void
906 e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, const char *calobj, CalObjModType mod)
907 {
908         g_return_if_fail (backend != NULL);
909         g_return_if_fail (E_IS_CAL_BACKEND (backend));
910         g_return_if_fail (calobj != NULL);
911
912         if (CLASS (backend)->modify_object)
913                 (* CLASS (backend)->modify_object) (backend, cal, calobj, mod);
914         else
915                 e_data_cal_notify_object_removed (cal, GNOME_Evolution_Calendar_PermissionDenied, NULL, NULL, NULL);
916 }
917
918 /**
919  * e_cal_backend_remove_object:
920  * @backend: A calendar backend.
921  * @cal: An #EDataCal object.
922  * @uid: Unique identifier of the object to remove.
923  * @rid: A recurrence ID.
924  * @mod: Type of removal.
925  * 
926  * Removes an object in a calendar backend.  The backend will notify all of its
927  * clients about the change.
928  */
929 void
930 e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, const char *uid, const char *rid, CalObjModType mod)
931 {
932         g_return_if_fail (backend != NULL);
933         g_return_if_fail (E_IS_CAL_BACKEND (backend));
934         g_return_if_fail (uid != NULL);
935
936         g_assert (CLASS (backend)->remove_object != NULL);
937         (* CLASS (backend)->remove_object) (backend, cal, uid, rid, mod);
938 }
939
940 /**
941  * e_cal_backend_receive_objects:
942  * @backend: A calendar backend.
943  * @cal: An #EDataCal object.
944  * @calobj: iCalendar object.
945  *
946  * Calls the receive_objects method on the given backend.
947  */
948 void
949 e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, const char *calobj)
950 {
951         g_return_if_fail (backend != NULL);
952         g_return_if_fail (E_IS_CAL_BACKEND (backend));
953         g_return_if_fail (calobj != NULL);
954
955         g_assert (CLASS (backend)->receive_objects != NULL);
956         (* CLASS (backend)->receive_objects) (backend, cal, calobj);
957 }
958
959 /**
960  * e_cal_backend_send_objects:
961  * @backend: A calendar backend.
962  * @cal: An #EDataCal object.
963  * @calobj: iCalendar object to be sent.
964  *
965  * Calls the send_objects method on the given backend.
966  */
967 void
968 e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, const char *calobj)
969 {
970         g_return_if_fail (backend != NULL);
971         g_return_if_fail (E_IS_CAL_BACKEND (backend));
972         g_return_if_fail (calobj != NULL);
973
974         g_assert (CLASS (backend)->send_objects != NULL);
975         (* CLASS (backend)->send_objects) (backend, cal, calobj);
976 }
977
978 /**
979  * e_cal_backend_get_timezone:
980  * @backend: A calendar backend.
981  * @cal: An #EDataCal object.
982  * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
983  * NULL.
984  * 
985  * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
986  * can't be found.
987  */
988 void
989 e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, const char *tzid)
990 {
991         g_return_if_fail (backend != NULL);
992         g_return_if_fail (E_IS_CAL_BACKEND (backend));
993         g_return_if_fail (tzid != NULL);
994
995         g_assert (CLASS (backend)->get_timezone != NULL);
996         (* CLASS (backend)->get_timezone) (backend, cal, tzid);
997 }
998
999 /**
1000  * e_cal_backend_set_default_zone:
1001  * @backend: A calendar backend.
1002  * @cal: An #EDataCal object.
1003  * @tzobj: The timezone object, in a string.
1004  * 
1005  * Sets the default timezone for the calendar, which is used to resolve
1006  * DATE and floating DATE-TIME values. 
1007  */
1008 void
1009 e_cal_backend_set_default_zone (ECalBackend *backend, EDataCal *cal, const char *tzobj)
1010 {
1011         g_return_if_fail (backend != NULL);
1012         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1013         g_return_if_fail (tzobj != NULL);
1014
1015         (* CLASS (backend)->set_default_zone) (backend, cal, tzobj);
1016 }
1017
1018 /**
1019  * @deprecated This virual function should not be used in the backends, use
1020  * e_cal_backend_set_zone instead. This function restricts the default timezone
1021  * to be libical builtin timezone.
1022  *
1023  * e_cal_backend_set_default_timezone:
1024  * @backend: A calendar backend.
1025  * @cal: An #EDataCal object.
1026  * @tzid: The TZID identifying the timezone.
1027  * 
1028  * Sets the default timezone for the calendar, which is used to resolve
1029  * DATE and floating DATE-TIME values. 
1030  * 
1031  */
1032 void
1033 e_cal_backend_set_default_timezone (ECalBackend *backend, EDataCal *cal, const char *tzid)
1034 {
1035         g_return_if_fail (backend != NULL);
1036         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1037         g_return_if_fail (tzid != NULL);
1038
1039         (* CLASS (backend)->set_default_timezone) (backend, cal, tzid);
1040 }
1041
1042 /**
1043  * e_cal_backend_add_timezone
1044  * @backend: A calendar backend.
1045  * @cal: An #EDataCal object.
1046  * @tzobj: The timezone object, in a string.
1047  *
1048  * Add a timezone object to the given backend.
1049  */
1050 void
1051 e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, const char *tzobj)
1052 {
1053         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1054         g_return_if_fail (tzobj != NULL);
1055         g_return_if_fail (CLASS (backend)->add_timezone != NULL);
1056
1057         (* CLASS (backend)->add_timezone) (backend, cal, tzobj);
1058 }
1059
1060 /**
1061  * e_cal_backend_internal_get_default_timezone:
1062  * @backend: A calendar backend.
1063  *
1064  * Calls the internal_get_default_timezone method on the given backend.
1065  */
1066 icaltimezone *
1067 e_cal_backend_internal_get_default_timezone (ECalBackend *backend)
1068 {
1069         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1070         g_return_val_if_fail (CLASS (backend)->internal_get_default_timezone != NULL, NULL);
1071
1072         return (* CLASS (backend)->internal_get_default_timezone) (backend);
1073 }
1074
1075 /**
1076  * e_cal_backend_internal_get_timezone:
1077  * @backend: A calendar backend.
1078  * @tzid: ID of the timezone to get.
1079  *
1080  * Calls the internal_get_timezone method on the given backend.
1081  */
1082 icaltimezone *
1083 e_cal_backend_internal_get_timezone (ECalBackend *backend, const char *tzid)
1084 {
1085         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1086         g_return_val_if_fail (tzid != NULL, NULL);
1087         g_return_val_if_fail (CLASS (backend)->internal_get_timezone != NULL, NULL);
1088
1089         return (* CLASS (backend)->internal_get_timezone) (backend, tzid);
1090 }
1091
1092 /**
1093  * e_cal_backend_set_notification_proxy:
1094  * @backend: A calendar backend.
1095  * @proxy: The calendar backend to act as notification proxy.
1096  *
1097  * Sets the backend that will act as notification proxy for the given backend.
1098  */
1099 void
1100 e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy)
1101 {
1102         ECalBackendPrivate *priv;
1103
1104         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1105
1106         priv = backend->priv;
1107
1108         priv->notification_proxy = proxy;
1109 }
1110
1111 /**
1112  * e_cal_backend_notify_object_created:
1113  * @backend: A calendar backend.
1114  * @calobj: iCalendar representation of new object
1115  *
1116  * Notifies each of the backend's listeners about a new object.
1117  *
1118  * #e_data_cal_notify_object_created() calls this for you. You only need to
1119  * call e_cal_backend_notify_object_created() yourself to report objects
1120  * created by non-EDS clients.
1121  **/
1122 void
1123 e_cal_backend_notify_object_created (ECalBackend *backend, const char *calobj)
1124 {
1125         ECalBackendPrivate *priv;
1126         EList *queries;
1127         EIterator *iter;
1128         EDataCalView *query;
1129
1130         priv = backend->priv;
1131
1132         if (priv->notification_proxy) {
1133                 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1134                 return;
1135         }
1136
1137         queries = e_cal_backend_get_queries (backend);
1138         iter = e_list_get_iterator (queries);
1139
1140         while (e_iterator_is_valid (iter)) {
1141                 query = QUERY (e_iterator_get (iter));
1142
1143                 bonobo_object_ref (query);
1144                 if (e_data_cal_view_object_matches (query, calobj))             
1145                         e_data_cal_view_notify_objects_added_1 (query, calobj);
1146                 bonobo_object_unref (query);
1147
1148                 e_iterator_next (iter);
1149         }
1150         g_object_unref (iter);
1151 }
1152
1153 static void
1154 match_query_and_notify (EDataCalView *query, const char *old_object, const char *object)
1155 {
1156         gboolean old_match = FALSE, new_match = FALSE;
1157
1158         if (old_object)
1159                 old_match = e_data_cal_view_object_matches (query, old_object);
1160
1161         new_match = e_data_cal_view_object_matches (query, object);
1162         if (old_match && new_match)
1163                 e_data_cal_view_notify_objects_modified_1 (query, object);
1164         else if (new_match)
1165                 e_data_cal_view_notify_objects_added_1 (query, object);
1166         else if (old_match) {
1167                 ECalComponent *comp = NULL;
1168         
1169                 comp = e_cal_component_new_from_string (old_object);
1170                 if (comp) {
1171                         ECalComponentId *id = e_cal_component_get_id (comp);
1172
1173                         e_data_cal_view_notify_objects_removed_1 (query, id);
1174                         
1175                         e_cal_component_free_id (id);
1176                         g_object_unref (comp);
1177                 }
1178         }
1179 }
1180
1181 /**
1182  * e_cal_backend_notify_view_progress:
1183  * @backend: A calendar backend.
1184  * @message: the UID of the removed object
1185  * @percent: percentage of the objects loaded in the view
1186  *
1187  * Notifies each of the backend's listeners about the view_progress in downloading the items.
1188  **/
1189 void
1190 e_cal_backend_notify_view_progress (ECalBackend *backend, const char *message, int percent)
1191 {
1192         ECalBackendPrivate *priv;
1193         EList *queries;
1194         EIterator *iter;
1195         EDataCalView *query;
1196
1197         priv = backend->priv;
1198
1199         if (priv->notification_proxy) {
1200                 e_cal_backend_notify_view_progress (priv->notification_proxy, message, percent);
1201                 return;
1202         }
1203
1204         queries = e_cal_backend_get_queries (backend);
1205         iter = e_list_get_iterator (queries);
1206
1207         while (e_iterator_is_valid (iter)) {
1208                 query = QUERY (e_iterator_get (iter));
1209
1210                 bonobo_object_ref (query);
1211
1212                 e_data_cal_view_notify_progress (query, message, percent);
1213
1214                 bonobo_object_unref (query);
1215
1216                 e_iterator_next (iter);
1217         }
1218         g_object_unref (iter);
1219 }
1220
1221 /**
1222  * e_cal_backend_notify_view_done:
1223  * @backend: A calendar backend.
1224  * @status: returns the status once the view is fully populated.
1225  *
1226  * Notifies each of the backend's listeners about the view_done in downloading the items.
1227  **/
1228 void
1229 e_cal_backend_notify_view_done (ECalBackend *backend, GNOME_Evolution_Calendar_CallStatus status)
1230 {
1231         ECalBackendPrivate *priv;
1232         EList *queries;
1233         EIterator *iter;
1234         EDataCalView *query;
1235
1236         priv = backend->priv;
1237
1238         if (priv->notification_proxy) {
1239                 e_cal_backend_notify_view_done (priv->notification_proxy, status);
1240                 return;
1241         }
1242
1243         queries = e_cal_backend_get_queries (backend);
1244         iter = e_list_get_iterator (queries);
1245
1246         while (e_iterator_is_valid (iter)) {
1247                 query = QUERY (e_iterator_get (iter));
1248
1249                 bonobo_object_ref (query);
1250
1251                 e_data_cal_view_notify_done (query, status);
1252
1253                 bonobo_object_unref (query);
1254
1255                 e_iterator_next (iter);
1256         }
1257         g_object_unref (iter);
1258 }
1259
1260 /**
1261  * e_cal_backend_notify_object_modified:
1262  * @backend: A calendar backend.
1263  * @old_object: iCalendar representation of the original form of the object
1264  * @object: iCalendar representation of the new form of the object
1265  *
1266  * Notifies each of the backend's listeners about a modified object.
1267  *
1268  * #e_data_cal_notify_object_modified() calls this for you. You only need to
1269  * call e_cal_backend_notify_object_modified() yourself to report objects
1270  * modified by non-EDS clients.
1271  **/
1272 void
1273 e_cal_backend_notify_object_modified (ECalBackend *backend, 
1274                                       const char *old_object, const char *object)
1275 {
1276         ECalBackendPrivate *priv;
1277         EList *queries;
1278         EIterator *iter;
1279         EDataCalView *query;
1280
1281         priv = backend->priv;
1282
1283         if (priv->notification_proxy) {
1284                 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1285                 return;
1286         }
1287
1288         queries = e_cal_backend_get_queries (backend);
1289         iter = e_list_get_iterator (queries);
1290
1291         while (e_iterator_is_valid (iter)) {
1292                 query = QUERY (e_iterator_get (iter));
1293
1294                 bonobo_object_ref (query);
1295                 match_query_and_notify (query, old_object, object);
1296                 bonobo_object_unref (query);
1297
1298                 e_iterator_next (iter);
1299         }
1300         g_object_unref (iter);
1301 }
1302
1303 /**
1304  * e_cal_backend_notify_object_removed:
1305  * @backend: A calendar backend.
1306  * @id: the Id of the removed object
1307  * @old_object: iCalendar representation of the removed object
1308  * @new_object: iCalendar representation of the object after the removal. This
1309  * only applies to recurrent appointments that had an instance removed. In that
1310  * case, this function notifies a modification instead of a removal.
1311  *
1312  * Notifies each of the backend's listeners about a removed object.
1313  *
1314  * e_data_cal_notify_object_removed() calls this for you. You only need to
1315  * call e_cal_backend_notify_object_removed() yourself to report objects
1316  * removed by non-EDS clients.
1317  **/
1318 void
1319 e_cal_backend_notify_object_removed (ECalBackend *backend, const ECalComponentId *id,
1320                                      const char *old_object, const char *object)
1321 {
1322         ECalBackendPrivate *priv;
1323         EList *queries;
1324         EIterator *iter;
1325         EDataCalView *query;
1326
1327         priv = backend->priv;
1328
1329         if (priv->notification_proxy) {
1330                 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, object);
1331                 return;
1332         }
1333
1334         queries = e_cal_backend_get_queries (backend);
1335         iter = e_list_get_iterator (queries);
1336
1337         while (e_iterator_is_valid (iter)) {
1338                 query = QUERY (e_iterator_get (iter));
1339
1340                 bonobo_object_ref (query);
1341
1342                 if (object == NULL) {
1343                         /* if object == NULL, it means the object has been completely
1344                            removed from the backend */
1345                         if (e_data_cal_view_object_matches (query, old_object))
1346                                 e_data_cal_view_notify_objects_removed_1 (query, id);
1347                 } else
1348                         match_query_and_notify (query, old_object, object);
1349
1350                 bonobo_object_unref (query);
1351
1352                 e_iterator_next (iter);
1353         }
1354         g_object_unref (iter);
1355 }
1356
1357 /**
1358  * e_cal_backend_notify_mode:
1359  * @backend: A calendar backend.
1360  * @status: Status of the mode set
1361  * @mode: the current mode
1362  *
1363  * Notifies each of the backend's listeners about the results of a
1364  * setMode call.
1365  **/
1366 void
1367 e_cal_backend_notify_mode (ECalBackend *backend,
1368                            GNOME_Evolution_Calendar_CalListener_SetModeStatus status, 
1369                            GNOME_Evolution_Calendar_CalMode mode)
1370 {
1371         ECalBackendPrivate *priv = backend->priv;
1372         GList *l;
1373
1374         if (priv->notification_proxy) {
1375                 e_cal_backend_notify_mode (priv->notification_proxy, status, mode);
1376                 return;
1377         }
1378
1379         for (l = priv->clients; l; l = l->next)
1380                 e_data_cal_notify_mode (l->data, status, mode);
1381 }
1382
1383 /**
1384  * e_cal_backend_notify_auth_required:
1385  * @backend: A calendar backend.
1386  *
1387  * Notifies each of the backend's listeners that authentication is required to
1388  * open the calendar.
1389  */
1390 void
1391 e_cal_backend_notify_auth_required (ECalBackend *backend)
1392 {
1393         ECalBackendPrivate *priv = backend->priv;
1394         GList *l;
1395                                                                                                                              
1396         for (l = priv->clients; l; l = l->next)
1397                 e_data_cal_notify_auth_required (l->data);
1398 }
1399
1400 /**
1401  * e_cal_backend_notify_error:
1402  * @backend: A calendar backend.
1403  * @message: Error message
1404  *
1405  * Notifies each of the backend's listeners about an error
1406  **/
1407 void
1408 e_cal_backend_notify_error (ECalBackend *backend, const char *message)
1409 {
1410         ECalBackendPrivate *priv = backend->priv;
1411         GList *l;
1412
1413         if (priv->notification_proxy) {
1414                 e_cal_backend_notify_error (priv->notification_proxy, message);
1415                 return;
1416         }
1417
1418         for (l = priv->clients; l; l = l->next)
1419                 e_data_cal_notify_error (l->data, message);
1420 }