[evolution-data-server/wip/offline-cache] Make ECalBackendHttp derive from ECalMetaBackend



commit 339974cb2fcdec74b5461bc0a92085fad88ba09b
Author: Milan Crha <mcrha redhat com>
Date:   Thu Mar 16 15:31:49 2017 +0100

    Make ECalBackendHttp derive from ECalMetaBackend

 src/calendar/backends/http/e-cal-backend-http.c | 1754 ++++++-----------------
 src/calendar/backends/http/e-cal-backend-http.h |    4 +-
 2 files changed, 458 insertions(+), 1300 deletions(-)
---
diff --git a/src/calendar/backends/http/e-cal-backend-http.c b/src/calendar/backends/http/e-cal-backend-http.c
index 1cb7f13..6d806c5 100644
--- a/src/calendar/backends/http/e-cal-backend-http.c
+++ b/src/calendar/backends/http/e-cal-backend-http.c
@@ -28,225 +28,26 @@
 #include <libedata-cal/libedata-cal.h>
 #include "e-cal-backend-http.h"
 
-#define E_CAL_BACKEND_HTTP_GET_PRIVATE(obj) \
-       (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_CAL_BACKEND_HTTP, ECalBackendHttpPrivate))
-
 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
 #define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
 
-G_DEFINE_TYPE (ECalBackendHttp, e_cal_backend_http, E_TYPE_CAL_BACKEND_SYNC)
+G_DEFINE_TYPE (ECalBackendHttp, e_cal_backend_http, E_TYPE_CAL_META_BACKEND)
 
-/* Private part of the ECalBackendHttp structure */
 struct _ECalBackendHttpPrivate {
-       /* signal handler id for source's 'changed' signal */
-       gulong source_changed_id;
-       /* URI to get remote calendar data from */
-       gchar *uri;
-
-       /* The file cache */
-       ECalBackendStore *store;
-
-       /* Soup handles for remote file */
        SoupSession *soup_session;
 
-       /* Reload */
-       guint reload_timeout_id;
-       guint is_loading : 1;
+       SoupRequestHTTP *request;
+       GInputStream *input_stream;
+       GHashTable *components; /* gchar *uid ~> icalcomponent * */
 
-       /* Flags */
-       gboolean opened;
-       gboolean requires_auth;
-
-       gchar *username;
-       gchar *password;
+       ENamedParameters *credentials;
 };
 
 #define d(x)
 
-static void    e_cal_backend_http_add_timezone (ECalBackendSync *backend,
-                                                EDataCal *cal,
-                                                GCancellable *cancellable,
-                                                const gchar *tzobj,
-                                                GError **perror);
-
-static void
-soup_authenticate (SoupSession *session,
-                   SoupMessage *msg,
-                   SoupAuth *auth,
-                   gboolean retrying,
-                   gpointer data)
-{
-       ECalBackendHttp *cbhttp;
-       ESourceAuthentication *auth_extension;
-       ESource *source;
-       const gchar *extension_name;
-       const gchar *username;
-       gchar *auth_user;
-
-       if (retrying)
-               return;
-
-       cbhttp = E_CAL_BACKEND_HTTP (data);
-
-       source = e_backend_get_source (E_BACKEND (data));
-       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
-       auth_extension = e_source_get_extension (source, extension_name);
-
-       auth_user = e_source_authentication_dup_user (auth_extension);
-
-       username = cbhttp->priv->username;
-       if (!username || !*username)
-               username = auth_user;
-
-       if (!username || !*username || !cbhttp->priv->password)
-               soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
-       else
-               soup_auth_authenticate (auth, username, cbhttp->priv->password);
-
-       g_free (auth_user);
-}
-
-/* Dispose handler for the file backend */
-static void
-e_cal_backend_http_dispose (GObject *object)
-{
-       ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-
-       cbhttp = E_CAL_BACKEND_HTTP (object);
-       priv = cbhttp->priv;
-
-       if (priv->reload_timeout_id) {
-               ESource *source = e_backend_get_source (E_BACKEND (cbhttp));
-               e_source_refresh_remove_timeout (source, priv->reload_timeout_id);
-               priv->reload_timeout_id = 0;
-       }
-
-       if (priv->soup_session) {
-               soup_session_abort (priv->soup_session);
-               g_object_unref (priv->soup_session);
-               priv->soup_session = NULL;
-       }
-       if (priv->source_changed_id) {
-               g_signal_handler_disconnect (
-                       e_backend_get_source (E_BACKEND (cbhttp)),
-                       priv->source_changed_id);
-               priv->source_changed_id = 0;
-       }
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->dispose (object);
-}
-
-/* Finalize handler for the file backend */
-static void
-e_cal_backend_http_finalize (GObject *object)
-{
-       ECalBackendHttpPrivate *priv;
-
-       priv = E_CAL_BACKEND_HTTP_GET_PRIVATE (object);
-
-       /* Clean up */
-
-       if (priv->store) {
-               g_object_unref (priv->store);
-               priv->store = NULL;
-       }
-
-       g_free (priv->uri);
-       g_free (priv->username);
-       g_free (priv->password);
-
-       /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->finalize (object);
-}
-
-static void
-e_cal_backend_http_constructed (GObject *object)
-{
-       ECalBackendHttp *backend;
-       SoupSession *soup_session;
-
-       /* Chain up to parent's constructed() method. */
-       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->constructed (object);
-
-       soup_session = soup_session_sync_new ();
-       g_object_set (
-               soup_session,
-               SOUP_SESSION_TIMEOUT, 90,
-               SOUP_SESSION_SSL_STRICT, TRUE,
-               SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
-               SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
-               NULL);
-
-       backend = E_CAL_BACKEND_HTTP (object);
-       backend->priv->soup_session = soup_session;
-
-       e_binding_bind_property (
-               backend, "proxy-resolver",
-               backend->priv->soup_session, "proxy-resolver",
-               G_BINDING_SYNC_CREATE);
-
-       g_signal_connect (
-               backend->priv->soup_session, "authenticate",
-               G_CALLBACK (soup_authenticate), backend);
-
-       if (g_getenv ("WEBCAL_DEBUG") != NULL) {
-               SoupLogger *logger;
-
-               logger = soup_logger_new (
-                       SOUP_LOGGER_LOG_BODY, 1024 * 1024);
-               soup_session_add_feature (
-                       backend->priv->soup_session,
-                       SOUP_SESSION_FEATURE (logger));
-               g_object_unref (logger);
-       }
-}
-
-/* Calendar backend methods */
-
 static gchar *
-e_cal_backend_http_get_backend_property (ECalBackend *backend,
-                                         const gchar *prop_name)
-{
-       g_return_val_if_fail (prop_name != NULL, NULL);
-
-       if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
-               return g_strjoin (
-                       ","
-                       CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS,
-                       CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED,
-                       NULL);
-
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
-                  g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
-               /* A HTTP backend has no particular email address associated
-                * with it (although that would be a useful feature some day).
-                */
-               return NULL;
-
-       } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
-               icalcomponent *icalcomp;
-               icalcomponent_kind kind;
-               gchar *prop_value;
-
-               kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
-               icalcomp = e_cal_util_new_component (kind);
-               prop_value = icalcomponent_as_ical_string_r (icalcomp);
-               icalcomponent_free (icalcomp);
-
-               return prop_value;
-       }
-
-       /* Chain up to parent's get_backend_property() method. */
-       return E_CAL_BACKEND_CLASS (e_cal_backend_http_parent_class)->
-               get_backend_property (backend, prop_name);
-}
-
-static gchar *
-webcal_to_http_method (const gchar *webcal_str,
-                       gboolean secure)
+ecb_http_webcal_to_http_method (const gchar *webcal_str,
+                               gboolean secure)
 {
        if (secure && (strncmp ("http://";, webcal_str, sizeof ("http://";) - 1) == 0))
                return g_strconcat ("https://";, webcal_str + sizeof ("http://";) - 1, NULL);
@@ -260,202 +61,44 @@ webcal_to_http_method (const gchar *webcal_str,
                return g_strconcat ("http://";, webcal_str + sizeof ("webcal://") - 1, NULL);
 }
 
-static gboolean
-notify_and_remove_from_cache (gpointer key,
-                              gpointer value,
-                              gpointer user_data)
-{
-       const gchar *calobj = value;
-       ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (user_data);
-       ECalComponent *comp = e_cal_component_new_from_string (calobj);
-       ECalComponentId *id = e_cal_component_get_id (comp);
-
-       if (id) {
-               e_cal_backend_store_remove_component (cbhttp->priv->store, id->uid, id->rid);
-               e_cal_backend_notify_component_removed (E_CAL_BACKEND (cbhttp), id, comp, NULL);
-
-               e_cal_component_free_id (id);
-       }
-
-       g_object_unref (comp);
-
-       return TRUE;
-}
-
-static void
-empty_cache (ECalBackendHttp *cbhttp)
-{
-       ECalBackendHttpPrivate *priv;
-       GSList *comps, *l;
-
-       priv = cbhttp->priv;
-
-       if (!priv->store)
-               return;
-
-       comps = e_cal_backend_store_get_components (priv->store);
-
-       for (l = comps; l != NULL; l = g_slist_next (l)) {
-               ECalComponentId *id;
-               ECalComponent *comp = l->data;
-
-               id = e_cal_component_get_id (comp);
-
-               e_cal_backend_notify_component_removed ((ECalBackend *) cbhttp, id, comp, NULL);
-
-               e_cal_component_free_id (id);
-               g_object_unref (comp);
-       }
-       g_slist_free (comps);
-
-       e_cal_backend_store_put_key_value (priv->store, "ETag", NULL);
-       e_cal_backend_store_clean (priv->store);
-}
-
-/* TODO Do not replicate this in every backend */
-static icaltimezone *
-resolve_tzid (const gchar *tzid,
-              gpointer user_data)
-{
-       ETimezoneCache *timezone_cache;
-
-       timezone_cache = E_TIMEZONE_CACHE (user_data);
-
-       return e_timezone_cache_get_timezone (timezone_cache, tzid);
-}
-
-static gboolean
-put_component_to_store (ECalBackendHttp *cb,
-                        ECalComponent *comp)
+static gchar *
+ecb_http_dup_uri (ECalBackendHttp *cbhttp)
 {
-       time_t time_start, time_end;
-       ECalBackendHttpPrivate *priv;
-       ECalComponent *cache_comp;
-       const gchar *uid;
-       gchar *rid;
-
-       priv = cb->priv;
-
-       e_cal_component_get_uid (comp, &uid);
-       rid = e_cal_component_get_recurid_as_string (comp);
-       cache_comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-       g_free (rid);
-
-       if (cache_comp) {
-               gboolean changed = TRUE;
-               struct icaltimetype stamp1, stamp2;
-
-               stamp1 = icaltime_null_time ();
-               stamp2 = icaltime_null_time ();
-
-               e_cal_component_get_dtstamp (comp, &stamp1);
-               e_cal_component_get_dtstamp (cache_comp, &stamp2);
-
-               changed = (icaltime_is_null_time (stamp1) && !icaltime_is_null_time (stamp2)) ||
-                         (!icaltime_is_null_time (stamp1) && icaltime_is_null_time (stamp2)) ||
-                         (icaltime_compare (stamp1, stamp2) != 0);
-
-               if (!changed) {
-                       struct icaltimetype *last_modified1 = NULL, *last_modified2 = NULL;
-
-                       e_cal_component_get_last_modified (comp, &last_modified1);
-                       e_cal_component_get_last_modified (cache_comp, &last_modified2);
-
-                       changed = (last_modified1 != NULL && last_modified2 == NULL) ||
-                                 (last_modified1 == NULL && last_modified2 != NULL) ||
-                                 (last_modified1 != NULL && last_modified2 != NULL && icaltime_compare 
(*last_modified1, *last_modified2) != 0);
-
-                       if (last_modified1)
-                               e_cal_component_free_icaltimetype (last_modified1);
-                       if (last_modified2)
-                               e_cal_component_free_icaltimetype (last_modified2);
-
-                       if (!changed) {
-                               gint *sequence1 = NULL, *sequence2 = NULL;
-
-                               e_cal_component_get_sequence (comp, &sequence1);
-                               e_cal_component_get_sequence (cache_comp, &sequence2);
-
-                               changed = (sequence1 != NULL && sequence2 == NULL) ||
-                                         (sequence1 == NULL && sequence2 != NULL) ||
-                                         (sequence1 != NULL && sequence2 != NULL && *sequence1 != 
*sequence2);
+       ESource *source;
+       ESourceSecurity *security_extension;
+       ESourceWebdav *webdav_extension;
+       SoupURI *soup_uri;
+       gboolean secure_connection;
+       const gchar *extension_name;
+       gchar *uri_string, *uri;
 
-                               if (sequence1)
-                                       e_cal_component_free_sequence (sequence1);
-                               if (sequence2)
-                                       e_cal_component_free_sequence (sequence2);
-                       }
-               }
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp), NULL);
 
-               g_object_unref (cache_comp);
+       source = e_backend_get_source (E_BACKEND (cbhttp));
 
-               if (!changed)
-                       return FALSE;
-       }
+       extension_name = E_SOURCE_EXTENSION_SECURITY;
+       security_extension = e_source_get_extension (source, extension_name);
 
-       e_cal_util_get_component_occur_times (
-               comp, &time_start, &time_end,
-               resolve_tzid, cb, icaltimezone_get_utc_timezone (),
-               e_cal_backend_get_kind (E_CAL_BACKEND (cb)));
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       webdav_extension = e_source_get_extension (source, extension_name);
 
-       e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
+       secure_connection = e_source_security_get_secure (security_extension);
 
-       return TRUE;
-}
+       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+       uri_string = soup_uri_to_string (soup_uri, FALSE);
+       soup_uri_free (soup_uri);
 
-static SoupMessage *
-cal_backend_http_new_message (ECalBackendHttp *backend,
-                              const gchar *uri)
-{
-       SoupMessage *soup_message;
-
-       /* create message to be sent to server */
-       soup_message = soup_message_new (SOUP_METHOD_GET, uri);
-       if (soup_message == NULL)
-               return NULL;
-
-       soup_message_headers_append (
-               soup_message->request_headers,
-               "User-Agent", "Evolution/" VERSION);
-       soup_message_headers_append (
-               soup_message->request_headers,
-               "Connection", "close");
-       soup_message_set_flags (
-               soup_message, SOUP_MESSAGE_NO_REDIRECT);
-       if (backend->priv->store != NULL) {
-               const gchar *etag;
-
-               etag = e_cal_backend_store_get_key_value (
-                       backend->priv->store, "ETag");
-
-               if (etag != NULL && *etag != '\0')
-                       soup_message_headers_append (
-                               soup_message->request_headers,
-                               "If-None-Match", etag);
-       }
+       uri = ecb_http_webcal_to_http_method (uri_string, secure_connection);
 
-       return soup_message;
-}
+       g_free (uri_string);
 
-static void
-cal_backend_http_cancelled (GCancellable *cancellable,
-                            gpointer user_data)
-{
-       struct {
-               SoupSession *soup_session;
-               SoupMessage *soup_message;
-       } *cancel_data = user_data;
-
-       soup_session_cancel_message (
-               cancel_data->soup_session,
-               cancel_data->soup_message,
-               SOUP_STATUS_CANCELLED);
+       return uri;
 }
 
 static void
-cal_backend_http_extract_ssl_failed_data (SoupMessage *msg,
-                                         gchar **out_certificate_pem,
-                                         GTlsCertificateFlags *out_certificate_errors)
+ecb_http_extract_ssl_failed_data (SoupMessage *msg,
+                                 gchar **out_certificate_pem,
+                                 GTlsCertificateFlags *out_certificate_errors)
 {
        GTlsCertificate *certificate = NULL;
 
@@ -475,1106 +118,621 @@ cal_backend_http_extract_ssl_failed_data (SoupMessage *msg,
        }
 }
 
-static gboolean
-cal_backend_http_load (ECalBackendHttp *backend,
-                       const gchar *uri,
-                      gchar **out_certificate_pem,
-                      GTlsCertificateFlags *out_certificate_errors,
-                       GCancellable *cancellable,
-                       GError **error)
+static void
+ecb_http_soup_authenticate (SoupSession *session,
+                           SoupMessage *msg,
+                           SoupAuth *auth,
+                           gboolean retrying,
+                           gpointer user_data)
 {
-       ECalBackendHttpPrivate *priv = backend->priv;
-       ETimezoneCache *timezone_cache;
-       SoupMessage *soup_message;
-       SoupSession *soup_session;
-       icalcomponent *icalcomp, *subcomp;
-       icalcomponent_kind kind;
-       const gchar *newuri;
-       SoupURI *uri_parsed;
-       GHashTable *old_cache;
-       GSList *comps_in_cache;
-       ESource *source;
-       guint status_code;
-       gulong cancel_id = 0;
-
-       struct {
-               SoupSession *soup_session;
-               SoupMessage *soup_message;
-       } cancel_data;
+       ECalBackendHttp *cbhttp;
+       const gchar *username;
+       gchar *auth_user = NULL;
 
-       timezone_cache = E_TIMEZONE_CACHE (backend);
+       if (retrying)
+               return;
 
-       soup_session = backend->priv->soup_session;
-       soup_message = cal_backend_http_new_message (backend, uri);
+       cbhttp = E_CAL_BACKEND_HTTP (user_data);
 
-       if (soup_message == NULL) {
-               g_set_error (
-                       error, SOUP_HTTP_ERROR,
-                       SOUP_STATUS_MALFORMED,
-                       _("Malformed URI: %s"), uri);
-               return FALSE;
-       }
+       username = cbhttp->priv->credentials ? e_named_parameters_get (cbhttp->priv->credentials, 
E_SOURCE_CREDENTIAL_USERNAME) : NULL;
+       if (!username || !*username) {
+               ESourceAuthentication *auth_extension;
+               ESource *source;
 
-       if (G_IS_CANCELLABLE (cancellable)) {
-               cancel_data.soup_session = soup_session;
-               cancel_data.soup_message = soup_message;
+               source = e_backend_get_source (E_BACKEND (cbhttp));
+               auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+               auth_user = e_source_authentication_dup_user (auth_extension);
 
-               cancel_id = g_cancellable_connect (
-                       cancellable,
-                       G_CALLBACK (cal_backend_http_cancelled),
-                       &cancel_data, (GDestroyNotify) NULL);
+               username = auth_user;
        }
 
-       source = e_backend_get_source (E_BACKEND (backend));
-
-       e_soup_ssl_trust_connect (soup_message, source);
+       if (!username || !*username || !cbhttp->priv->credentials ||
+           !e_named_parameters_exists (cbhttp->priv->credentials, E_SOURCE_CREDENTIAL_PASSWORD))
+               soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
+       else
+               soup_auth_authenticate (auth, username, e_named_parameters_get (cbhttp->priv->credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
 
-       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+       g_free (auth_user);
+}
 
-       status_code = soup_session_send_message (soup_session, soup_message);
+static gboolean
+ecb_http_connect_sync (ECalMetaBackend *meta_backend,
+                      const ENamedParameters *credentials,
+                      ESourceAuthenticationResult *out_auth_result,
+                      gchar **out_certificate_pem,
+                      GTlsCertificateFlags *out_certificate_errors,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       ECalBackendHttp *cbhttp;
+       ESource *source;
+       SoupRequestHTTP *request;
+       GInputStream *input_stream = NULL;
+       gchar *uri;
+       gboolean success;
+       GError *local_error = NULL;
 
-       if (G_IS_CANCELLABLE (cancellable))
-               g_cancellable_disconnect (cancellable, cancel_id);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
+       g_return_val_if_fail (out_auth_result != NULL, FALSE);
 
-       if (status_code == SOUP_STATUS_NOT_MODIFIED) {
-               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+       cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
-               /* attempts with ETag can result in 304 status code */
-               g_object_unref (soup_message);
-               priv->opened = TRUE;
+       if (cbhttp->priv->request && cbhttp->priv->input_stream)
                return TRUE;
-       }
 
-       /* Handle redirection ourselves */
-       if (SOUP_STATUS_IS_REDIRECTION (status_code)) {
-               gboolean success;
+       source = e_backend_get_source (E_BACKEND (meta_backend));
 
-               newuri = soup_message_headers_get_list (
-                       soup_message->response_headers, "Location");
+       g_clear_object (&cbhttp->priv->input_stream);
+       g_clear_object (&cbhttp->priv->request);
 
-               d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri));
+       uri = ecb_http_dup_uri (cbhttp);
 
-               if (newuri != NULL) {
-                       gchar *redirected_uri;
+       if (!uri || !*uri) {
+               g_free (uri);
 
-                       if (newuri[0]=='/') {
-                               g_warning ("Hey! Relative URI returned! Working around...\n");
-
-                               uri_parsed = soup_uri_new (uri);
-                               soup_uri_set_path (uri_parsed, newuri);
-                               soup_uri_set_query (uri_parsed, NULL);
-                               /* g_free (newuri); */
-
-                               newuri = soup_uri_to_string (uri_parsed, FALSE);
-                               g_message ("Translated URI: %s\n", newuri);
-                               soup_uri_free (uri_parsed);
-                       }
-
-                       redirected_uri =
-                               webcal_to_http_method (newuri, FALSE);
-                       success = cal_backend_http_load (
-                               backend, redirected_uri, out_certificate_pem, out_certificate_errors, 
cancellable, error);
-                       g_free (redirected_uri);
-
-               } else {
-                       g_set_error (
-                               error, SOUP_HTTP_ERROR,
-                               SOUP_STATUS_BAD_REQUEST,
-                               _("Redirected to Invalid URI"));
-                       success = FALSE;
-               }
-
-               if (success) {
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
-               } else {
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-               }
-
-               g_object_unref (soup_message);
-               return success;
-       }
-
-       /* check status code */
-       if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
-               /* because evolution knows only G_IO_ERROR_CANCELLED */
-               if (status_code == SOUP_STATUS_CANCELLED)
-                       g_set_error (
-                               error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                               "%s", soup_message->reason_phrase);
-               else
-                       g_set_error (
-                               error, SOUP_HTTP_ERROR, status_code,
-                               "%s", soup_message->reason_phrase);
-
-               if (status_code == SOUP_STATUS_SSL_FAILED) {
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
-                       cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, 
out_certificate_errors);
-               } else {
-                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
-               }
-
-               g_object_unref (soup_message);
-               empty_cache (backend);
+               g_propagate_error (error, EDC_ERROR_EX (OtherError, _("URI not set")));
                return FALSE;
        }
 
-       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
-
-       if (priv->store) {
-               const gchar *etag;
-
-               etag = soup_message_headers_get_one (
-                       soup_message->response_headers, "ETag");
-
-               if (etag != NULL && *etag == '\0')
-                       etag = NULL;
-
-               e_cal_backend_store_put_key_value (priv->store, "ETag", etag);
-       }
-
-       /* get the calendar from the response */
-       icalcomp = icalparser_parse_string (soup_message->response_body->data);
-
-       if (!icalcomp) {
-               g_set_error (
-                       error, SOUP_HTTP_ERROR,
-                       SOUP_STATUS_MALFORMED,
-                       _("Bad file format."));
-               g_object_unref (soup_message);
-               empty_cache (backend);
-               return FALSE;
-       }
-
-       if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
-               g_set_error (
-                       error, SOUP_HTTP_ERROR,
-                       SOUP_STATUS_MALFORMED,
-                       _("Not a calendar."));
-               icalcomponent_free (icalcomp);
-               g_object_unref (soup_message);
-               empty_cache (backend);
-               return FALSE;
-       }
-
-       g_object_unref (soup_message);
-       soup_message = NULL;
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
 
-       /* Update cache */
-       old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+       e_named_parameters_free (cbhttp->priv->credentials);
+       cbhttp->priv->credentials = credentials ? e_named_parameters_new_clone (credentials) : NULL;
 
-       comps_in_cache = e_cal_backend_store_get_components (priv->store);
-       while (comps_in_cache != NULL) {
-               const gchar *uid;
-               ECalComponent *comp = comps_in_cache->data;
+       request = soup_session_request_http (cbhttp->priv->soup_session, SOUP_METHOD_GET, uri, &local_error);
+       success = request != NULL;
 
-               e_cal_component_get_uid (comp, &uid);
-               g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp));
+       if (success) {
+               SoupMessage *message;
 
-               comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data);
-               g_object_unref (comp);
-       }
-
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
-       subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
-       e_cal_backend_store_freeze_changes (priv->store);
-       while (subcomp) {
-               ECalComponent *comp;
-               icalcomponent_kind subcomp_kind;
-               icalproperty *prop = NULL;
-
-               subcomp_kind = icalcomponent_isa (subcomp);
-               prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY);
-               if (!prop && subcomp_kind == kind) {
-                       gchar *new_uid = e_cal_component_gen_uid ();
-                       icalcomponent_set_uid (subcomp, new_uid);
-                       g_free (new_uid);
+               message = soup_request_http_get_message (request);
+               if (message) {
+                       soup_message_headers_append (message->request_headers, "User-Agent", "Evolution/" 
VERSION);
+                       soup_message_headers_append (message->request_headers, "Connection", "close");
                }
 
-               if (subcomp_kind == kind) {
-                       comp = e_cal_component_new ();
-                       if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) {
-                               const gchar *uid;
-                               gpointer orig_key, orig_value;
+               input_stream = soup_request_send (SOUP_REQUEST (request), cancellable, &local_error);
 
-                               e_cal_component_get_uid (comp, &uid);
+               success = input_stream != NULL;
 
-                               if (!put_component_to_store (backend, comp)) {
-                                       g_hash_table_remove (old_cache, uid);
-                               } else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, 
&orig_value)) {
-                                       ECalComponent *orig_comp = e_cal_component_new_from_string 
(orig_value);
-
-                                       e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), 
orig_comp, comp);
+               if (success && message && !SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+                       g_clear_object (&input_stream);
+                       success = FALSE;
+               }
 
-                                       g_hash_table_remove (old_cache, uid);
-                                       if (orig_comp)
-                                               g_object_unref (orig_comp);
-                               } else {
-                                       e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), 
comp);
-                               }
+               if (success) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+               } else {
+                       guint status_code = message ? message->status_code : SOUP_STATUS_MALFORMED;
+                       gboolean credentials_empty;
+
+                       credentials_empty = !credentials || !e_named_parameters_count (credentials);
+
+                       *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
+
+                       /* because evolution knows only G_IO_ERROR_CANCELLED */
+                       if (status_code == SOUP_STATUS_CANCELLED) {
+                               g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+                                       "%s", message->reason_phrase);
+                       } else if (status_code == SOUP_STATUS_FORBIDDEN && credentials_empty) {
+                               *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
+                       } else if (status_code == SOUP_STATUS_UNAUTHORIZED ||
+                                  status_code == SOUP_STATUS_FORBIDDEN) {
+                               *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
+                       } else if (local_error) {
+                               g_propagate_error (error, local_error);
+                               local_error = NULL;
+                       } else {
+                               g_set_error (error, SOUP_HTTP_ERROR, status_code,
+                                       "%s", message ? message->reason_phrase : soup_status_get_phrase 
(status_code));
                        }
 
-                       g_object_unref (comp);
-               } else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) {
-                       icaltimezone *zone;
+                       if (status_code == SOUP_STATUS_SSL_FAILED) {
+                               *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
-                       zone = icaltimezone_new ();
-                       icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp));
-                       e_timezone_cache_add_timezone (timezone_cache, zone);
-
-                       icaltimezone_free (zone, 1);
+                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
+                               if (message)
+                                       ecb_http_extract_ssl_failed_data (message, out_certificate_pem, 
out_certificate_errors);
+                       } else {
+                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+                       }
                }
 
-               subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT);
-       }
+               g_clear_object (&message);
+       } else {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 
-       e_cal_backend_store_thaw_changes (priv->store);
+               g_set_error (error, E_DATA_CAL_ERROR, OtherError, _("Malformed URI ā€œ%sā€œ: %s"),
+                       uri, local_error ? local_error->message : _("Unknown error"));
+       }
 
-       /* notify the removals */
-       g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend);
-       g_hash_table_destroy (old_cache);
+       if (success) {
+               cbhttp->priv->request = request;
+               cbhttp->priv->input_stream = input_stream;
 
-       /* free memory */
-       icalcomponent_free (icalcomp);
+               *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+       } else {
+               g_clear_object (&request);
+               g_clear_object (&input_stream);
+       }
 
-       priv->opened = TRUE;
+       g_clear_error (&local_error);
+       g_free (uri);
 
-       return TRUE;
+       return success;
 }
 
-static const gchar *
-cal_backend_http_ensure_uri (ECalBackendHttp *backend)
+static gboolean
+ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
+                         GCancellable *cancellable,
+                         GError **error)
 {
+       ECalBackendHttp *cbhttp;
        ESource *source;
-       ESourceSecurity *security_extension;
-       ESourceWebdav *webdav_extension;
-       SoupURI *soup_uri;
-       gboolean secure_connection;
-       const gchar *extension_name;
-       gchar *uri_string;
 
-       if (backend->priv->uri != NULL)
-               return backend->priv->uri;
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
 
-       source = e_backend_get_source (E_BACKEND (backend));
+       cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
-       extension_name = E_SOURCE_EXTENSION_SECURITY;
-       security_extension = e_source_get_extension (source, extension_name);
+       if (cbhttp->priv->soup_session)
+               soup_session_abort (cbhttp->priv->soup_session);
 
-       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
-       webdav_extension = e_source_get_extension (source, extension_name);
+       g_clear_object (&cbhttp->priv->input_stream);
+       g_clear_object (&cbhttp->priv->request);
 
-       secure_connection = e_source_security_get_secure (security_extension);
-
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-       uri_string = soup_uri_to_string (soup_uri, FALSE);
-       soup_uri_free (soup_uri);
-
-       backend->priv->uri = webcal_to_http_method (
-               uri_string, secure_connection);
+       if (cbhttp->priv->components) {
+               g_hash_table_destroy (cbhttp->priv->components);
+               cbhttp->priv->components = NULL;
+       }
 
-       g_free (uri_string);
+       source = e_backend_get_source (E_BACKEND (meta_backend));
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 
-       return backend->priv->uri;
+       return TRUE;
 }
 
-static void
-begin_retrieval_cb (GTask *task,
-                   gpointer source_object,
-                   gpointer task_tada,
-                   GCancellable *cancellable)
+static gchar *
+ecb_http_read_stream_sync (GInputStream *input_stream,
+                          goffset expected_length,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-       ECalBackendHttp *backend = source_object;
-       const gchar *uri;
-       gchar *certificate_pem = NULL;
-       GTlsCertificateFlags certificate_errors = 0;
-       GError *error = NULL;
-
-       if (!e_backend_get_online (E_BACKEND (backend)) ||
-           backend->priv->is_loading)
-               return;
-
-       d (g_message ("Starting retrieval...\n"));
+       GString *icalstr;
+       void *buffer;
+       gsize nread = 0;
+       gboolean success = FALSE;
 
-       backend->priv->is_loading = TRUE;
+       g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL);
 
-       uri = cal_backend_http_ensure_uri (backend);
-       cal_backend_http_load (backend, uri, &certificate_pem, &certificate_errors, cancellable, &error);
+       icalstr = g_string_sized_new (expected_length > 0 ? expected_length + 1 : 1024);
 
-       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-           g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
-               GError *local_error = NULL;
-               ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+       buffer = g_malloc (16384);
 
-               if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
-                       reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
-               }
-
-               e_backend_credentials_required_sync (E_BACKEND (backend),
-                       reason, certificate_pem, certificate_errors, error, cancellable, &local_error);
-
-               g_clear_error (&error);
-               error = local_error;
-       } else if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-               GError *local_error = NULL;
-
-               e_backend_credentials_required_sync (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_REJECTED,
-                       certificate_pem, certificate_errors, error, cancellable, &local_error);
-
-               g_clear_error (&error);
-               error = local_error;
+       while (success = g_input_stream_read_all (input_stream, buffer, 16384, &nread, cancellable, error),
+              success && nread > 0) {
+               g_string_append_len (icalstr, (const gchar *) buffer, nread);
        }
 
-       g_free (certificate_pem);
-       backend->priv->is_loading = FALSE;
-
-       /* Ignore cancellations. */
-       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_error_free (error);
-
-       } else if (error != NULL) {
-               e_cal_backend_notify_error (
-                       E_CAL_BACKEND (backend),
-                       error->message);
-               empty_cache (backend);
-               g_error_free (error);
-       }
+       g_free (buffer);
 
-       d (g_message ("Retrieval really done.\n"));
+       return g_string_free (icalstr, !success);
 }
 
 static void
-http_cal_schedule_begin_retrieval (ECalBackendHttp *cbhttp)
+ecb_http_gather_uids_cb (gpointer uid,
+                        gpointer icalcomp,
+                        gpointer user_data)
 {
-       GTask *task;
+       GHashTable *hash_table = user_data;
 
-       task = g_task_new (cbhttp, NULL, NULL, NULL);
+       g_return_if_fail (hash_table != NULL);
 
-       g_task_run_in_thread (task, begin_retrieval_cb);
-
-       g_object_unref (task);
+       if (uid)
+               g_hash_table_insert (hash_table, g_strdup (uid), NULL);
 }
 
-static void
-source_changed_cb (ESource *source,
-                   ECalBackendHttp *cbhttp)
+static gboolean
+ecb_http_remove_unchanged_cb (gpointer uid,
+                             gpointer icalcomp,
+                             gpointer user_data)
 {
-       g_return_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp));
+       GHashTable *unchanged = user_data;
 
-       g_object_ref (cbhttp);
+       g_return_val_if_fail (unchanged != NULL, FALSE);
 
-       if (cbhttp->priv->uri != NULL) {
-               gboolean uri_changed;
-               const gchar *new_uri;
-               gchar *old_uri;
-
-               old_uri = g_strdup (cbhttp->priv->uri);
-
-               g_free (cbhttp->priv->uri);
-               cbhttp->priv->uri = NULL;
+       return !uid || g_hash_table_contains (unchanged, uid);
+}
 
-               new_uri = cal_backend_http_ensure_uri (cbhttp);
+static gboolean
+ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
+                          const gchar *last_sync_tag,
+                          gchar **out_new_sync_tag,
+                          gboolean *out_repeat,
+                          GSList **out_created_objects,
+                          GSList **out_modified_objects,
+                          GSList **out_removed_objects,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       ECalBackendHttp *cbhttp;
+       SoupMessage *message;
+       gchar *icalstring;
+       icalcomponent *vcalendar;
+       gboolean success = TRUE;
 
-               uri_changed = (g_strcmp0 (old_uri, new_uri) != 0);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
+       g_return_val_if_fail (out_new_sync_tag != NULL, FALSE);
+       g_return_val_if_fail (out_created_objects != NULL, FALSE);
+       g_return_val_if_fail (out_modified_objects != NULL, FALSE);
+       g_return_val_if_fail (out_removed_objects != NULL, FALSE);
 
-               if (uri_changed && !cbhttp->priv->is_loading)
-                       http_cal_schedule_begin_retrieval (cbhttp);
+       cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
-               g_free (old_uri);
+       if (!cbhttp->priv->request || !cbhttp->priv->input_stream) {
+               g_propagate_error (error, EDC_ERROR (RepositoryOffline));
+               return FALSE;
        }
 
-       g_object_unref (cbhttp);
-}
-
-static void
-http_cal_reload_cb (ESource *source,
-                    gpointer user_data)
-{
-       ECalBackendHttp *cbhttp = user_data;
+       message = soup_request_http_get_message (cbhttp->priv->request);
+       if (message) {
+               const gchar *new_etag;
 
-       g_return_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp));
+               new_etag = soup_message_headers_get_one (message->response_headers, "ETag");
+               if (new_etag && !*new_etag) {
+                       new_etag = NULL;
+               } else if (g_strcmp0 (last_sync_tag, new_etag) == 0) {
+                       /* Nothing changed */
+                       g_object_unref (message);
 
-       if (!e_backend_get_online (E_BACKEND (cbhttp)))
-               return;
+                       ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
 
-       http_cal_schedule_begin_retrieval (cbhttp);
-}
+                       return TRUE;
+               }
 
-/* Open handler for the file backend */
-static void
-e_cal_backend_http_open (ECalBackendSync *backend,
-                         EDataCal *cal,
-                         GCancellable *cancellable,
-                         gboolean only_if_exists,
-                         GError **perror)
-{
-       ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       ESource *source;
-       ESourceWebdav *webdav_extension;
-       const gchar *extension_name;
-       const gchar *cache_dir;
-       gboolean opened = TRUE;
-       gchar *tmp;
-       GError *local_error = NULL;
+               *out_new_sync_tag = g_strdup (new_etag);
+       }
 
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
+       g_clear_object (&message);
 
-       /* already opened, thus can skip all this initialization */
-       if (priv->opened)
-               return;
+       icalstring = ecb_http_read_stream_sync (cbhttp->priv->input_stream,
+               soup_request_get_content_length (SOUP_REQUEST (cbhttp->priv->request)), cancellable, error);
 
-       source = e_backend_get_source (E_BACKEND (backend));
-       cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));
+       if (!icalstring) {
+               /* The error is already set */
+               e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+               return FALSE;
+       }
 
-       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
-       webdav_extension = e_source_get_extension (source, extension_name);
+       vcalendar = icalparser_parse_string (icalstring);
 
-       e_source_webdav_unset_temporary_ssl_trust (webdav_extension);
+       g_free (icalstring);
 
-       if (priv->source_changed_id == 0) {
-               priv->source_changed_id = g_signal_connect (
-                       source, "changed",
-                       G_CALLBACK (source_changed_cb), cbhttp);
+       if (!vcalendar) {
+               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Bad file format."));
+               e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+               return FALSE;
        }
 
-       /* always read uri again */
-       tmp = priv->uri;
-       priv->uri = NULL;
-       g_free (tmp);
-
-       if (priv->store == NULL) {
-               /* remove the old cache while migrating to ECalBackendStore */
-               e_cal_backend_cache_remove (cache_dir, "cache.xml");
-               priv->store = e_cal_backend_store_new (
-                       cache_dir, E_TIMEZONE_CACHE (backend));
-               e_cal_backend_store_load (priv->store);
-
-               if (!priv->store) {
-                       g_propagate_error (
-                               perror, EDC_ERROR_EX (OtherError,
-                               _("Could not create cache file")));
-                       return;
-               }
+       if (icalcomponent_isa (vcalendar) != ICAL_VCALENDAR_COMPONENT) {
+               icalcomponent_free (vcalendar);
+               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Not a calendar."));
+               e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+               return FALSE;
        }
 
-       e_cal_backend_set_writable (E_CAL_BACKEND (backend), FALSE);
+       success = e_cal_meta_backend_gather_timezones_sync (meta_backend, vcalendar, TRUE, cancellable, 
error);
+       if (success) {
+               icalcomponent_kind kind = e_cal_backend_get_kind (E_CAL_BACKEND (meta_backend));
+               icalcomponent *subcomp;
+               GHashTable *components;
 
-       if (e_backend_get_online (E_BACKEND (backend))) {
-               gchar *certificate_pem = NULL;
-               GTlsCertificateFlags certificate_errors = 0;
-               const gchar *uri;
+               components = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) 
icalcomponent_free);
 
-               uri = cal_backend_http_ensure_uri (cbhttp);
+               while (subcomp = icalcomponent_get_first_component (vcalendar, kind), subcomp) {
+                       icalcomponent *existing_icalcomp;
+                       gpointer orig_key, orig_value;
+                       const gchar *uid;
 
-               opened = cal_backend_http_load (cbhttp, uri, &certificate_pem,
-                       &certificate_errors, cancellable, &local_error);
+                       icalcomponent_remove_component (vcalendar, subcomp);
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) ||
-                   (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) &&
-                   !cbhttp->priv->password)) {
-                       GError *local_error2 = NULL;
-                       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+                       if (!icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY)) {
+                               gchar *new_uid = e_cal_component_gen_uid ();
+                               icalcomponent_set_uid (subcomp, new_uid);
+                               g_free (new_uid);
+                       }
 
-                       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
-                               reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+                       uid = icalcomponent_get_uid (subcomp);
+
+                       if (!g_hash_table_lookup_extended (components, uid, &orig_key, &orig_value)) {
+                               orig_key = NULL;
+                               orig_value = NULL;
                        }
 
-                       e_backend_credentials_required_sync (E_BACKEND (cbhttp), reason, certificate_pem,
-                               certificate_errors, local_error, cancellable, &local_error2);
-                       g_clear_error (&local_error);
-                       local_error = local_error2;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-                       GError *local_error2 = NULL;
+                       existing_icalcomp = orig_value;
+                       if (existing_icalcomp) {
+                               if (icalcomponent_isa (existing_icalcomp) != ICAL_VCALENDAR_COMPONENT) {
+                                       icalcomponent *vcal;
 
-                       e_backend_credentials_required_sync (E_BACKEND (cbhttp), 
E_SOURCE_CREDENTIALS_REASON_REJECTED,
-                               certificate_pem, certificate_errors, local_error, cancellable, &local_error2);
+                                       vcal = e_cal_util_new_top_level ();
 
-                       g_clear_error (&local_error);
-                       local_error = local_error2;
-               }
+                                       g_warn_if_fail (g_hash_table_steal (components, uid));
 
-               g_free (certificate_pem);
+                                       icalcomponent_add_component (vcal, existing_icalcomp);
+                                       g_hash_table_insert (components, g_strdup (uid), vcal);
 
-               if (local_error != NULL)
-                       g_propagate_error (perror, local_error);
-       }
+                                       g_free (orig_key);
 
-       if (opened) {
-               if (!priv->reload_timeout_id)
-                       priv->reload_timeout_id = e_source_refresh_add_timeout (source, NULL, 
http_cal_reload_cb, backend, NULL);
-       }
-}
+                                       existing_icalcomp = vcal;
+                               }
 
-static void
-e_cal_backend_http_refresh (ECalBackendSync *backend,
-                            EDataCal *cal,
-                            GCancellable *cancellable,
-                            GError **perror)
-{
-       ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       ESource *source;
+                               icalcomponent_add_component (existing_icalcomp, subcomp);
+                       } else {
+                               g_hash_table_insert (components, g_strdup (uid), subcomp);
+                       }
+               }
 
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
+               cbhttp->priv->components = components;
 
-       if (!priv->opened ||
-           priv->is_loading)
-               return;
+               icalcomponent_free (vcalendar);
 
-       source = e_backend_get_source (E_BACKEND (cbhttp));
-       g_return_if_fail (source != NULL);
+               success = E_CAL_META_BACKEND_CLASS (e_cal_backend_http_parent_class)->get_changes_sync 
(meta_backend,
+                       last_sync_tag, out_new_sync_tag, out_repeat, out_created_objects,
+                       out_modified_objects, out_removed_objects, cancellable, error);
 
-       e_source_refresh_force_timeout (source);
-}
+               if (success) {
+                       GHashTable *unchanged;
+                       GSList *link;
 
-/* Set_mode handler for the http backend */
-static void
-e_cal_backend_http_notify_online_cb (ECalBackend *backend,
-                                     GParamSpec *pspec)
-{
-       gboolean loaded;
-       gboolean online;
+                       unchanged = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+                       g_hash_table_foreach (cbhttp->priv->components, ecb_http_gather_uids_cb, unchanged);
 
-       online = e_backend_get_online (E_BACKEND (backend));
-       loaded = e_cal_backend_is_opened (backend);
+                       for (link = *out_created_objects; link; link = g_slist_next (link)) {
+                               ECalMetaBackendInfo *nfo = link->data;
 
-       if (online && loaded)
-               http_cal_schedule_begin_retrieval (E_CAL_BACKEND_HTTP (backend));
-}
+                               if (nfo && nfo->uid)
+                                       g_hash_table_remove (unchanged, nfo->uid);
+                       }
 
-/* Get_object_component handler for the http backend */
-static void
-e_cal_backend_http_get_object (ECalBackendSync *backend,
-                               EDataCal *cal,
-                               GCancellable *cancellable,
-                               const gchar *uid,
-                               const gchar *rid,
-                               gchar **object,
-                               GError **error)
-{
-       ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       ECalComponent *comp = NULL;
+                       for (link = *out_modified_objects; link; link = g_slist_next (link)) {
+                               ECalMetaBackendInfo *nfo = link->data;
 
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
+                               if (nfo && nfo->uid)
+                                       g_hash_table_remove (unchanged, nfo->uid);
+                       }
 
-       if (!priv->store) {
-               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-               return;
-       }
+                       if (g_hash_table_size (unchanged))
+                               g_hash_table_foreach_remove (cbhttp->priv->components, 
ecb_http_remove_unchanged_cb, unchanged);
 
-       if (rid && *rid) {
-               comp = e_cal_backend_store_get_component (priv->store, uid, rid);
-               if (!comp) {
-                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-                       return;
+                       g_hash_table_destroy (unchanged);
                }
-
-               *object = e_cal_component_get_as_string (comp);
-               g_object_unref (comp);
        } else {
-               *object = e_cal_backend_store_get_components_by_uid_as_ical_string (priv->store, uid);
-               if (!*object)
-                       g_propagate_error (error, EDC_ERROR (ObjectNotFound));
-       }
-}
-
-/* Add_timezone handler for the file backend */
-static void
-e_cal_backend_http_add_timezone (ECalBackendSync *backend,
-                                 EDataCal *cal,
-                                 GCancellable *cancellable,
-                                 const gchar *tzobj,
-                                 GError **error)
-{
-       ETimezoneCache *timezone_cache;
-       icalcomponent *tz_comp;
-       icaltimezone *zone;
-
-       timezone_cache = E_TIMEZONE_CACHE (backend);
-
-       tz_comp = icalparser_parse_string (tzobj);
-       if (!tz_comp) {
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
+               icalcomponent_free (vcalendar);
        }
 
-       if (icalcomponent_isa (tz_comp) != ICAL_VTIMEZONE_COMPONENT) {
-               icalcomponent_free (tz_comp);
-               g_propagate_error (error, EDC_ERROR (InvalidObject));
-               return;
-       }
+       if (!success)
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
 
-       zone = icaltimezone_new ();
-       icaltimezone_set_component (zone, tz_comp);
-       e_timezone_cache_add_timezone (timezone_cache, zone);
+       return success;
 }
 
-/* Get_objects_in_range handler for the file backend */
-static void
-e_cal_backend_http_get_object_list (ECalBackendSync *backend,
-                                    EDataCal *cal,
-                                    GCancellable *cancellable,
-                                    const gchar *sexp,
-                                    GSList **objects,
-                                    GError **perror)
+static gboolean
+ecb_http_list_existing_sync (ECalMetaBackend *meta_backend,
+                            gchar **out_new_sync_tag,
+                            GSList **out_existing_objects, /* ECalMetaBackendInfo * */
+                            GCancellable *cancellable,
+                            GError **error)
 {
        ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       GSList *components, *l;
-       ECalBackendSExp *cbsexp;
-       ETimezoneCache *timezone_cache;
-       time_t occur_start = -1, occur_end = -1;
-       gboolean prunning_by_time;
-
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
-
-       timezone_cache = E_TIMEZONE_CACHE (backend);
-
-       if (!priv->store) {
-               g_propagate_error (perror, EDC_ERROR (NoSuchCal));
-               return;
-       }
-
-       /* process all components in the cache */
-       cbsexp = e_cal_backend_sexp_new (sexp);
-
-       *objects = NULL;
-       prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (
-               cbsexp,
-               &occur_start,
-               &occur_end);
-
-       components = prunning_by_time ?
-               e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
-               : e_cal_backend_store_get_components (priv->store);
+       ECalCache *cal_cache;
+       icalcomponent_kind kind;
+       GHashTableIter iter;
+       gpointer key, value;
 
-       for (l = components; l != NULL; l = g_slist_next (l)) {
-               if (e_cal_backend_sexp_match_comp (cbsexp, E_CAL_COMPONENT (l->data), timezone_cache)) {
-                       *objects = g_slist_append (*objects, e_cal_component_get_as_string (l->data));
-               }
-       }
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
+       g_return_val_if_fail (out_existing_objects != NULL, FALSE);
 
-       g_slist_foreach (components, (GFunc) g_object_unref, NULL);
-       g_slist_free (components);
-       g_object_unref (cbsexp);
-}
+       cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
-static void
-e_cal_backend_http_start_view (ECalBackend *backend,
-                               EDataCalView *query)
-{
-       ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       GSList *components, *l;
-       GSList *objects = NULL;
-       ECalBackendSExp *cbsexp;
-       ETimezoneCache *timezone_cache;
-       time_t occur_start = -1, occur_end = -1;
-       gboolean prunning_by_time;
+       *out_existing_objects = NULL;
 
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
+       g_return_val_if_fail (cbhttp->priv->components != NULL, FALSE);
 
-       timezone_cache = E_TIMEZONE_CACHE (backend);
+       cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+       g_return_val_if_fail (cal_cache != NULL, FALSE);
 
-       cbsexp = e_data_cal_view_get_sexp (query);
+       kind = e_cal_backend_get_kind (E_CAL_BACKEND (meta_backend));
 
-       d (g_message (G_STRLOC ": Starting query (%s)", e_cal_backend_sexp_text (cbsexp)));
+       g_hash_table_iter_init (&iter, cbhttp->priv->components);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               icalcomponent *icalcomp = value;
+               ECalMetaBackendInfo *nfo;
+               const gchar *uid;
+               gchar *revision;
 
-       if (!priv->store) {
-               GError *error = EDC_ERROR (NoSuchCal);
-               e_data_cal_view_notify_complete (query, error);
-               g_error_free (error);
-               return;
-       }
+               if (icalcomp && icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT)
+                       icalcomp = icalcomponent_get_first_component (icalcomp, kind);
 
-       /* process all components in the cache */
-       objects = NULL;
-       prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (
-               cbsexp,
-               &occur_start,
-               &occur_end);
+               if (!icalcomp)
+                       continue;
 
-       components = prunning_by_time ?
-               e_cal_backend_store_get_components_occuring_in_range (priv->store, occur_start, occur_end)
-               : e_cal_backend_store_get_components (priv->store);
+               uid = icalcomponent_get_uid (icalcomp);
+               revision = e_cal_cache_dup_component_revision (cal_cache, icalcomp);
 
-       for (l = components; l != NULL; l = g_slist_next (l)) {
-               ECalComponent *comp = l->data;
+               nfo = e_cal_meta_backend_info_new (uid, NULL, revision);
+               *out_existing_objects = g_slist_prepend (*out_existing_objects, nfo);
 
-               if (e_cal_backend_sexp_match_comp (cbsexp, comp, timezone_cache)) {
-                       objects = g_slist_append (objects, comp);
-               }
+               g_free (revision);
        }
 
-       e_data_cal_view_notify_components_added (query, objects);
-
-       g_slist_free_full (components, g_object_unref);
-       g_slist_free (objects);
+       g_object_unref (cal_cache);
 
-       e_data_cal_view_notify_complete (query, NULL /* Success */);
+       return TRUE;
 }
 
-/***** static icaltimezone *
-resolve_tzid (const gchar *tzid,
- *            gpointer user_data)
-{
-       icalcomponent *vcalendar_comp = user_data;
- *
-       if (!tzid || !tzid[0])
-               return NULL;
- *      else if (!strcmp (tzid, "UTC"))
-               return icaltimezone_get_utc_timezone ();
- *
-       return icalcomponent_get_timezone (vcalendar_comp, tzid);
-} *****/
-
 static gboolean
-free_busy_instance (ECalComponent *comp,
-                    time_t instance_start,
-                    time_t instance_end,
-                    gpointer data)
+ecb_http_load_component_sync (ECalMetaBackend *meta_backend,
+                             const gchar *uid,
+                             icalcomponent **out_component,
+                             gchar **out_extra,
+                             GCancellable *cancellable,
+                             GError **error)
 {
-       icalcomponent *vfb = data;
-       icalproperty *prop;
-       icalparameter *param;
-       struct icalperiodtype ipt;
-       icaltimezone *utc_zone;
-
-       utc_zone = icaltimezone_get_utc_timezone ();
-
-       ipt.start = icaltime_from_timet_with_zone (instance_start, FALSE, utc_zone);
-       ipt.end = icaltime_from_timet_with_zone (instance_end, FALSE, utc_zone);
-       ipt.duration = icaldurationtype_null_duration ();
+       ECalBackendHttp *cbhttp;
+       gpointer key = NULL, value = NULL;
 
-        /* add busy information to the vfb component */
-       prop = icalproperty_new (ICAL_FREEBUSY_PROPERTY);
-       icalproperty_set_freebusy (prop, ipt);
+       g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
+       g_return_val_if_fail (uid != NULL, FALSE);
+       g_return_val_if_fail (out_component != NULL, FALSE);
 
-       param = icalparameter_new_fbtype (ICAL_FBTYPE_BUSY);
-       icalproperty_add_parameter (prop, param);
+       cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
+       g_return_val_if_fail (cbhttp->priv->components != NULL, FALSE);
 
-       icalcomponent_add_property (vfb, prop);
+       if (!cbhttp->priv->components ||
+           !g_hash_table_contains (cbhttp->priv->components, uid)) {
+               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+               return FALSE;
+       }
 
-       return TRUE;
-}
+       g_warn_if_fail (g_hash_table_lookup_extended (cbhttp->priv->components, uid, &key, &value));
+       g_warn_if_fail (g_hash_table_steal (cbhttp->priv->components, uid));
 
-static icalcomponent *
-create_user_free_busy (ECalBackendHttp *cbhttp,
-                       const gchar *address,
-                       const gchar *cn,
-                       time_t start,
-                       time_t end)
-{
-       GSList *slist = NULL, *l;
-       icalcomponent *vfb;
-       icaltimezone *utc_zone;
-       ECalBackendSExp *obj_sexp;
-       ECalBackendHttpPrivate *priv;
-       ECalBackendStore *store;
-       gchar *query, *iso_start, *iso_end;
-
-       priv = cbhttp->priv;
-       store = priv->store;
-
-        /* create the (unique) VFREEBUSY object that we'll return */
-       vfb = icalcomponent_new_vfreebusy ();
-       if (address != NULL) {
-               icalproperty *prop;
-               icalparameter *param;
-
-               prop = icalproperty_new_organizer (address);
-               if (prop != NULL && cn != NULL) {
-                       param = icalparameter_new_cn (cn);
-                       icalproperty_add_parameter (prop, param);
-               }
-               if (prop != NULL)
-                       icalcomponent_add_property (vfb, prop);
-       }
-       utc_zone = icaltimezone_get_utc_timezone ();
-       icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone));
-       icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
-
-        /* add all objects in the given interval */
-       iso_start = isodate_from_time_t (start);
-       iso_end = isodate_from_time_t (end);
-       query = g_strdup_printf (
-               "occur-in-time-range? (make-time \"%s\") (make-time \"%s\")",
-               iso_start, iso_end);
-       obj_sexp = e_cal_backend_sexp_new (query);
-       g_free (query);
-       g_free (iso_start);
-       g_free (iso_end);
-
-       if (!obj_sexp)
-               return vfb;
-
-       slist = e_cal_backend_store_get_components (store);
-
-       for (l = slist; l; l = g_slist_next (l)) {
-               ECalComponent *comp = l->data;
-               icalcomponent *icalcomp, *vcalendar_comp;
-               icalproperty *prop;
-
-               icalcomp = e_cal_component_get_icalcomponent (comp);
-               if (!icalcomp)
-                       continue;
+       *out_component = value;
 
-                /* If the event is TRANSPARENT, skip it. */
-               prop = icalcomponent_get_first_property (
-                       icalcomp,
-                       ICAL_TRANSP_PROPERTY);
-               if (prop) {
-                       icalproperty_transp transp_val = icalproperty_get_transp (prop);
-                       if (transp_val == ICAL_TRANSP_TRANSPARENT ||
-                           transp_val == ICAL_TRANSP_TRANSPARENTNOCONFLICT)
-                               continue;
-               }
+       g_free (key);
 
-               if (!e_cal_backend_sexp_match_comp (
-                       obj_sexp, l->data,
-                       E_TIMEZONE_CACHE (cbhttp)))
-                       continue;
+       if (!g_hash_table_size (cbhttp->priv->components)) {
+               g_hash_table_destroy (cbhttp->priv->components);
+               cbhttp->priv->components = NULL;
 
-               vcalendar_comp = icalcomponent_get_parent (icalcomp);
-               if (!vcalendar_comp)
-                       vcalendar_comp = icalcomp;
-               e_cal_recur_generate_instances (
-                       comp, start, end,
-                       free_busy_instance,
-                       vfb,
-                       resolve_tzid,
-                       vcalendar_comp,
-                       icaltimezone_get_utc_timezone ());
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
        }
-       g_object_unref (obj_sexp);
 
-       return vfb;
+       return value != NULL;
 }
 
-/* Get_free_busy handler for the file backend */
 static void
-e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
-                                  EDataCal *cal,
-                                  GCancellable *cancellable,
-                                  const GSList *users,
-                                  time_t start,
-                                  time_t end,
-                                  GSList **freebusy,
-                                  GError **error)
+e_cal_backend_http_dispose (GObject *object)
 {
-       ESourceRegistry *registry;
        ECalBackendHttp *cbhttp;
-       ECalBackendHttpPrivate *priv;
-       gchar *address, *name;
-       icalcomponent *vfb;
-       gchar *calobj;
-
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv = cbhttp->priv;
 
-       if (!priv->store) {
-               g_propagate_error (error, EDC_ERROR (NoSuchCal));
-               return;
-       }
+       cbhttp = E_CAL_BACKEND_HTTP (object);
 
-       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+       g_clear_object (&cbhttp->priv->request);
+       g_clear_object (&cbhttp->priv->input_stream);
 
-       if (users == NULL) {
-               if (e_cal_backend_mail_account_get_default (registry, &address, &name)) {
-                       vfb = create_user_free_busy (cbhttp, address, name, start, end);
-                       calobj = icalcomponent_as_ical_string_r (vfb);
-                        *freebusy = g_slist_append (*freebusy, calobj);
-                       icalcomponent_free (vfb);
-                       g_free (address);
-                       g_free (name);
-               }
-       } else {
-               const GSList *l;
-               for (l = users; l != NULL; l = l->next ) {
-                       address = l->data;
-                       if (e_cal_backend_mail_account_is_valid (registry, address, &name)) {
-                               vfb = create_user_free_busy (cbhttp, address, name, start, end);
-                               calobj = icalcomponent_as_ical_string_r (vfb);
-                                *freebusy = g_slist_append (*freebusy, calobj);
-                               icalcomponent_free (vfb);
-                               g_free (name);
-                       }
-               }
+       if (cbhttp->priv->soup_session) {
+               soup_session_abort (cbhttp->priv->soup_session);
+               g_clear_object (&cbhttp->priv->soup_session);
        }
-}
 
-static void
-e_cal_backend_http_create_objects (ECalBackendSync *backend,
-                                   EDataCal *cal,
-                                   GCancellable *cancellable,
-                                   const GSList *calobjs,
-                                   GSList **uids,
-                                   GSList **new_components,
-                                   GError **perror)
-{
-       g_propagate_error (perror, EDC_ERROR (PermissionDenied));
-}
+       if (cbhttp->priv->components) {
+               g_hash_table_destroy (cbhttp->priv->components);
+               cbhttp->priv->components = NULL;
+       }
 
-static void
-e_cal_backend_http_modify_objects (ECalBackendSync *backend,
-                                   EDataCal *cal,
-                                   GCancellable *cancellable,
-                                   const GSList *calobjs,
-                                   ECalObjModType mod,
-                                   GSList **old_components,
-                                   GSList **new_components,
-                                   GError **perror)
-{
-       g_propagate_error (perror, EDC_ERROR (PermissionDenied));
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->dispose (object);
 }
 
-/* Remove_objects handler for the file backend */
 static void
-e_cal_backend_http_remove_objects (ECalBackendSync *backend,
-                                   EDataCal *cal,
-                                   GCancellable *cancellable,
-                                   const GSList *ids,
-                                   ECalObjModType mod,
-                                   GSList **old_components,
-                                   GSList **new_components,
-                                   GError **perror)
+e_cal_backend_http_finalize (GObject *object)
 {
-       *old_components = *new_components = NULL;
+       ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (object);
 
-       g_propagate_error (perror, EDC_ERROR (PermissionDenied));
-}
+       e_named_parameters_free (cbhttp->priv->credentials);
+       cbhttp->priv->credentials = NULL;
 
-/* Update_objects handler for the file backend. */
-static void
-e_cal_backend_http_receive_objects (ECalBackendSync *backend,
-                                    EDataCal *cal,
-                                    GCancellable *cancellable,
-                                    const gchar *calobj,
-                                    GError **perror)
-{
-       g_propagate_error (perror, EDC_ERROR (PermissionDenied));
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->finalize (object);
 }
 
 static void
-e_cal_backend_http_send_objects (ECalBackendSync *backend,
-                                 EDataCal *cal,
-                                 GCancellable *cancellable,
-                                 const gchar *calobj,
-                                 GSList **users,
-                                 gchar **modified_calobj,
-                                 GError **perror)
-{
-       *users = NULL;
-       *modified_calobj = NULL;
-
-       g_propagate_error (perror, EDC_ERROR (PermissionDenied));
-}
-
-static ESourceAuthenticationResult
-e_cal_backend_http_authenticate_sync (EBackend *backend,
-                                     const ENamedParameters *credentials,
-                                     gchar **out_certificate_pem,
-                                     GTlsCertificateFlags *out_certificate_errors,
-                                     GCancellable *cancellable,
-                                     GError **error)
+e_cal_backend_http_init (ECalBackendHttp *cbhttp)
 {
-       ECalBackendHttp *cbhttp;
-       ESourceAuthenticationResult result;
-       const gchar *uri, *username;
-       GError *local_error = NULL;
-
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
+       SoupSession *soup_session;
 
-       g_free (cbhttp->priv->username);
-       cbhttp->priv->username = NULL;
+       cbhttp->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbhttp, E_TYPE_CAL_BACKEND_HTTP, ECalBackendHttpPrivate);
 
-       g_free (cbhttp->priv->password);
-       cbhttp->priv->password = g_strdup (e_named_parameters_get (credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
+       e_cal_backend_set_writable (E_CAL_BACKEND (cbhttp), FALSE);
 
-       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
-       if (username && *username) {
-               cbhttp->priv->username = g_strdup (username);
-       }
-
-       uri = cal_backend_http_ensure_uri (cbhttp);
-       if (cal_backend_http_load (cbhttp, uri, out_certificate_pem, out_certificate_errors, cancellable, 
&local_error)) {
-               if (!cbhttp->priv->reload_timeout_id) {
-                       ESource *source = e_backend_get_source (backend);
+       soup_session = soup_session_new ();
+       g_object_set (
+               soup_session,
+               SOUP_SESSION_TIMEOUT, 90,
+               SOUP_SESSION_SSL_STRICT, TRUE,
+               SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
+               SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+               NULL);
 
-                       cbhttp->priv->reload_timeout_id = e_source_refresh_add_timeout (source, NULL, 
http_cal_reload_cb, backend, NULL);
-               }
-       }
+       if (g_getenv ("WEBCAL_DEBUG") != NULL) {
+               SoupLogger *logger;
 
-       if (local_error == NULL) {
-               result = E_SOURCE_AUTHENTICATION_ACCEPTED;
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
-               result = E_SOURCE_AUTHENTICATION_REJECTED;
-               g_clear_error (&local_error);
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
-               result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
-               g_propagate_error (error, local_error);
-       } else {
-               result = E_SOURCE_AUTHENTICATION_ERROR;
-               g_propagate_error (error, local_error);
+               logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, 1024 * 1024);
+               soup_session_add_feature (soup_session, SOUP_SESSION_FEATURE (logger));
+               g_object_unref (logger);
        }
 
-       return result;
-}
+       cbhttp->priv->soup_session = soup_session;
+       cbhttp->priv->request = NULL;
+       cbhttp->priv->input_stream = NULL;
 
-/* Object initialization function for the file backend */
-static void
-e_cal_backend_http_init (ECalBackendHttp *cbhttp)
-{
-       cbhttp->priv = E_CAL_BACKEND_HTTP_GET_PRIVATE (cbhttp);
+       e_binding_bind_property (
+               cbhttp, "proxy-resolver",
+               cbhttp->priv->soup_session, "proxy-resolver",
+               G_BINDING_SYNC_CREATE);
 
        g_signal_connect (
-               cbhttp, "notify::online",
-               G_CALLBACK (e_cal_backend_http_notify_online_cb), NULL);
+               cbhttp->priv->soup_session, "authenticate",
+               G_CALLBACK (ecb_http_soup_authenticate), cbhttp);
 }
 
-/* Class initialization function for the file backend */
 static void
-e_cal_backend_http_class_init (ECalBackendHttpClass *class)
+e_cal_backend_http_class_init (ECalBackendHttpClass *klass)
 {
        GObjectClass *object_class;
-       EBackendClass *backend_class;
-       ECalBackendClass *cal_backend_class;
-       ECalBackendSyncClass *sync_class;
-
-       g_type_class_add_private (class, sizeof (ECalBackendHttpPrivate));
-
-       object_class = (GObjectClass *) class;
-       backend_class = E_BACKEND_CLASS (class);
-       cal_backend_class = (ECalBackendClass *) class;
-       sync_class = (ECalBackendSyncClass *) class;
-
+       ECalBackendSyncClass *cal_backend_sync_class;
+       ECalMetaBackendClass *cal_meta_backend_class;
+
+       g_type_class_add_private (klass, sizeof (ECalBackendHttpPrivate));
+
+       cal_meta_backend_class = E_CAL_META_BACKEND_CLASS (klass);
+       cal_meta_backend_class->connect_sync = ecb_http_connect_sync;
+       cal_meta_backend_class->disconnect_sync = ecb_http_disconnect_sync;
+       cal_meta_backend_class->get_changes_sync = ecb_http_get_changes_sync;
+       cal_meta_backend_class->list_existing_sync = ecb_http_list_existing_sync;
+       cal_meta_backend_class->load_component_sync = ecb_http_load_component_sync;
+
+       /* Setting these methods to NULL will cause "Not supported" error,
+          which is more accurate than "Permission denied" error */
+       cal_backend_sync_class = E_CAL_BACKEND_SYNC_CLASS (klass);
+       cal_backend_sync_class->create_objects_sync = NULL;
+       cal_backend_sync_class->modify_objects_sync = NULL;
+       cal_backend_sync_class->remove_objects_sync = NULL;
+
+       object_class = G_OBJECT_CLASS (klass);
        object_class->dispose = e_cal_backend_http_dispose;
        object_class->finalize = e_cal_backend_http_finalize;
-       object_class->constructed = e_cal_backend_http_constructed;
-
-       backend_class->authenticate_sync = e_cal_backend_http_authenticate_sync;
-
-       /* Execute one method at a time. */
-       cal_backend_class->use_serial_dispatch_queue = TRUE;
-       cal_backend_class->get_backend_property = e_cal_backend_http_get_backend_property;
-       cal_backend_class->start_view = e_cal_backend_http_start_view;
-
-       sync_class->open_sync = e_cal_backend_http_open;
-       sync_class->refresh_sync = e_cal_backend_http_refresh;
-       sync_class->create_objects_sync = e_cal_backend_http_create_objects;
-       sync_class->modify_objects_sync = e_cal_backend_http_modify_objects;
-       sync_class->remove_objects_sync = e_cal_backend_http_remove_objects;
-       sync_class->receive_objects_sync = e_cal_backend_http_receive_objects;
-       sync_class->send_objects_sync = e_cal_backend_http_send_objects;
-       sync_class->get_object_sync = e_cal_backend_http_get_object;
-       sync_class->get_object_list_sync = e_cal_backend_http_get_object_list;
-       sync_class->add_timezone_sync = e_cal_backend_http_add_timezone;
-       sync_class->get_free_busy_sync = e_cal_backend_http_get_free_busy;
 }
diff --git a/src/calendar/backends/http/e-cal-backend-http.h b/src/calendar/backends/http/e-cal-backend-http.h
index b45ff33..b7c5df3 100644
--- a/src/calendar/backends/http/e-cal-backend-http.h
+++ b/src/calendar/backends/http/e-cal-backend-http.h
@@ -47,12 +47,12 @@ typedef struct _ECalBackendHttpClass ECalBackendHttpClass;
 typedef struct _ECalBackendHttpPrivate ECalBackendHttpPrivate;
 
 struct _ECalBackendHttp {
-       ECalBackendSync backend;
+       ECalMetaBackend backend;
        ECalBackendHttpPrivate *priv;
 };
 
 struct _ECalBackendHttpClass {
-       ECalBackendSyncClass parent_class;
+       ECalMetaBackendClass parent_class;
 };
 
 GType          e_cal_backend_http_get_type     (void);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]