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