Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / calendar / backends / http / e-cal-backend-http.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - iCalendar http backend
3  *
4  * Copyright (C) 2003 Novell, Inc.
5  *
6  * Authors: Hans Petter Jansson <hpj@ximian.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * Based in part on the file backend.
22  */
23
24 #include <config.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <gconf/gconf-client.h>
28 #include <bonobo/bonobo-exception.h>
29 #include <bonobo/bonobo-moniker-util.h>
30 #include <glib/gi18n-lib.h>
31 #include "libedataserver/e-xml-hash-utils.h"
32 #include <libecal/e-cal-recur.h>
33 #include <libecal/e-cal-util.h>
34 #include <libecal/e-cal-time-util.h>
35 #include <libedata-cal/e-cal-backend-cache.h>
36 #include <libedata-cal/e-cal-backend-util.h>
37 #include <libedata-cal/e-cal-backend-sexp.h>
38 #include <libsoup/soup-session-async.h>
39 #include <libsoup/soup-uri.h>
40 #include "e-cal-backend-http.h"
41
42 \f
43
44 /* Private part of the ECalBackendHttp structure */
45 struct _ECalBackendHttpPrivate {
46         /* URI to get remote calendar data from */
47         char *uri;
48
49         /* Local/remote mode */
50         CalMode mode;
51
52         /* The file cache */
53         ECalBackendCache *cache;
54
55         /* The calendar's default timezone, used for resolving DATE and
56            floating DATE-TIME values. */
57         icaltimezone *default_zone;
58
59         /* The list of live queries */
60         GList *queries;
61
62         /* Soup handles for remote file */
63         SoupSession *soup_session;
64
65         /* Reload */
66         guint reload_timeout_id;
67         guint is_loading : 1;
68
69         /* Flags */
70         gboolean opened;
71
72         char *username;
73         char *password;
74 };
75
76 \f
77
78 #define d(x)
79
80 static void e_cal_backend_http_dispose (GObject *object);
81 static void e_cal_backend_http_finalize (GObject *object);
82 static gboolean begin_retrieval_cb (ECalBackendHttp *cbhttp);
83 static ECalBackendSyncStatus
84 e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj);
85
86 static ECalBackendSyncClass *parent_class;
87
88 \f
89
90 /* Dispose handler for the file backend */
91 static void
92 e_cal_backend_http_dispose (GObject *object)
93 {
94         ECalBackendHttp *cbhttp;
95         ECalBackendHttpPrivate *priv;
96
97         cbhttp = E_CAL_BACKEND_HTTP (object);
98         priv = cbhttp->priv;
99
100         g_free (priv->username);
101         g_free (priv->password);
102
103         if (G_OBJECT_CLASS (parent_class)->dispose)
104                 (* G_OBJECT_CLASS (parent_class)->dispose) (object);
105 }
106
107 /* Finalize handler for the file backend */
108 static void
109 e_cal_backend_http_finalize (GObject *object)
110 {
111         ECalBackendHttp *cbhttp;
112         ECalBackendHttpPrivate *priv;
113
114         g_return_if_fail (object != NULL);
115         g_return_if_fail (E_IS_CAL_BACKEND_HTTP (object));
116
117         cbhttp = E_CAL_BACKEND_HTTP (object);
118         priv = cbhttp->priv;
119
120         /* Clean up */
121
122         if (priv->cache) {
123                 g_object_unref (priv->cache);
124                 priv->cache = NULL;
125         }
126
127         if (priv->uri) {
128                 g_free (priv->uri);
129                 priv->uri = NULL;
130         }
131
132         if (priv->default_zone) {
133                 icaltimezone_free (priv->default_zone, 1);
134                 priv->default_zone = NULL;
135         }
136         
137
138         if (priv->soup_session) {
139                 soup_session_abort (priv->soup_session);
140                 g_object_unref (priv->soup_session);
141                 priv->soup_session = NULL;
142         }
143
144         if (priv->reload_timeout_id) {
145                 g_source_remove (priv->reload_timeout_id);
146                 priv->reload_timeout_id = 0;
147         }
148
149         g_free (priv);
150         cbhttp->priv = NULL;
151
152         if (G_OBJECT_CLASS (parent_class)->finalize)
153                 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
154 }
155
156 \f
157
158 /* Calendar backend methods */
159
160 /* Is_read_only handler for the file backend */
161 static ECalBackendSyncStatus
162 e_cal_backend_http_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only)
163 {
164         *read_only = TRUE;
165         
166         return GNOME_Evolution_Calendar_Success;
167 }
168
169 /* Get_email_address handler for the file backend */
170 static ECalBackendSyncStatus
171 e_cal_backend_http_get_cal_address (ECalBackendSync *backend, EDataCal *cal, char **address)
172 {
173         /* A HTTP backend has no particular email address associated
174          * with it (although that would be a useful feature some day).
175          */
176         *address = NULL;
177
178         return GNOME_Evolution_Calendar_Success;
179 }
180
181 static ECalBackendSyncStatus
182 e_cal_backend_http_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, char **attribute)
183 {
184         *attribute = NULL;
185         
186         return GNOME_Evolution_Calendar_Success;
187 }
188
189 static ECalBackendSyncStatus
190 e_cal_backend_http_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, char **address)
191 {
192         /* A HTTP backend has no particular email address associated
193          * with it (although that would be a useful feature some day).
194          */
195         *address = NULL;
196         
197         return GNOME_Evolution_Calendar_Success;
198 }
199
200 static ECalBackendSyncStatus
201 e_cal_backend_http_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, char **capabilities)
202 {
203         *capabilities = g_strdup (CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS);
204
205         return GNOME_Evolution_Calendar_Success;
206 }
207
208 static gchar *
209 webcal_to_http_method (const gchar *webcal_str, gboolean secure)
210 {
211         if (secure && (strncmp ("http://", webcal_str, sizeof ("http://") - 1) == 0))
212                 return g_strconcat ("https://", webcal_str + sizeof ("http://") - 1, NULL);
213
214         if (strncmp ("webcal://", webcal_str, sizeof ("webcal://") - 1))
215                 return g_strdup (webcal_str);
216
217         if (secure)
218                 return g_strconcat ("https://", webcal_str + sizeof ("webcal://") - 1, NULL);
219         else
220                 return g_strconcat ("http://", webcal_str + sizeof ("webcal://") - 1, NULL);
221 }
222
223 static gboolean
224 notify_and_remove_from_cache (gpointer key, gpointer value, gpointer user_data)
225 {
226         const char *calobj = value;
227         ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (user_data);
228         ECalComponent *comp = e_cal_component_new_from_string (calobj);
229         ECalComponentId *id = e_cal_component_get_id (comp);
230
231         e_cal_backend_cache_remove_component (cbhttp->priv->cache, id->uid, id->rid);
232         e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbhttp), id, calobj, NULL);
233
234         e_cal_component_free_id (id);
235         g_object_unref (comp);
236
237         return TRUE;
238 }
239
240 static void
241 retrieval_done (SoupMessage *msg, ECalBackendHttp *cbhttp)
242 {
243         ECalBackendHttpPrivate *priv;
244         icalcomponent *icalcomp, *subcomp;
245         icalcomponent_kind kind;
246         const char *newuri;
247         char *str;
248         GHashTable *old_cache;
249         GList *comps_in_cache;
250
251         priv = cbhttp->priv;
252
253         priv->is_loading = FALSE;
254         d(g_message ("Retrieval done.\n"));
255
256         /* Handle redirection ourselves */
257         if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
258                 newuri = soup_message_get_header (msg->response_headers,
259                                                   "Location");
260
261                 d(g_message ("Redirected to %s\n", newuri));
262
263                 if (newuri) {
264                         g_free (priv->uri);
265
266                         priv->uri = webcal_to_http_method (newuri, FALSE);
267                         begin_retrieval_cb (cbhttp);
268                 } else {
269                         if (!priv->opened) {
270                                 e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
271                                                             _("Redirected to Invalid URI"));
272                         }
273                 }
274
275                 return;
276         }
277
278         /* check status code */
279         if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
280                 if (!priv->opened) {
281                         e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
282                                                     soup_status_get_phrase (msg->status_code));
283                 }
284                 return;
285         }
286
287         /* get the calendar from the response */
288         str = g_malloc0 (msg->response.length + 1);
289         strncpy (str, msg->response.body, msg->response.length);
290         icalcomp = icalparser_parse_string (str);
291         g_free (str);
292
293         if (!icalcomp) {
294                 if (!priv->opened)
295                         e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp), _("Bad file format."));
296                 return;
297         }
298
299         if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
300                 if (!priv->opened)
301                         e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp), _("Not a calendar."));
302                 icalcomponent_free (icalcomp);
303                 return;
304         }
305
306         /* Update cache */
307         old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
308
309         comps_in_cache = e_cal_backend_cache_get_components (priv->cache);
310         while (comps_in_cache != NULL) {
311                 const char *uid;
312                 ECalComponent *comp = comps_in_cache->data;
313
314                 e_cal_component_get_uid (comp, &uid);
315                 g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp));
316
317                 comps_in_cache = g_list_remove (comps_in_cache, comps_in_cache->data);
318                 g_object_unref (comp);
319         }
320
321         kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbhttp));
322         subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
323         e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
324         while (subcomp) {
325                 ECalComponent *comp;
326                 icalcomponent_kind subcomp_kind;
327                 icalproperty *prop = NULL;
328
329                 subcomp_kind = icalcomponent_isa (subcomp);
330                 prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY);
331                 if (!prop) {
332                         g_warning (" The component does not have the  mandatory property UID \n");
333                         subcomp = icalcomponent_get_next_component (icalcomp, kind);
334                         continue;
335                 }
336
337                 if (subcomp_kind == kind) {
338                         comp = e_cal_component_new ();
339                         if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) {
340                                 const char *uid, *orig_key, *orig_value;
341
342                                 e_cal_backend_cache_put_component (priv->cache, comp);
343
344                                 e_cal_component_get_uid (comp, &uid);
345                                 /* middle (void*) cast only because of 'dereferencing type-punned pointer will break strict-aliasing rules' */
346                                 if (g_hash_table_lookup_extended (old_cache, uid, (void **)(void*)&orig_key, (void **)(void*)&orig_value)) {
347                                         e_cal_backend_notify_object_modified (E_CAL_BACKEND (cbhttp),
348                                                                               orig_value,
349                                                                               icalcomponent_as_ical_string (subcomp));
350                                         g_hash_table_remove (old_cache, uid);
351                                 } else {
352                                         e_cal_backend_notify_object_created (E_CAL_BACKEND (cbhttp),
353                                                                              icalcomponent_as_ical_string (subcomp));
354                                 }
355                         }
356
357                         g_object_unref (comp);
358                 } else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) {
359                         icaltimezone *zone;
360
361                         zone = icaltimezone_new ();
362                         icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp));
363                         e_cal_backend_cache_put_timezone (priv->cache, (const icaltimezone *) zone);
364
365                         icaltimezone_free (zone, 1);
366                 }
367
368                 subcomp = icalcomponent_get_next_component (icalcomp, kind);
369         }
370
371         e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
372
373         /* notify the removals */
374         g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, cbhttp);
375         g_hash_table_destroy (old_cache);
376
377         /* free memory */
378         icalcomponent_free (icalcomp);
379
380         d(g_message ("Retrieval really done.\n"));
381 }
382
383 /* ************************************************************************* */
384 /* Authentication helpers for libsoup */
385
386 static void
387 soup_authenticate (SoupSession  *session, 
388                    SoupMessage  *msg,
389                    const char   *auth_type, 
390                    const char   *auth_realm,
391                    char        **username, 
392                    char        **password, 
393                    gpointer      data)
394 {
395         ECalBackendHttpPrivate *priv;
396         ECalBackendHttp        *cbhttp;
397         
398         cbhttp = E_CAL_BACKEND_HTTP (data);     
399         priv =  cbhttp->priv;
400
401         *username = priv->username;
402         *password = priv->password;
403         
404         priv->username = NULL;
405         priv->password = NULL;
406
407 }
408
409 static void
410 soup_reauthenticate (SoupSession  *session, 
411                      SoupMessage  *msg,
412                      const char   *auth_type, 
413                      const char   *auth_realm,
414                      char        **username, 
415                      char        **password, 
416                      gpointer      data)
417 {
418         ECalBackendHttpPrivate *priv;
419         ECalBackendHttp        *cbhttp;
420         
421         cbhttp = E_CAL_BACKEND_HTTP (data);     
422         priv = cbhttp->priv;
423
424         *username = priv->username;
425         *password = priv->password;
426         
427         priv->username = NULL;
428         priv->password = NULL;
429 }
430
431 static gboolean reload_cb                  (ECalBackendHttp *cbhttp);
432 static void     maybe_start_reload_timeout (ECalBackendHttp *cbhttp);
433
434 static gboolean
435 begin_retrieval_cb (ECalBackendHttp *cbhttp)
436 {
437         ECalBackendHttpPrivate *priv;
438         SoupMessage *soup_message;
439
440         priv = cbhttp->priv;
441
442         if (priv->mode != CAL_MODE_REMOTE)
443                 return TRUE;
444
445         maybe_start_reload_timeout (cbhttp);
446
447         d(g_message ("Starting retrieval...\n"));
448
449         if (priv->is_loading)
450                 return FALSE;
451
452         priv->is_loading = TRUE;
453
454         /* create the Soup session if not already created */
455         if (!priv->soup_session) {
456                 GConfClient *conf_client;
457
458                 priv->soup_session = soup_session_async_new ();
459
460                 g_signal_connect (priv->soup_session, "authenticate",
461                                   G_CALLBACK (soup_authenticate), cbhttp);
462                 g_signal_connect (priv->soup_session, "reauthenticate",
463                                   G_CALLBACK (soup_reauthenticate), cbhttp);
464         
465                 /* set the HTTP proxy, if configuration is set to do so */
466                 conf_client = gconf_client_get_default ();
467                 if (gconf_client_get_bool (conf_client, "/system/http_proxy/use_http_proxy", NULL)) {
468                         char *server, *proxy_uri;
469                         int port;
470
471                         server = gconf_client_get_string (conf_client, "/system/http_proxy/host", NULL);
472                         port = gconf_client_get_int (conf_client, "/system/http_proxy/port", NULL);
473
474                         if (server && server[0]) {
475                                 SoupUri *suri;
476                                 if (gconf_client_get_bool (conf_client, "/system/http_proxy/use_authentication", NULL)) {
477                                         char *user, *password;
478
479                                         user = gconf_client_get_string (conf_client,
480                                                                         "/system/http_proxy/authentication_user",
481                                                                         NULL);
482                                         password = gconf_client_get_string (conf_client,
483                                                                             "/system/http_proxy/authentication_password",
484                                                                             NULL);
485
486                                         proxy_uri = g_strdup_printf("http://%s:%s@%s:%d", user, password, server, port);
487
488                                         g_free (user);
489                                         g_free (password);
490                                 } else
491                                         proxy_uri = g_strdup_printf ("http://%s:%d", server, port);
492
493                                 suri = soup_uri_new (proxy_uri);
494                                 g_object_set (G_OBJECT (priv->soup_session), SOUP_SESSION_PROXY_URI, suri, NULL);
495
496                                 soup_uri_free (suri);
497                                 g_free (server);
498                                 g_free (proxy_uri);
499                         }
500                 }
501
502                 g_object_unref (conf_client);
503         }
504
505         if (priv->uri == NULL) {
506                 ESource *source = e_cal_backend_get_source (E_CAL_BACKEND (cbhttp));
507                 const char *secure_prop = e_source_get_property (source, "use_ssl");
508                 
509                 priv->uri = webcal_to_http_method (e_cal_backend_get_uri (E_CAL_BACKEND (cbhttp)),
510                                                    (secure_prop && g_str_equal(secure_prop, "1")));
511         }
512
513         /* create message to be sent to server */
514         soup_message = soup_message_new (SOUP_METHOD_GET, priv->uri);
515         soup_message_add_header (soup_message->request_headers, "User-Agent",
516                                  "Evolution/" VERSION);
517         soup_message_set_flags (soup_message, SOUP_MESSAGE_NO_REDIRECT);
518
519         soup_session_queue_message (priv->soup_session, soup_message,
520                                     (SoupMessageCallbackFn) retrieval_done, cbhttp);
521
522         d(g_message ("Retrieval started.\n"));
523         return FALSE;
524 }
525
526 static gboolean
527 reload_cb (ECalBackendHttp *cbhttp)
528 {
529         ECalBackendHttpPrivate *priv;
530
531         priv = cbhttp->priv;
532
533         if (priv->is_loading)
534                 return TRUE;
535
536         d(g_message ("Reload!\n"));
537
538         priv->reload_timeout_id = 0;
539         priv->opened = TRUE;
540         begin_retrieval_cb (cbhttp);
541         return FALSE;
542 }
543
544 static void
545 maybe_start_reload_timeout (ECalBackendHttp *cbhttp)
546 {
547         ECalBackendHttpPrivate *priv;
548         ESource *source;
549         const gchar *refresh_str;
550
551         priv = cbhttp->priv;
552
553         d(g_message ("Setting reload timeout.\n"));
554
555         if (priv->reload_timeout_id)
556                 return;
557
558         source = e_cal_backend_get_source (E_CAL_BACKEND (cbhttp));
559         if (!source) {
560                 g_warning ("Could not get source for ECalBackendHttp reload.");
561                 return;
562         }
563
564         refresh_str = e_source_get_property (source, "refresh");
565
566         priv->reload_timeout_id = g_timeout_add ((refresh_str ? atoi (refresh_str) : 30) * 60000,
567                                                  (GSourceFunc) reload_cb, cbhttp);
568 }
569
570 /* Open handler for the file backend */
571 static ECalBackendSyncStatus
572 e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
573                          const char *username, const char *password)
574 {
575         ECalBackendHttp *cbhttp;
576         ECalBackendHttpPrivate *priv;
577         ESource *source;
578         
579         cbhttp = E_CAL_BACKEND_HTTP (backend);
580         priv = cbhttp->priv;
581         source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
582         
583         if (e_source_get_property (source, "auth") != NULL) {
584                 if ((username == NULL || password == NULL)) {
585                         return GNOME_Evolution_Calendar_AuthenticationRequired;
586                 }
587
588                 priv->username = g_strdup (username);
589                 priv->password = g_strdup (password);
590         }
591
592         if (!priv->cache) {
593                 priv->cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (backend)), E_CAL_SOURCE_TYPE_EVENT );
594
595
596                 if (!priv->cache) {
597                         e_cal_backend_notify_error (E_CAL_BACKEND(cbhttp), _("Could not create cache file"));
598                         return GNOME_Evolution_Calendar_OtherError;     
599                 }
600                 
601                 if (priv->default_zone) {
602                         e_cal_backend_cache_put_default_timezone (priv->cache, priv->default_zone);
603                 }
604
605                 if (priv->mode == CAL_MODE_LOCAL) 
606                         return GNOME_Evolution_Calendar_Success;
607                 
608
609                 g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
610         }
611
612         return GNOME_Evolution_Calendar_Success;
613 }
614
615 static ECalBackendSyncStatus
616 e_cal_backend_http_remove (ECalBackendSync *backend, EDataCal *cal)
617 {
618         ECalBackendHttp *cbhttp;
619         ECalBackendHttpPrivate *priv;
620         
621         cbhttp = E_CAL_BACKEND_HTTP (backend);
622         priv = cbhttp->priv;
623
624         if (!priv->cache)
625                 return GNOME_Evolution_Calendar_OtherError;
626
627         e_file_cache_remove (E_FILE_CACHE (priv->cache));
628         return GNOME_Evolution_Calendar_Success;
629 }
630
631 /* is_loaded handler for the file backend */
632 static gboolean
633 e_cal_backend_http_is_loaded (ECalBackend *backend)
634 {
635         ECalBackendHttp *cbhttp;
636         ECalBackendHttpPrivate *priv;
637
638         cbhttp = E_CAL_BACKEND_HTTP (backend);
639         priv = cbhttp->priv;
640
641         if (!priv->cache)
642                 return FALSE;
643
644         return TRUE;
645 }
646
647 /* is_remote handler for the http backend */
648 static CalMode
649 e_cal_backend_http_get_mode (ECalBackend *backend)
650 {
651         ECalBackendHttp *cbhttp;
652         ECalBackendHttpPrivate *priv;
653
654         cbhttp = E_CAL_BACKEND_HTTP (backend);
655         priv = cbhttp->priv;
656
657         return priv->mode;
658 }
659
660 /* Set_mode handler for the http backend */
661 static void
662 e_cal_backend_http_set_mode (ECalBackend *backend, CalMode mode)
663 {
664         ECalBackendHttp *cbhttp;
665         ECalBackendHttpPrivate *priv;
666         GNOME_Evolution_Calendar_CalMode set_mode;
667         gboolean loaded;
668         cbhttp = E_CAL_BACKEND_HTTP (backend);
669         priv = cbhttp->priv;
670
671         loaded = e_cal_backend_http_is_loaded (backend);
672                                 
673         switch (mode) {
674                 case CAL_MODE_LOCAL:
675                         priv->mode = mode;
676                         set_mode = cal_mode_to_corba (mode);
677                         if (loaded && priv->reload_timeout_id) {
678                                 g_source_remove (priv->reload_timeout_id);
679                                 priv->reload_timeout_id = 0;
680                         }
681                         break;
682                 case CAL_MODE_REMOTE:
683                 case CAL_MODE_ANY:      
684                         priv->mode = mode;
685                         set_mode = cal_mode_to_corba (mode);
686                         if (loaded) 
687                                 g_idle_add ((GSourceFunc) begin_retrieval_cb, backend);
688                         break;
689                 
690                         priv->mode = CAL_MODE_REMOTE;
691                         set_mode = GNOME_Evolution_Calendar_MODE_REMOTE;
692                         break;
693                 default:
694                         set_mode = GNOME_Evolution_Calendar_MODE_ANY;
695                         break;
696         }
697
698         if (loaded) {
699                 
700                 if (set_mode == GNOME_Evolution_Calendar_MODE_ANY)
701                         e_cal_backend_notify_mode (backend,
702                                                    GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED,
703                                                    cal_mode_to_corba (priv->mode));
704                 else
705                         e_cal_backend_notify_mode (backend,
706                                                    GNOME_Evolution_Calendar_CalListener_MODE_SET,
707                                                    set_mode);
708         }
709 }
710
711 static ECalBackendSyncStatus
712 e_cal_backend_http_get_default_object (ECalBackendSync *backend, EDataCal *cal, char **object)
713 {
714         ECalBackendHttp *cbhttp;
715         ECalBackendHttpPrivate *priv;
716         icalcomponent *icalcomp;
717         icalcomponent_kind kind;
718
719         cbhttp = E_CAL_BACKEND_HTTP (backend);
720         priv = cbhttp->priv;
721
722         kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
723         icalcomp = e_cal_util_new_component (kind);
724         *object = g_strdup (icalcomponent_as_ical_string (icalcomp));
725         icalcomponent_free (icalcomp);
726
727         return GNOME_Evolution_Calendar_Success;
728 }
729
730 /* Get_object_component handler for the http backend */
731 static ECalBackendSyncStatus
732 e_cal_backend_http_get_object (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *rid, char **object)
733 {
734         ECalBackendHttp *cbhttp;
735         ECalBackendHttpPrivate *priv;
736         ECalComponent *comp = NULL;
737
738         cbhttp = E_CAL_BACKEND_HTTP (backend);
739         priv = cbhttp->priv;
740
741         g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
742
743         if (!priv->cache)
744                 return GNOME_Evolution_Calendar_ObjectNotFound;
745
746         comp = e_cal_backend_cache_get_component (priv->cache, uid, rid);
747         if (!comp)
748                 return GNOME_Evolution_Calendar_ObjectNotFound;
749
750         *object = e_cal_component_get_as_string (comp);
751         g_object_unref (comp);
752
753         return GNOME_Evolution_Calendar_Success;
754 }
755
756 /* Get_timezone_object handler for the file backend */
757 static ECalBackendSyncStatus
758 e_cal_backend_http_get_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzid, char **object)
759 {
760         ECalBackendHttp *cbhttp;
761         ECalBackendHttpPrivate *priv;
762         const icaltimezone *zone;
763         icalcomponent *icalcomp;
764
765         cbhttp = E_CAL_BACKEND_HTTP (backend);
766         priv = cbhttp->priv;
767
768         g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
769
770         /* first try to get the timezone from the cache */
771         zone = e_cal_backend_cache_get_timezone (priv->cache, tzid);
772         if (!zone) {
773                 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
774                 if (!zone)
775                         return GNOME_Evolution_Calendar_ObjectNotFound;
776         }
777
778         icalcomp = icaltimezone_get_component ((icaltimezone *)zone);
779         if (!icalcomp)
780                 return GNOME_Evolution_Calendar_InvalidObject;
781
782         *object = g_strdup (icalcomponent_as_ical_string (icalcomp));
783
784         return GNOME_Evolution_Calendar_Success;
785 }
786
787 /* Add_timezone handler for the file backend */
788 static ECalBackendSyncStatus
789 e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
790 {
791         ECalBackendHttp *cbhttp;
792         ECalBackendHttpPrivate *priv;
793         icalcomponent *tz_comp;
794         icaltimezone *zone;
795
796         cbhttp = (ECalBackendHttp *) backend;
797
798         g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp), GNOME_Evolution_Calendar_OtherError);
799         g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
800
801         priv = cbhttp->priv;
802
803         tz_comp = icalparser_parse_string (tzobj);
804         if (!tz_comp)
805                 return GNOME_Evolution_Calendar_InvalidObject;
806
807         if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT) {
808                 icalcomponent_free (tz_comp);
809                 return GNOME_Evolution_Calendar_InvalidObject;
810         }
811
812         zone = icaltimezone_new ();
813         icaltimezone_set_component (zone, tz_comp);
814         e_cal_backend_cache_put_timezone (priv->cache, zone);
815
816         return GNOME_Evolution_Calendar_Success;
817 }
818
819 static ECalBackendSyncStatus
820 e_cal_backend_http_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const char *tzobj)
821 {
822         icalcomponent *tz_comp;
823         ECalBackendHttp *cbhttp;
824         ECalBackendHttpPrivate *priv;
825         icaltimezone *zone;
826
827         cbhttp = (ECalBackendHttp *) backend;
828
829         g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp), GNOME_Evolution_Calendar_OtherError);
830         g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
831
832         priv = cbhttp->priv;
833
834         tz_comp = icalparser_parse_string (tzobj);
835         if (!tz_comp)
836                 return GNOME_Evolution_Calendar_InvalidObject;
837
838
839         zone = icaltimezone_new ();
840         icaltimezone_set_component (zone, tz_comp);
841
842         if (priv->default_zone)
843                 icaltimezone_free (priv->default_zone, 1);
844
845         /* Set the default timezone to it. */
846         priv->default_zone = zone;
847
848         return GNOME_Evolution_Calendar_Success;
849 }
850
851 /* Get_objects_in_range handler for the file backend */
852 static ECalBackendSyncStatus
853 e_cal_backend_http_get_object_list (ECalBackendSync *backend, EDataCal *cal, const char *sexp, GList **objects)
854 {
855         ECalBackendHttp *cbhttp;
856         ECalBackendHttpPrivate *priv;
857         GList *components, *l;
858         ECalBackendSExp *cbsexp;
859
860         cbhttp = E_CAL_BACKEND_HTTP (backend);
861         priv = cbhttp->priv;
862
863         if (!priv->cache)
864                 return GNOME_Evolution_Calendar_NoSuchCal;
865
866         /* process all components in the cache */
867         cbsexp = e_cal_backend_sexp_new (sexp);
868
869         *objects = NULL;
870         components = e_cal_backend_cache_get_components (priv->cache);
871         for (l = components; l != NULL; l = l->next) {
872                 if (e_cal_backend_sexp_match_comp (cbsexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend))) {
873                         *objects = g_list_append (*objects, e_cal_component_get_as_string (l->data));
874                 }
875         }
876
877         g_list_foreach (components, (GFunc) g_object_unref, NULL);
878         g_list_free (components);
879         g_object_unref (cbsexp);
880
881         return GNOME_Evolution_Calendar_Success;
882 }
883
884 /* get_query handler for the file backend */
885 static void
886 e_cal_backend_http_start_query (ECalBackend *backend, EDataCalView *query)
887 {
888         ECalBackendHttp *cbhttp;
889         ECalBackendHttpPrivate *priv;
890         GList *components, *l, *objects = NULL;
891         ECalBackendSExp *cbsexp;
892
893         cbhttp = E_CAL_BACKEND_HTTP (backend);
894         priv = cbhttp->priv;
895
896         d(g_message (G_STRLOC ": Starting query (%s)", e_data_cal_view_get_text (query)));
897
898         if (!priv->cache) {
899                 e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_NoSuchCal);
900                 return;
901         }
902
903         /* process all components in the cache */
904         cbsexp = e_cal_backend_sexp_new (e_data_cal_view_get_text (query));
905
906         objects = NULL;
907         components = e_cal_backend_cache_get_components (priv->cache);
908         for (l = components; l != NULL; l = l->next) {
909                 if (e_cal_backend_sexp_match_comp (cbsexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend))) {
910                         objects = g_list_append (objects, e_cal_component_get_as_string (l->data));
911                 }
912         }
913
914         e_data_cal_view_notify_objects_added (query, (const GList *) objects);
915
916         g_list_foreach (components, (GFunc) g_object_unref, NULL);
917         g_list_free (components);
918         g_list_foreach (objects, (GFunc) g_free, NULL);
919         g_list_free (objects);
920         g_object_unref (cbsexp);
921
922         e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
923 }
924
925
926 static icaltimezone *
927 resolve_tzid (const char *tzid, gpointer user_data)
928 {
929         icalcomponent *vcalendar_comp = user_data;
930
931         if (!tzid || !tzid[0])
932                 return NULL;
933         else if (!strcmp (tzid, "UTC"))
934                 return icaltimezone_get_utc_timezone ();
935
936         return icalcomponent_get_timezone (vcalendar_comp, tzid);
937 }
938
939
940 static gboolean
941 free_busy_instance (ECalComponent *comp,
942                     time_t        instance_start,
943                     time_t        instance_end,
944                     gpointer      data)
945 {
946         icalcomponent *vfb = data;
947         icalproperty *prop;
948         icalparameter *param;
949         struct icalperiodtype ipt;
950         icaltimezone *utc_zone;
951
952         utc_zone = icaltimezone_get_utc_timezone ();
953
954         ipt.start = icaltime_from_timet_with_zone (instance_start, FALSE, utc_zone);
955         ipt.end = icaltime_from_timet_with_zone (instance_end, FALSE, utc_zone);
956         ipt.duration = icaldurationtype_null_duration ();
957
958         /* add busy information to the vfb component */
959         prop = icalproperty_new (ICAL_FREEBUSY_PROPERTY);
960         icalproperty_set_freebusy (prop, ipt);
961
962         param = icalparameter_new_fbtype (ICAL_FBTYPE_BUSY);
963         icalproperty_add_parameter (prop, param);
964
965         icalcomponent_add_property (vfb, prop);
966
967         return TRUE;
968 }
969
970 static icalcomponent *
971 create_user_free_busy (ECalBackendHttp *cbhttp, const char *address, const char *cn,
972                        time_t start, time_t end)
973 {
974         GList *list = NULL, *l;
975         icalcomponent *vfb;
976         icaltimezone *utc_zone;
977         ECalBackendSExp *obj_sexp;
978         ECalBackendHttpPrivate *priv;
979         ECalBackendCache *cache;
980         char *query, *iso_start, *iso_end;
981         
982         priv = cbhttp->priv;
983         cache = priv->cache;
984
985         /* create the (unique) VFREEBUSY object that we'll return */
986         vfb = icalcomponent_new_vfreebusy ();
987         if (address != NULL) {
988                 icalproperty *prop;
989                 icalparameter *param;
990
991                 prop = icalproperty_new_organizer (address);
992                 if (prop != NULL && cn != NULL) {
993                         param = icalparameter_new_cn (cn);
994                         icalproperty_add_parameter (prop, param);
995                 }
996                 if (prop != NULL)
997                         icalcomponent_add_property (vfb, prop);
998         }
999         utc_zone = icaltimezone_get_utc_timezone ();
1000         icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone));
1001         icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
1002
1003         /* add all objects in the given interval */
1004         iso_start = isodate_from_time_t (start);
1005         iso_end = isodate_from_time_t (end);
1006         query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") (make-time \"%s\")",
1007                                  iso_start, iso_end);
1008         obj_sexp = e_cal_backend_sexp_new (query);
1009         g_free (query);
1010         g_free (iso_start);
1011         g_free (iso_end);
1012
1013         if (!obj_sexp)
1014                 return vfb;
1015         if (!obj_sexp)
1016                 return vfb;
1017
1018         list = e_cal_backend_cache_get_components(cache);
1019
1020         for (l = list; l; l = l->next) {
1021                 ECalComponent *comp = l->data;
1022                 icalcomponent *icalcomp, *vcalendar_comp;
1023                 icalproperty *prop;
1024
1025                 icalcomp = e_cal_component_get_icalcomponent (comp);
1026                 if (!icalcomp)
1027                         continue;
1028
1029                 /* If the event is TRANSPARENT, skip it. */
1030                 prop = icalcomponent_get_first_property (icalcomp,
1031                                                          ICAL_TRANSP_PROPERTY);
1032                 if (prop) {
1033                         icalproperty_transp transp_val = icalproperty_get_transp (prop);
1034                         if (transp_val == ICAL_TRANSP_TRANSPARENT ||
1035                             transp_val == ICAL_TRANSP_TRANSPARENTNOCONFLICT)
1036                                 continue;
1037                 }
1038
1039                 if (!e_cal_backend_sexp_match_comp (obj_sexp, l->data, E_CAL_BACKEND (cbhttp)))
1040                         continue;
1041
1042                 vcalendar_comp = icalcomponent_get_parent (icalcomp);
1043                 if (!vcalendar_comp)
1044                         vcalendar_comp = icalcomp;
1045                 e_cal_recur_generate_instances (comp, start, end,
1046                                                 free_busy_instance,
1047                                                 vfb,
1048                                                 resolve_tzid,
1049                                                 vcalendar_comp,
1050                                                 e_cal_backend_cache_get_default_timezone (cache));
1051         }
1052         g_object_unref (obj_sexp);
1053
1054         return vfb;
1055 }
1056
1057
1058
1059 /* Get_free_busy handler for the file backend */
1060 static ECalBackendSyncStatus
1061 e_cal_backend_http_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users,
1062                                 time_t start, time_t end, GList **freebusy)
1063 {
1064         ECalBackendHttp *cbhttp;
1065         ECalBackendHttpPrivate *priv;
1066         gchar *address, *name;
1067         icalcomponent *vfb;
1068         char *calobj;
1069         
1070
1071         cbhttp = E_CAL_BACKEND_HTTP (backend);
1072         priv = cbhttp->priv;
1073
1074         g_return_val_if_fail (start != -1 && end != -1, GNOME_Evolution_Calendar_InvalidRange);
1075         g_return_val_if_fail (start <= end, GNOME_Evolution_Calendar_InvalidRange);
1076
1077         if (!priv->cache)
1078                 return GNOME_Evolution_Calendar_NoSuchCal;
1079
1080         if (users == NULL) {
1081                 if (e_cal_backend_mail_account_get_default (&address, &name)) {
1082                         vfb = create_user_free_busy (cbhttp, address, name, start, end);
1083                         calobj = icalcomponent_as_ical_string (vfb);
1084                         *freebusy = g_list_append (*freebusy, g_strdup (calobj));
1085                         icalcomponent_free (vfb);       
1086                         g_free (address);
1087                         g_free (name);
1088                 }
1089         } else {
1090                 GList *l;
1091                 for (l = users; l != NULL; l = l->next ) {
1092                         address = l->data;
1093                         if (e_cal_backend_mail_account_is_valid (address, &name)) {
1094                                 vfb = create_user_free_busy (cbhttp, address, name, start, end);
1095                                 calobj = icalcomponent_as_ical_string (vfb);
1096                                 *freebusy = g_list_append (*freebusy, g_strdup (calobj));
1097                                 icalcomponent_free (vfb);
1098                                 g_free (name);
1099                         }
1100                 }
1101         }
1102
1103         return GNOME_Evolution_Calendar_Success;
1104 }
1105
1106 /* Get_changes handler for the file backend */
1107 static ECalBackendSyncStatus
1108 e_cal_backend_http_get_changes (ECalBackendSync *backend, EDataCal *cal, const char *change_id,
1109                                 GList **adds, GList **modifies, GList **deletes)
1110 {
1111         ECalBackendHttp *cbhttp;
1112         ECalBackendHttpPrivate *priv;
1113
1114         cbhttp = E_CAL_BACKEND_HTTP (backend);
1115         priv = cbhttp->priv;
1116
1117         g_return_val_if_fail (change_id != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
1118
1119         /* FIXME */
1120         return GNOME_Evolution_Calendar_Success;
1121 }
1122
1123 /* Discard_alarm handler for the file backend */
1124 static ECalBackendSyncStatus
1125 e_cal_backend_http_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const char *uid, const char *auid)
1126 {
1127         ECalBackendHttp *cbhttp;
1128         ECalBackendHttpPrivate *priv;
1129
1130         cbhttp = E_CAL_BACKEND_HTTP (backend);
1131         priv = cbhttp->priv;
1132
1133         /* FIXME */
1134         return GNOME_Evolution_Calendar_Success;
1135 }
1136
1137 static ECalBackendSyncStatus
1138 e_cal_backend_http_create_object (ECalBackendSync *backend, EDataCal *cal, char **calobj, char **uid)
1139 {
1140         ECalBackendHttp *cbhttp;
1141         ECalBackendHttpPrivate *priv;
1142         
1143         cbhttp = E_CAL_BACKEND_HTTP (backend);
1144         priv = cbhttp->priv;
1145
1146         return GNOME_Evolution_Calendar_PermissionDenied;
1147 }
1148
1149 static ECalBackendSyncStatus
1150 e_cal_backend_http_modify_object (ECalBackendSync *backend, EDataCal *cal, const char *calobj, 
1151                                 CalObjModType mod, char **old_object, char **new_object)
1152 {
1153         ECalBackendHttp *cbhttp;
1154         ECalBackendHttpPrivate *priv;
1155
1156         cbhttp = E_CAL_BACKEND_HTTP (backend);
1157         priv = cbhttp->priv;
1158
1159         g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
1160
1161         return GNOME_Evolution_Calendar_PermissionDenied;
1162 }
1163
1164 /* Remove_object handler for the file backend */
1165 static ECalBackendSyncStatus
1166 e_cal_backend_http_remove_object (ECalBackendSync *backend, EDataCal *cal,
1167                                 const char *uid, const char *rid,
1168                                 CalObjModType mod, char **old_object,
1169                                 char **object)
1170 {
1171         ECalBackendHttp *cbhttp;
1172         ECalBackendHttpPrivate *priv;
1173
1174         cbhttp = E_CAL_BACKEND_HTTP (backend);
1175         priv = cbhttp->priv;
1176
1177         g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
1178
1179         *old_object = *object = NULL;
1180
1181         return GNOME_Evolution_Calendar_PermissionDenied;
1182 }
1183
1184 /* Update_objects handler for the file backend. */
1185 static ECalBackendSyncStatus
1186 e_cal_backend_http_receive_objects (ECalBackendSync *backend, EDataCal *cal, const char *calobj)
1187 {
1188         ECalBackendHttp *cbhttp;
1189         ECalBackendHttpPrivate *priv;
1190
1191         cbhttp = E_CAL_BACKEND_HTTP (backend);
1192         priv = cbhttp->priv;
1193
1194         g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
1195
1196         return GNOME_Evolution_Calendar_PermissionDenied;
1197 }
1198
1199 static ECalBackendSyncStatus
1200 e_cal_backend_http_send_objects (ECalBackendSync *backend, EDataCal *cal, const char *calobj, GList **users,
1201                                  char **modified_calobj)
1202 {
1203         ECalBackendHttp *cbhttp;
1204         ECalBackendHttpPrivate *priv;
1205
1206         cbhttp = E_CAL_BACKEND_HTTP (backend);
1207         priv = cbhttp->priv;
1208
1209         *users = NULL;
1210         *modified_calobj = NULL;
1211
1212         return GNOME_Evolution_Calendar_PermissionDenied;
1213 }
1214
1215 static icaltimezone *
1216 e_cal_backend_http_internal_get_default_timezone (ECalBackend *backend)
1217 {
1218         ECalBackendHttp *cbhttp;
1219         ECalBackendHttpPrivate *priv;
1220
1221         cbhttp = E_CAL_BACKEND_HTTP (backend);
1222         priv = cbhttp->priv;
1223
1224         if (!priv->cache)
1225                 return NULL;
1226
1227         return NULL;
1228 }
1229
1230 static icaltimezone *
1231 e_cal_backend_http_internal_get_timezone (ECalBackend *backend, const char *tzid)
1232 {
1233         ECalBackendHttp *cbhttp;
1234         ECalBackendHttpPrivate *priv;
1235         icaltimezone *zone;
1236
1237         cbhttp = E_CAL_BACKEND_HTTP (backend);
1238         priv = cbhttp->priv;
1239
1240         if (!strcmp (tzid, "UTC"))
1241                 zone = icaltimezone_get_utc_timezone ();
1242         else {
1243                 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
1244         }
1245
1246         return zone;
1247 }
1248
1249 /* Object initialization function for the file backend */
1250 static void
1251 e_cal_backend_http_init (ECalBackendHttp *cbhttp, ECalBackendHttpClass *class)
1252 {
1253         ECalBackendHttpPrivate *priv;
1254
1255         priv = g_new0 (ECalBackendHttpPrivate, 1);
1256         cbhttp->priv = priv;
1257
1258         priv->uri = NULL;
1259         priv->reload_timeout_id = 0;
1260         priv->opened = FALSE;
1261
1262         e_cal_backend_sync_set_lock (E_CAL_BACKEND_SYNC (cbhttp), TRUE);
1263 }
1264
1265 /* Class initialization function for the file backend */
1266 static void
1267 e_cal_backend_http_class_init (ECalBackendHttpClass *class)
1268 {
1269         GObjectClass *object_class;
1270         ECalBackendClass *backend_class;
1271         ECalBackendSyncClass *sync_class;
1272
1273         object_class = (GObjectClass *) class;
1274         backend_class = (ECalBackendClass *) class;
1275         sync_class = (ECalBackendSyncClass *) class;
1276
1277         parent_class = (ECalBackendSyncClass *) g_type_class_peek_parent (class);
1278
1279         object_class->dispose = e_cal_backend_http_dispose;
1280         object_class->finalize = e_cal_backend_http_finalize;
1281
1282         sync_class->is_read_only_sync = e_cal_backend_http_is_read_only;
1283         sync_class->get_cal_address_sync = e_cal_backend_http_get_cal_address;
1284         sync_class->get_alarm_email_address_sync = e_cal_backend_http_get_alarm_email_address;
1285         sync_class->get_ldap_attribute_sync = e_cal_backend_http_get_ldap_attribute;
1286         sync_class->get_static_capabilities_sync = e_cal_backend_http_get_static_capabilities;
1287         sync_class->open_sync = e_cal_backend_http_open;
1288         sync_class->remove_sync = e_cal_backend_http_remove;
1289         sync_class->create_object_sync = e_cal_backend_http_create_object;
1290         sync_class->modify_object_sync = e_cal_backend_http_modify_object;
1291         sync_class->remove_object_sync = e_cal_backend_http_remove_object;
1292         sync_class->discard_alarm_sync = e_cal_backend_http_discard_alarm;
1293         sync_class->receive_objects_sync = e_cal_backend_http_receive_objects;
1294         sync_class->send_objects_sync = e_cal_backend_http_send_objects;
1295         sync_class->get_default_object_sync = e_cal_backend_http_get_default_object;
1296         sync_class->get_object_sync = e_cal_backend_http_get_object;
1297         sync_class->get_object_list_sync = e_cal_backend_http_get_object_list;
1298         sync_class->get_timezone_sync = e_cal_backend_http_get_timezone;
1299         sync_class->add_timezone_sync = e_cal_backend_http_add_timezone;
1300         sync_class->set_default_zone_sync = e_cal_backend_http_set_default_zone;
1301         sync_class->get_freebusy_sync = e_cal_backend_http_get_free_busy;
1302         sync_class->get_changes_sync = e_cal_backend_http_get_changes;
1303
1304         backend_class->is_loaded = e_cal_backend_http_is_loaded;
1305         backend_class->start_query = e_cal_backend_http_start_query;
1306         backend_class->get_mode = e_cal_backend_http_get_mode;
1307         backend_class->set_mode = e_cal_backend_http_set_mode;
1308
1309         backend_class->internal_get_default_timezone = e_cal_backend_http_internal_get_default_timezone;
1310         backend_class->internal_get_timezone = e_cal_backend_http_internal_get_timezone;
1311 }
1312
1313
1314 /**
1315  * e_cal_backend_http_get_type:
1316  * @void: 
1317  * 
1318  * Registers the #ECalBackendHttp class if necessary, and returns the type ID
1319  * associated to it.
1320  * 
1321  * Return value: The type ID of the #ECalBackendHttp class.
1322  **/
1323 GType
1324 e_cal_backend_http_get_type (void)
1325 {
1326         static GType e_cal_backend_http_type = 0;
1327
1328         if (!e_cal_backend_http_type) {
1329                 static GTypeInfo info = {
1330                         sizeof (ECalBackendHttpClass),
1331                         (GBaseInitFunc) NULL,
1332                         (GBaseFinalizeFunc) NULL,
1333                         (GClassInitFunc) e_cal_backend_http_class_init,
1334                         NULL, NULL,
1335                         sizeof (ECalBackendHttp),
1336                         0,
1337                         (GInstanceInitFunc) e_cal_backend_http_init
1338                 };
1339                 e_cal_backend_http_type = g_type_register_static (E_TYPE_CAL_BACKEND_SYNC,
1340                                                                   "ECalBackendHttp", &info, 0);
1341         }
1342
1343         return e_cal_backend_http_type;
1344 }