Fixes #273057
[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_timezone:
1001  * @backend: A calendar backend.
1002  * @cal: An #EDataCal object.
1003  * @tzid: The TZID identifying the timezone.
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_timezone (ECalBackend *backend, EDataCal *cal, const char *tzid)
1010 {
1011         g_return_if_fail (backend != NULL);
1012         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1013         g_return_if_fail (tzid != NULL);
1014
1015         g_assert (CLASS (backend)->set_default_timezone != NULL);
1016         (* CLASS (backend)->set_default_timezone) (backend, cal, tzid);
1017 }
1018
1019 /**
1020  * e_cal_backend_add_timezone
1021  * @backend: A calendar backend.
1022  * @cal: An #EDataCal object.
1023  * @tzobj: The timezone object, in a string.
1024  *
1025  * Add a timezone object to the given backend.
1026  */
1027 void
1028 e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, const char *tzobj)
1029 {
1030         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1031         g_return_if_fail (tzobj != NULL);
1032         g_return_if_fail (CLASS (backend)->add_timezone != NULL);
1033
1034         (* CLASS (backend)->add_timezone) (backend, cal, tzobj);
1035 }
1036
1037 /**
1038  * e_cal_backend_internal_get_default_timezone:
1039  * @backend: A calendar backend.
1040  *
1041  * Calls the internal_get_default_timezone method on the given backend.
1042  */
1043 icaltimezone *
1044 e_cal_backend_internal_get_default_timezone (ECalBackend *backend)
1045 {
1046         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1047         g_return_val_if_fail (CLASS (backend)->internal_get_default_timezone != NULL, NULL);
1048
1049         return (* CLASS (backend)->internal_get_default_timezone) (backend);
1050 }
1051
1052 /**
1053  * e_cal_backend_internal_get_timezone:
1054  * @backend: A calendar backend.
1055  * @tzid: ID of the timezone to get.
1056  *
1057  * Calls the internal_get_timezone method on the given backend.
1058  */
1059 icaltimezone *
1060 e_cal_backend_internal_get_timezone (ECalBackend *backend, const char *tzid)
1061 {
1062         g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1063         g_return_val_if_fail (tzid != NULL, NULL);
1064         g_return_val_if_fail (CLASS (backend)->internal_get_timezone != NULL, NULL);
1065
1066         return (* CLASS (backend)->internal_get_timezone) (backend, tzid);
1067 }
1068
1069 /**
1070  * e_cal_backend_set_notification_proxy:
1071  * @backend: A calendar backend.
1072  * @proxy: The calendar backend to act as notification proxy.
1073  *
1074  * Sets the backend that will act as notification proxy for the given backend.
1075  */
1076 void
1077 e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy)
1078 {
1079         ECalBackendPrivate *priv;
1080
1081         g_return_if_fail (E_IS_CAL_BACKEND (backend));
1082
1083         priv = backend->priv;
1084
1085         priv->notification_proxy = proxy;
1086 }
1087
1088 /**
1089  * e_cal_backend_notify_object_created:
1090  * @backend: A calendar backend.
1091  * @calobj: iCalendar representation of new object
1092  *
1093  * Notifies each of the backend's listeners about a new object.
1094  *
1095  * #e_data_cal_notify_object_created() calls this for you. You only need to
1096  * call e_cal_backend_notify_object_created() yourself to report objects
1097  * created by non-EDS clients.
1098  **/
1099 void
1100 e_cal_backend_notify_object_created (ECalBackend *backend, const char *calobj)
1101 {
1102         ECalBackendPrivate *priv;
1103         EList *queries;
1104         EIterator *iter;
1105         EDataCalView *query;
1106
1107         priv = backend->priv;
1108
1109         if (priv->notification_proxy) {
1110                 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1111                 return;
1112         }
1113
1114         queries = e_cal_backend_get_queries (backend);
1115         iter = e_list_get_iterator (queries);
1116
1117         while (e_iterator_is_valid (iter)) {
1118                 query = QUERY (e_iterator_get (iter));
1119
1120                 bonobo_object_ref (query);
1121                 if (e_data_cal_view_object_matches (query, calobj))             
1122                         e_data_cal_view_notify_objects_added_1 (query, calobj);
1123                 bonobo_object_unref (query);
1124
1125                 e_iterator_next (iter);
1126         }
1127         g_object_unref (iter);
1128 }
1129
1130 static void
1131 match_query_and_notify (EDataCalView *query, const char *old_object, const char *object)
1132 {
1133         gboolean old_match = FALSE, new_match = FALSE;
1134
1135         if (old_object)
1136                 old_match = e_data_cal_view_object_matches (query, old_object);
1137
1138         new_match = e_data_cal_view_object_matches (query, object);
1139         if (old_match && new_match)
1140                 e_data_cal_view_notify_objects_modified_1 (query, object);
1141         else if (new_match)
1142                 e_data_cal_view_notify_objects_added_1 (query, object);
1143         else if (old_match) {
1144                 ECalComponent *comp = NULL;
1145         
1146                 comp = e_cal_component_new_from_string (old_object);
1147                 if (comp) {
1148                         ECalComponentId *id = e_cal_component_get_id (comp);
1149
1150                         e_data_cal_view_notify_objects_removed_1 (query, id);
1151                         
1152                         e_cal_component_free_id (id);
1153                         g_object_unref (comp);
1154                 }
1155         }
1156 }
1157
1158 /**
1159  * e_cal_backend_notify_view_progress:
1160  * @backend: A calendar backend.
1161  * @message: the UID of the removed object
1162  * @percent: percentage of the objects loaded in the view
1163  *
1164  * Notifies each of the backend's listeners about the view_progress in downloading the items.
1165  **/
1166 void
1167 e_cal_backend_notify_view_progress (ECalBackend *backend, const char *message, int percent)
1168 {
1169         ECalBackendPrivate *priv;
1170         EList *queries;
1171         EIterator *iter;
1172         EDataCalView *query;
1173
1174         priv = backend->priv;
1175
1176         if (priv->notification_proxy) {
1177                 e_cal_backend_notify_view_progress (priv->notification_proxy, message, percent);
1178                 return;
1179         }
1180
1181         queries = e_cal_backend_get_queries (backend);
1182         iter = e_list_get_iterator (queries);
1183
1184         while (e_iterator_is_valid (iter)) {
1185                 query = QUERY (e_iterator_get (iter));
1186
1187                 bonobo_object_ref (query);
1188
1189                 e_data_cal_view_notify_progress (query, message, percent);
1190
1191                 bonobo_object_unref (query);
1192
1193                 e_iterator_next (iter);
1194         }
1195         g_object_unref (iter);
1196 }
1197
1198 /**
1199  * e_cal_backend_notify_view_done:
1200  * @backend: A calendar backend.
1201  * @status: returns the status once the view is fully populated.
1202  *
1203  * Notifies each of the backend's listeners about the view_done in downloading the items.
1204  **/
1205 void
1206 e_cal_backend_notify_view_done (ECalBackend *backend, GNOME_Evolution_Calendar_CallStatus status)
1207 {
1208         ECalBackendPrivate *priv;
1209         EList *queries;
1210         EIterator *iter;
1211         EDataCalView *query;
1212
1213         priv = backend->priv;
1214
1215         if (priv->notification_proxy) {
1216                 e_cal_backend_notify_view_done (priv->notification_proxy, status);
1217                 return;
1218         }
1219
1220         queries = e_cal_backend_get_queries (backend);
1221         iter = e_list_get_iterator (queries);
1222
1223         while (e_iterator_is_valid (iter)) {
1224                 query = QUERY (e_iterator_get (iter));
1225
1226                 bonobo_object_ref (query);
1227
1228                 e_data_cal_view_notify_done (query, status);
1229
1230                 bonobo_object_unref (query);
1231
1232                 e_iterator_next (iter);
1233         }
1234         g_object_unref (iter);
1235 }
1236
1237 /**
1238  * e_cal_backend_notify_object_modified:
1239  * @backend: A calendar backend.
1240  * @old_object: iCalendar representation of the original form of the object
1241  * @object: iCalendar representation of the new form of the object
1242  *
1243  * Notifies each of the backend's listeners about a modified object.
1244  *
1245  * #e_data_cal_notify_object_modified() calls this for you. You only need to
1246  * call e_cal_backend_notify_object_modified() yourself to report objects
1247  * modified by non-EDS clients.
1248  **/
1249 void
1250 e_cal_backend_notify_object_modified (ECalBackend *backend, 
1251                                       const char *old_object, const char *object)
1252 {
1253         ECalBackendPrivate *priv;
1254         EList *queries;
1255         EIterator *iter;
1256         EDataCalView *query;
1257
1258         priv = backend->priv;
1259
1260         if (priv->notification_proxy) {
1261                 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1262                 return;
1263         }
1264
1265         queries = e_cal_backend_get_queries (backend);
1266         iter = e_list_get_iterator (queries);
1267
1268         while (e_iterator_is_valid (iter)) {
1269                 query = QUERY (e_iterator_get (iter));
1270
1271                 bonobo_object_ref (query);
1272                 match_query_and_notify (query, old_object, object);
1273                 bonobo_object_unref (query);
1274
1275                 e_iterator_next (iter);
1276         }
1277         g_object_unref (iter);
1278 }
1279
1280 /**
1281  * e_cal_backend_notify_object_removed:
1282  * @backend: A calendar backend.
1283  * @id: the Id of the removed object
1284  * @old_object: iCalendar representation of the removed object
1285  * @new_object: iCalendar representation of the object after the removal. This
1286  * only applies to recurrent appointments that had an instance removed. In that
1287  * case, this function notifies a modification instead of a removal.
1288  *
1289  * Notifies each of the backend's listeners about a removed object.
1290  *
1291  * e_data_cal_notify_object_removed() calls this for you. You only need to
1292  * call e_cal_backend_notify_object_removed() yourself to report objects
1293  * removed by non-EDS clients.
1294  **/
1295 void
1296 e_cal_backend_notify_object_removed (ECalBackend *backend, const ECalComponentId *id,
1297                                      const char *old_object, const char *object)
1298 {
1299         ECalBackendPrivate *priv;
1300         EList *queries;
1301         EIterator *iter;
1302         EDataCalView *query;
1303
1304         priv = backend->priv;
1305
1306         if (priv->notification_proxy) {
1307                 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, object);
1308                 return;
1309         }
1310
1311         queries = e_cal_backend_get_queries (backend);
1312         iter = e_list_get_iterator (queries);
1313
1314         while (e_iterator_is_valid (iter)) {
1315                 query = QUERY (e_iterator_get (iter));
1316
1317                 bonobo_object_ref (query);
1318
1319                 if (object == NULL) {
1320                         /* if object == NULL, it means the object has been completely
1321                            removed from the backend */
1322                         e_data_cal_view_notify_objects_removed_1 (query, id);
1323                 } else
1324                         match_query_and_notify (query, old_object, object);
1325
1326                 bonobo_object_unref (query);
1327
1328                 e_iterator_next (iter);
1329         }
1330         g_object_unref (iter);
1331 }
1332
1333 /**
1334  * e_cal_backend_notify_mode:
1335  * @backend: A calendar backend.
1336  * @status: Status of the mode set
1337  * @mode: the current mode
1338  *
1339  * Notifies each of the backend's listeners about the results of a
1340  * setMode call.
1341  **/
1342 void
1343 e_cal_backend_notify_mode (ECalBackend *backend,
1344                            GNOME_Evolution_Calendar_CalListener_SetModeStatus status, 
1345                            GNOME_Evolution_Calendar_CalMode mode)
1346 {
1347         ECalBackendPrivate *priv = backend->priv;
1348         GList *l;
1349
1350         if (priv->notification_proxy) {
1351                 e_cal_backend_notify_mode (priv->notification_proxy, status, mode);
1352                 return;
1353         }
1354
1355         for (l = priv->clients; l; l = l->next)
1356                 e_data_cal_notify_mode (l->data, status, mode);
1357 }
1358
1359 /**
1360  * e_cal_backend_notify_auth_required:
1361  * @backend: A calendar backend.
1362  *
1363  * Notifies each of the backend's listeners that authentication is required to
1364  * open the calendar.
1365  */
1366 void
1367 e_cal_backend_notify_auth_required (ECalBackend *backend)
1368 {
1369         ECalBackendPrivate *priv = backend->priv;
1370         GList *l;
1371                                                                                                                              
1372         for (l = priv->clients; l; l = l->next)
1373                 e_data_cal_notify_auth_required (l->data);
1374 }
1375
1376 /**
1377  * e_cal_backend_notify_error:
1378  * @backend: A calendar backend.
1379  * @message: Error message
1380  *
1381  * Notifies each of the backend's listeners about an error
1382  **/
1383 void
1384 e_cal_backend_notify_error (ECalBackend *backend, const char *message)
1385 {
1386         ECalBackendPrivate *priv = backend->priv;
1387         GList *l;
1388
1389         if (priv->notification_proxy) {
1390                 e_cal_backend_notify_error (priv->notification_proxy, message);
1391                 return;
1392         }
1393
1394         for (l = priv->clients; l; l = l->next)
1395                 e_data_cal_notify_error (l->data, message);
1396 }