Adapt calendar backends to the new ESource API.
authorMatthew Barnes <mbarnes@redhat.com>
Tue, 23 Nov 2010 04:04:56 +0000 (23:04 -0500)
committerMatthew Barnes <mbarnes@redhat.com>
Sun, 3 Jun 2012 23:51:08 +0000 (19:51 -0400)
calendar/backends/caldav/e-cal-backend-caldav.c
calendar/backends/http/e-cal-backend-http.c

index 862b028..6341868 100644 (file)
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-xml-hash-utils.h>
 #include <libedataserver/e-proxy.h>
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-authenticator.h>
+#include <libedataserver/e-source-offline.h>
+#include <libedataserver/e-source-refresh.h>
+#include <libedataserver/e-source-webdav.h>
 #include <libecal/e-cal-recur.h>
 #include <libecal/e-cal-util.h>
 #include <libecal/e-cal-time-util.h>
@@ -114,7 +119,7 @@ struct _ECalBackendCalDAVPrivate {
        gchar *uri;
 
        /* Authentication info */
-       ECredentials *credentials;
+       gchar *password;
        gboolean auth_required;
 
        /* object cleanup */
@@ -547,6 +552,9 @@ status_code_to_result (SoupMessage *message,
 {
        ECalBackendCalDAVPrivate *priv;
        ESource *source;
+       ESourceWebdav *extension;
+       const gchar *extension_name;
+       gboolean ignore_invalid_cert;
 
        g_return_val_if_fail (cbdav != NULL, FALSE);
        g_return_val_if_fail (message != NULL, FALSE);
@@ -559,6 +567,10 @@ status_code_to_result (SoupMessage *message,
 
        source = e_backend_get_source (E_BACKEND (cbdav));
 
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       extension = e_source_get_extension (source, extension_name);
+       ignore_invalid_cert = e_source_webdav_get_ignore_invalid_cert (extension);
+
        switch (message->status_code) {
        case SOUP_STATUS_CANT_CONNECT:
        case SOUP_STATUS_CANT_CONNECT_PROXY:
@@ -592,7 +604,7 @@ status_code_to_result (SoupMessage *message,
                break;
 
        case SOUP_STATUS_SSL_FAILED:
-               if (g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") == 0) {
+               if (ignore_invalid_cert) {
                        g_propagate_error (perror,
                                e_data_cal_create_error_fmt ( OtherError,
                                _("Failed to connect to a server using SSL: %s"),
@@ -974,13 +986,23 @@ soup_authenticate (SoupSession *session,
                    gpointer data)
 {
        ECalBackendCalDAV *cbdav;
+       ESourceAuthentication *auth_extension;
+       ESource *source;
+       const gchar *extension_name;
 
        cbdav = E_CAL_BACKEND_CALDAV (data);
 
+       source = e_backend_get_source (E_BACKEND (data));
+       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+       auth_extension = e_source_get_extension (source, extension_name);
+
        /* do not send same password twice, but keep it for later use */
-       if (!retrying && cbdav->priv->credentials && e_credentials_has_key (cbdav->priv->credentials, E_CREDENTIALS_KEY_USERNAME)) {
-               soup_auth_authenticate (auth, e_credentials_peek (cbdav->priv->credentials, E_CREDENTIALS_KEY_USERNAME), e_credentials_peek (cbdav->priv->credentials, E_CREDENTIALS_KEY_PASSWORD));
-               e_credentials_clear_peek (cbdav->priv->credentials);
+       if (!retrying && cbdav->priv->password != NULL) {
+               gchar *user;
+
+               user = e_source_authentication_dup_user (auth_extension);
+               soup_auth_authenticate (auth, user, cbdav->priv->password);
+               g_free (user);
        }
 }
 
@@ -1138,37 +1160,20 @@ caldav_server_open_calendar (ECalBackendCalDAV *cbdav,
        return FALSE;
 }
 
-static void
-caldav_notify_auth_required (ECalBackendCalDAV *cbdav)
+static gboolean
+caldav_authenticate (ECalBackendCalDAV *cbdav,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-       ECredentials *credentials;
-       guint prompt_flags;
-       gchar *prompt_flags_str;
-
-       g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav));
-
-       cbdav->priv->opened = FALSE;
-       update_slave_cmd (cbdav->priv, SLAVE_SHOULD_SLEEP);
-
-       if (!e_backend_get_online (E_BACKEND (cbdav)))
-               return;
-
-       if (cbdav->priv->credentials)
-               credentials = e_credentials_new_clone (cbdav->priv->credentials);
-       else
-               credentials = e_credentials_new ();
-       prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
-                    | E_CREDENTIALS_PROMPT_FLAG_SECRET
-                    | E_CREDENTIALS_PROMPT_FLAG_ONLINE
-                    | E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
-
-       prompt_flags_str = e_credentials_util_prompt_flags_to_string (prompt_flags);
-       e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS, prompt_flags_str);
-       g_free (prompt_flags_str);
+       ESource *source;
+       ESourceRegistry *registry;
 
-       e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbdav), TRUE, credentials);
+       source = e_backend_get_source (E_BACKEND (cbdav));
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbdav));
 
-       e_credentials_free (credentials);
+       return e_source_registry_authenticate_sync (
+               registry, source, E_SOURCE_AUTHENTICATOR (cbdav),
+               cancellable, error);
 }
 
 /* Returns whether calendar changed on the server. This works only when server
@@ -1228,7 +1233,7 @@ check_calendar_changed_on_server (ECalBackendCalDAV *cbdav)
 
        /* Check the result */
        if (message->status_code == 401) {
-               caldav_notify_auth_required (cbdav);
+               caldav_authenticate (cbdav, NULL, NULL);
        } else if (message->status_code != 207) {
                /* does not support it, but report calendar changed to update cache */
                cbdav->priv->ctag_supported = FALSE;
@@ -1386,7 +1391,7 @@ caldav_server_list_objects (ECalBackendCalDAV *cbdav,
                                E_CAL_BACKEND (cbdav), cbdav->priv->read_only);
                        break;
                case 401:
-                       caldav_notify_auth_required (cbdav);
+                       caldav_authenticate (cbdav, NULL, NULL);
                        break;
                default:
                        g_warning ("Server did not response with 207, but with code %d (%s)", message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : "Unknown code");
@@ -1431,7 +1436,7 @@ caldav_server_download_attachment (ECalBackendCalDAV *cbdav,
                status_code_to_result (message, cbdav, FALSE, error);
 
                if (message->status_code == 401)
-                       caldav_notify_auth_required (cbdav);
+                       caldav_authenticate (cbdav, NULL, NULL);
 
                g_object_unref (message);
                return FALSE;
@@ -1473,7 +1478,7 @@ caldav_server_get_object (ECalBackendCalDAV *cbdav,
                status_code_to_result (message, cbdav, FALSE, perror);
 
                if (message->status_code == 401)
-                       caldav_notify_auth_required (cbdav);
+                       caldav_authenticate (cbdav, NULL, NULL);
                else
                        g_warning ("Could not fetch object '%s' from server, status:%d (%s)", uri, message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : "Unknown code");
                g_object_unref (message);
@@ -1539,7 +1544,7 @@ caldav_post_freebusy (ECalBackendCalDAV *cbdav,
        if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
                status_code_to_result (message, cbdav, FALSE, error);
                if (message->status_code == 401)
-                       caldav_notify_auth_required (cbdav);
+                       caldav_authenticate (cbdav, NULL, NULL);
                else
                        g_warning ("Could not post free/busy request to '%s', status:%d (%s)", url, message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : "Unknown code");
 
@@ -1726,7 +1731,7 @@ caldav_server_put_object (ECalBackendCalDAV *cbdav,
                        g_propagate_error (perror, local_error);
                }
        } else if (message->status_code == 401) {
-               caldav_notify_auth_required (cbdav);
+               caldav_authenticate (cbdav, NULL, NULL);
        }
 
        g_object_unref (message);
@@ -1765,7 +1770,7 @@ caldav_server_delete_object (ECalBackendCalDAV *cbdav,
        status_code_to_result (message, cbdav, FALSE, perror);
 
        if (message->status_code == 401)
-               caldav_notify_auth_required (cbdav);
+               caldav_authenticate (cbdav, NULL, NULL);
 
        g_object_unref (message);
 }
@@ -1880,7 +1885,7 @@ caldav_receive_schedule_outbox_url (ECalBackendCalDAV *cbdav)
                xmlOutputBufferClose (buf);
                xmlFreeDoc (doc);
        } else if (message->status_code == 401) {
-               caldav_notify_auth_required (cbdav);
+               caldav_authenticate (cbdav, NULL, NULL);
        }
 
        if (message)
@@ -2388,27 +2393,38 @@ maybe_append_email_domain (const gchar *username,
 static gchar *
 get_usermail (ECalBackend *backend)
 {
-       ECalBackendCalDAV        *cbdav;
+       ECalBackendCalDAV *cbdav;
        ESource *source;
+       ESourceAuthentication *auth_extension;
+       ESourceWebdav *webdav_extension;
+       const gchar *extension_name;
+       gchar *usermail;
+       gchar *username;
        gchar *res = NULL;
 
        g_return_val_if_fail (backend != NULL, NULL);
 
        source = e_backend_get_source (E_BACKEND (backend));
-       if (source) {
-               res = e_source_get_duped_property (source, "usermail");
-               if (res && *res)
-                       return res;
 
-               g_free (res);
-               res = NULL;
-       }
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       webdav_extension = e_source_get_extension (source, extension_name);
+
+       /* This will never return an empty string. */
+       usermail = e_source_webdav_dup_email_address (webdav_extension);
+
+       if (usermail != NULL)
+               return usermail;
 
        cbdav = E_CAL_BACKEND_CALDAV (backend);
 
-       if (cbdav->priv->is_google && cbdav->priv->credentials) {
-               res = maybe_append_email_domain (e_credentials_peek (cbdav->priv->credentials, E_CREDENTIALS_KEY_USERNAME), "@gmail.com");
-       }
+       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+       auth_extension = e_source_get_extension (source, extension_name);
+       username = e_source_authentication_dup_user (auth_extension);
+
+       if (cbdav->priv && cbdav->priv->is_google)
+               res = maybe_append_email_domain (username, "@gmail.com");
+
+       g_free (username);
 
        return res;
 }
@@ -2430,9 +2446,11 @@ caldav_get_backend_property (ECalBackendSync *backend,
        g_return_val_if_fail (prop_value != NULL, FALSE);
 
        if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+               ESourceWebdav *extension;
                ESource *source;
                GString *caps;
                gchar *usermail;
+               const gchar *extension_name;
 
                caps = g_string_new (CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
                                     CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
@@ -2444,12 +2462,13 @@ caldav_get_backend_property (ECalBackendSync *backend,
                g_free (usermail);
 
                source = e_backend_get_source (E_BACKEND (backend));
-               if (source) {
-                       const gchar *prop = e_source_get_property (source, "autoschedule");
 
-                       if (prop && g_str_equal (prop, "1"))
-                               g_string_append (caps, "," CAL_STATIC_CAPABILITY_CREATE_MESSAGES
-                                                      "," CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
+               extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+               extension = e_source_get_extension (source, extension_name);
+
+               if (e_source_webdav_get_calendar_auto_schedule (extension)) {
+                       g_string_append (caps, "," CAL_STATIC_CAPABILITY_CREATE_MESSAGES
+                                              "," CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
                }
 
                *prop_value = g_string_free (caps, FALSE);
@@ -2490,79 +2509,71 @@ static gboolean
 initialize_backend (ECalBackendCalDAV *cbdav,
                     GError **perror)
 {
+       ESourceAuthentication    *auth_extension;
+       ESourceOffline           *offline_extension;
+       ESourceRefresh           *refresh_extension;
+       ESourceWebdav            *webdav_extension;
        ECalBackend              *backend;
+       SoupURI                  *soup_uri;
        ESource                  *source;
-       const gchar              *os_val;
-       gchar                    *uri;
        gsize                     len;
-       const gchar              *refresh;
        const gchar              *cache_dir;
+       const gchar              *extension_name;
+       guint                     interval_in_minutes;
 
        backend = E_CAL_BACKEND (cbdav);
        cache_dir = e_cal_backend_get_cache_dir (backend);
        source = e_backend_get_source (E_BACKEND (backend));
-       uri = e_source_get_uri (source);
 
-       if (!g_signal_handler_find (G_OBJECT (source), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, caldav_source_changed_cb, cbdav))
-               g_signal_connect (G_OBJECT (source), "changed", G_CALLBACK (caldav_source_changed_cb), cbdav);
+       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+       auth_extension = e_source_get_extension (source, extension_name);
 
-       os_val = e_source_get_property (source, "offline_sync");
-       cbdav->priv->do_offline = os_val && g_str_equal (os_val, "1");
+       extension_name = E_SOURCE_EXTENSION_OFFLINE;
+       offline_extension = e_source_get_extension (source, extension_name);
 
-       os_val = e_source_get_property (source, "auth");
-       cbdav->priv->auth_required = os_val != NULL;
+       extension_name = E_SOURCE_EXTENSION_REFRESH;
+       refresh_extension = e_source_get_extension (source, extension_name);
 
-       os_val = e_source_get_property(source, "ssl");
-
-       g_free (cbdav->priv->uri);
-       cbdav->priv->uri = NULL;
-       if (g_str_has_prefix (uri, "caldav://")) {
-               const gchar *proto;
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       webdav_extension = e_source_get_extension (source, extension_name);
 
-               if (os_val && os_val[0] == '1') {
-                       proto = "https://";
-               } else {
-                       proto = "http://";
-               }
+       if (!g_signal_handler_find (G_OBJECT (source), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, caldav_source_changed_cb, cbdav))
+               g_signal_connect (G_OBJECT (source), "changed", G_CALLBACK (caldav_source_changed_cb), cbdav);
 
-               cbdav->priv->uri = g_strconcat (proto, uri + 9, NULL);
+       cbdav->priv->do_offline = e_source_offline_get_stay_synchronized (offline_extension);
 
-               g_free (uri);
-       } else {
-               cbdav->priv->uri = uri;
-       }
+       cbdav->priv->auth_required = e_source_authentication_required (auth_extension);
 
-       if (cbdav->priv->uri) {
-               SoupURI *suri = soup_uri_new (cbdav->priv->uri);
+       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
 
-               /* properly encode uri */
-               if (suri && suri->path) {
-                       gchar *tmp, *path;
+       /* properly encode uri */
+       if (soup_uri != NULL && soup_uri->path != NULL) {
+               gchar *tmp, *path;
 
-                       if (suri->path && strchr (suri->path, '%')) {
-                               /* If path contains anything already encoded, then decode it first,
-                                * thus it'll be managed properly. For example, the '#' in a path
-                                * is in URI shown as %23 and not doing this decode makes it being
-                                * like %2523, which is not what is wanted here. */
-                               tmp = soup_uri_decode (suri->path);
-                               soup_uri_set_path (suri, tmp);
-                               g_free (tmp);
-                       }
+               if (strchr (soup_uri->path, '%')) {
+                       /* If path contains anything already encoded, then
+                        * decode it first, thus it'll be managed properly.
+                        * For example, the '#' in a path is in URI shown as
+                        * %23 and not doing this decode makes it being like
+                        * %2523, which is not what is wanted here. */
+                       tmp = soup_uri_decode (soup_uri->path);
+                       soup_uri_set_path (soup_uri, tmp);
+                       g_free (tmp);
+               }
 
-                       tmp = soup_uri_encode (suri->path, NULL);
-                       path = soup_uri_normalize (tmp, "/");
+               tmp = soup_uri_encode (soup_uri->path, NULL);
+               path = soup_uri_normalize (tmp, "/");
 
-                       soup_uri_set_path (suri, path);
+               soup_uri_set_path (soup_uri, path);
 
-                       g_free (tmp);
-                       g_free (path);
-                       g_free (cbdav->priv->uri);
+               g_free (tmp);
+               g_free (path);
+       }
 
-                       cbdav->priv->uri = soup_uri_to_string (suri, FALSE);
-               }
+       g_free (cbdav->priv->uri);
+       cbdav->priv->uri = soup_uri_to_string (soup_uri, FALSE);
 
-               soup_uri_free (suri);
-       }
+       soup_uri_free (soup_uri);
 
        g_return_val_if_fail (cbdav->priv->uri != NULL, FALSE);
 
@@ -2606,8 +2617,14 @@ initialize_backend (ECalBackendCalDAV *cbdav,
                return FALSE;
        }
 
-       refresh = e_source_get_property (source, "refresh");
-       cbdav->priv->refresh_time.tv_sec  = (refresh && atoi (refresh) > 0) ? (60 * atoi (refresh)) : (DEFAULT_REFRESH_TIME);
+       /* FIXME Not honoring ESourceRefresh:enabled. */
+       interval_in_minutes =
+               e_source_refresh_get_interval_minutes (refresh_extension);
+
+       if (interval_in_minutes == 0)
+               cbdav->priv->refresh_time.tv_sec = DEFAULT_REFRESH_TIME;
+       else
+               cbdav->priv->refresh_time.tv_sec = interval_in_minutes * 60;
 
        if (!cbdav->priv->synch_slave) {
                GThread *slave;
@@ -2653,15 +2670,6 @@ open_calendar (ECalBackendCalDAV *cbdav,
 
        g_return_val_if_fail (cbdav != NULL, FALSE);
 
-       if (cbdav->priv->session) {
-               ESource *source = e_backend_get_source (E_BACKEND (cbdav));
-
-               g_object_set (G_OBJECT (cbdav->priv->session),
-                       SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
-                       g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") != 0,
-                       NULL);
-       }
-
        /* set forward proxy */
        proxy_settings_changed (cbdav->priv->proxy, cbdav->priv);
 
@@ -2733,8 +2741,8 @@ caldav_do_open (ECalBackendSync *backend,
 
                if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired) || g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
                        g_clear_error (&local_error);
-                       e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbdav), TRUE, cbdav->priv->credentials);
-                       opened = FALSE;
+                       opened = caldav_authenticate (
+                               cbdav, cancellable, perror);
                }
 
                if (local_error != NULL)
@@ -2755,34 +2763,6 @@ caldav_do_open (ECalBackendSync *backend,
 }
 
 static void
-caldav_authenticate_user (ECalBackendSync *backend,
-                          GCancellable *cancellable,
-                          ECredentials *credentials,
-                          GError **error)
-{
-       ECalBackendCalDAV        *cbdav;
-
-       cbdav = E_CAL_BACKEND_CALDAV (backend);
-
-       g_mutex_lock (cbdav->priv->busy_lock);
-
-       e_credentials_free (cbdav->priv->credentials);
-       cbdav->priv->credentials = NULL;
-
-       if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
-               g_mutex_unlock (cbdav->priv->busy_lock);
-               g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
-               return;
-       }
-
-       cbdav->priv->credentials = e_credentials_new_clone (credentials);
-
-       open_calendar (cbdav, error);
-
-       g_mutex_unlock (cbdav->priv->busy_lock);
-}
-
-static void
 caldav_refresh (ECalBackendSync *backend,
                 EDataCal *cal,
                 GCancellable *cancellable,
@@ -4133,6 +4113,7 @@ process_object (ECalBackendCalDAV *cbdav,
                 icalproperty_method method,
                 GError **error)
 {
+       ESourceRegistry *registry;
        ECalBackend              *backend;
        struct icaltimetype       now;
        gchar *new_obj_str;
@@ -4145,6 +4126,8 @@ process_object (ECalBackendCalDAV *cbdav,
 
        e_return_data_cal_error_if_fail (id != NULL, InvalidObject);
 
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (cbdav));
+
        /* ctime, mtime */
        now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
        e_cal_component_set_created (ecomp, &now);
@@ -4161,7 +4144,7 @@ process_object (ECalBackendCalDAV *cbdav,
        case ICAL_METHOD_REQUEST:
        case ICAL_METHOD_REPLY:
                is_declined = e_cal_backend_user_declined (
-                       e_cal_component_get_icalcomponent (ecomp));
+                       registry, e_cal_component_get_icalcomponent (ecomp));
                if (is_in_cache) {
                        if (!is_declined) {
                                GSList *new_components = NULL, *old_components = NULL;
@@ -4608,11 +4591,15 @@ caldav_get_free_busy (ECalBackendSync *backend,
        icalcomponent *icalcomp;
        ECalComponent *comp;
        ECalComponentDateTime dt;
+       ECalComponentOrganizer organizer = {NULL};
+       ESourceAuthentication *auth_extension;
+       ESource *source;
        struct icaltimetype dtvalue;
        icaltimezone *utc;
        gchar *str;
        const GSList *u;
        GSList *attendees = NULL, *to_free = NULL;
+       const gchar *extension_name;
        gchar *usermail;
        GError *err = NULL;
 
@@ -4662,16 +4649,16 @@ caldav_get_free_busy (ECalBackendSync *backend,
                usermail = NULL;
        }
 
-       if ((cbdav->priv->credentials && e_credentials_has_key (cbdav->priv->credentials, E_CREDENTIALS_KEY_USERNAME)) || usermail) {
-               ECalComponentOrganizer organizer = {NULL};
-
-               organizer.value = usermail ? usermail : e_credentials_peek (cbdav->priv->credentials, E_CREDENTIALS_KEY_USERNAME);
-               organizer.value = g_strconcat ("mailto:", organizer.value, NULL);
+       source = e_backend_get_source (E_BACKEND (backend));
+       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+       auth_extension = e_source_get_extension (source, extension_name);
 
-               e_cal_component_set_organizer (comp, &organizer);
+       if (usermail == NULL)
+               usermail = e_source_authentication_dup_user (auth_extension);
 
-               g_free ((gchar *) organizer.value);
-       }
+       organizer.value = g_strconcat ("mailto:", usermail, NULL);
+       e_cal_component_set_organizer (comp, &organizer);
+       g_free ((gchar *) organizer.value);
 
        g_free (usermail);
 
@@ -4863,13 +4850,54 @@ caldav_source_changed_cb (ESource *source,
        }
 }
 
+static ESourceAuthenticationResult
+caldav_try_password_sync (ESourceAuthenticator *authenticator,
+                          const GString *password,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       ECalBackendCalDAV *cbdav;
+       ESourceAuthenticationResult result;
+       GError *local_error = NULL;
+
+       cbdav = E_CAL_BACKEND_CALDAV (authenticator);
+
+       /* Busy lock is already acquired by caldav_do_open(). */
+
+       g_free (cbdav->priv->password);
+       cbdav->priv->password = g_strdup (password->str);
+
+       open_calendar (cbdav, &local_error);
+
+       if (local_error == NULL) {
+               result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+       } else if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
+               result = E_SOURCE_AUTHENTICATION_REJECTED;
+               g_clear_error (&local_error);
+       } else {
+               result = E_SOURCE_AUTHENTICATION_ERROR;
+               g_propagate_error (error, local_error);
+       }
+
+       return result;
+}
+
+static void
+caldav_source_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+       interface->try_password_sync = caldav_try_password_sync;
+}
+
 /* ************************************************************************* */
 /* ***************************** GObject Foo ******************************* */
 
-G_DEFINE_TYPE (
+G_DEFINE_TYPE_WITH_CODE (
        ECalBackendCalDAV,
        e_cal_backend_caldav,
-       E_TYPE_CAL_BACKEND_SYNC)
+       E_TYPE_CAL_BACKEND_SYNC,
+       G_IMPLEMENT_INTERFACE (
+               E_TYPE_SOURCE_AUTHENTICATOR,
+               caldav_source_authenticator_init))
 
 static void
 e_cal_backend_caldav_dispose (GObject *object)
@@ -4905,9 +4933,6 @@ e_cal_backend_caldav_dispose (GObject *object)
        g_object_unref (priv->session);
        g_object_unref (priv->proxy);
 
-       e_credentials_free (priv->credentials);
-       priv->credentials = NULL;
-
        g_free (priv->uri);
        g_free (priv->schedule_outbox_url);
 
@@ -4933,11 +4958,38 @@ e_cal_backend_caldav_finalize (GObject *object)
        g_cond_free (priv->cond);
        g_cond_free (priv->slave_gone_cond);
 
+       g_free (priv->password);
+
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static void
+cal_backend_caldav_constructed (GObject *object)
+{
+       ESource *source;
+       ESourceWebdav *extension;
+       ECalBackendCalDAV *cbdav;
+       const gchar *extension_name;
+
+       cbdav = E_CAL_BACKEND_CALDAV (object);
+
+       source = e_backend_get_source (E_BACKEND (cbdav));
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       extension = e_source_get_extension (source, extension_name);
+
+       g_object_bind_property (
+               extension, "ignore-invalid-cert",
+               cbdav->priv->session, SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
+               G_BINDING_SYNC_CREATE |
+               G_BINDING_INVERT_BOOLEAN);
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_backend_caldav_parent_class)->
+               constructed (object);
+}
+
+static void
 e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
 {
        cbdav->priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
@@ -5001,11 +5053,11 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
 
        object_class->dispose  = e_cal_backend_caldav_dispose;
        object_class->finalize = e_cal_backend_caldav_finalize;
+       object_class->constructed = cal_backend_caldav_constructed;
 
        sync_class->get_backend_property_sync   = caldav_get_backend_property;
 
        sync_class->open_sync                   = caldav_do_open;
-       sync_class->authenticate_user_sync      = caldav_authenticate_user;
        sync_class->refresh_sync                = caldav_refresh;
        sync_class->remove_sync                 = caldav_remove;
 
index d427931..0b0ada1 100644 (file)
 #include <glib/gi18n-lib.h>
 #include "libedataserver/e-xml-hash-utils.h"
 #include "libedataserver/e-proxy.h"
+#include "libedataserver/e-source-authentication.h"
+#include "libedataserver/e-source-authenticator.h"
+#include "libedataserver/e-source-refresh.h"
+#include "libedataserver/e-source-security.h"
+#include "libedataserver/e-source-webdav.h"
 #include <libecal/e-cal-recur.h>
 #include <libecal/e-cal-util.h>
 #include <libecal/e-cal-time-util.h>
 #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 (
+/* Forward Declarations */
+static void    e_cal_backend_http_source_authenticator_init
+                               (ESourceAuthenticatorInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
        ECalBackendHttp,
        e_cal_backend_http,
-       E_TYPE_CAL_BACKEND_SYNC)
+       E_TYPE_CAL_BACKEND_SYNC,
+       G_IMPLEMENT_INTERFACE (
+               E_TYPE_SOURCE_AUTHENTICATOR,
+               e_cal_backend_http_source_authenticator_init))
 
 /* Private part of the ECalBackendHttp structure */
 struct _ECalBackendHttpPrivate {
@@ -72,14 +84,40 @@ struct _ECalBackendHttpPrivate {
        gboolean opened;
        gboolean requires_auth;
 
-       ECredentials *credentials;
+       gchar *password;
 };
 
 #define d(x)
 
-static gboolean begin_retrieval_cb (ECalBackendHttp *cbhttp);
 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;
+
+       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);
+
+       if (!retrying && cbhttp->priv->password != NULL) {
+               gchar *user;
+
+               user = e_source_authentication_dup_user (auth_extension);
+               soup_auth_authenticate (auth, user, cbhttp->priv->password);
+               g_free (user);
+       }
+}
+
 /* Dispose handler for the file backend */
 static void
 e_cal_backend_http_dispose (GObject *object)
@@ -100,10 +138,6 @@ e_cal_backend_http_dispose (GObject *object)
                g_object_unref (priv->soup_session);
                priv->soup_session = NULL;
        }
-
-       e_credentials_free (priv->credentials);
-       priv->credentials = NULL;
-
        if (priv->source_changed_id) {
                g_signal_handler_disconnect (
                        e_backend_get_source (E_BACKEND (cbhttp)),
@@ -131,11 +165,55 @@ e_cal_backend_http_finalize (GObject *object)
        }
 
        g_free (priv->uri);
+       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)
+{
+       ESource *source;
+       ECalBackendHttp *backend;
+       ESourceWebdav *extension;
+       SoupSession *soup_session;
+       const gchar *extension_name;
+
+       /* Chain up to parent's constructed() method. */
+       G_OBJECT_CLASS (e_cal_backend_http_parent_class)->constructed (object);
+
+       soup_session = soup_session_sync_new ();
+
+       backend = E_CAL_BACKEND_HTTP (object);
+       backend->priv->soup_session = soup_session;
+
+       source = e_backend_get_source (E_BACKEND (backend));
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       extension = e_source_get_extension (source, extension_name);
+
+       g_object_bind_property (
+               extension, "ignore-invalid-cert",
+               soup_session, SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
+               G_BINDING_SYNC_CREATE |
+               G_BINDING_INVERT_BOOLEAN);
+
+       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 gboolean
@@ -335,56 +413,127 @@ put_component_to_store (ECalBackendHttp *cb,
        return TRUE;
 }
 
+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);
+       }
+
+       return soup_message;
+}
+
 static void
-retrieval_done (SoupSession *session,
-                SoupMessage *msg,
-                ECalBackendHttp *cbhttp)
+cal_backend_http_cancelled (GCancellable *cancellable,
+                            gpointer user_data)
 {
-       ECalBackendHttpPrivate *priv;
+       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);
+}
+
+static gboolean
+cal_backend_http_load (ECalBackendHttp *backend,
+                       GCancellable *cancellable,
+                       const gchar *uri,
+                       GError **error)
+{
+       ECalBackendHttpPrivate *priv = backend->priv;
+       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;
+       guint status_code;
+       gulong cancel_id = 0;
 
-       if (!msg || msg->status_code == SOUP_STATUS_CANCELLED) {
-               /* the backend probably gone in this case, thus just return */
-               g_object_unref (cbhttp);
-               return;
-       }
+       struct {
+               SoupSession *soup_session;
+               SoupMessage *soup_message;
+       } cancel_data;
 
-       priv = cbhttp->priv;
+       soup_session = backend->priv->soup_session;
+       soup_message = cal_backend_http_new_message (backend, uri);
 
-       priv->is_loading = FALSE;
-       d(g_message ("Retrieval done.\n"));
+       if (soup_message == NULL) {
+               g_set_error (
+                       error, SOUP_HTTP_ERROR,
+                       SOUP_STATUS_MALFORMED,
+                       _("Malformed URI: %s"), uri);
+               return FALSE;
+       }
 
-       if (!priv->uri) {
-               /* uri changed meanwhile, retrieve again */
-               begin_retrieval_cb (cbhttp);
-               g_object_unref (cbhttp);
-               return;
+       if (G_IS_CANCELLABLE (cancellable)) {
+               cancel_data.soup_session = soup_session;
+               cancel_data.soup_message = soup_message;
+
+               cancel_id = g_cancellable_connect (
+                       cancellable,
+                       G_CALLBACK (cal_backend_http_cancelled),
+                       &cancel_data, (GDestroyNotify) NULL);
        }
 
-       if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
+       status_code = soup_session_send_message (soup_session, soup_message);
+
+       if (G_IS_CANCELLABLE (cancellable))
+               g_cancellable_disconnect (cancellable, cancel_id);
+
+       if (status_code == SOUP_STATUS_NOT_MODIFIED) {
                /* attempts with ETag can result in 304 status code */
+               g_object_unref (soup_message);
                priv->opened = TRUE;
-               g_object_unref (cbhttp);
-               return;
+               return TRUE;
        }
 
        /* Handle redirection ourselves */
-       if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+       if (SOUP_STATUS_IS_REDIRECTION (status_code)) {
+               gboolean success;
+
                newuri = soup_message_headers_get (
-                       msg->response_headers, "Location");
+                       soup_message->response_headers, "Location");
 
-               d(g_message ("Redirected from %s to %s\n", priv->uri, newuri));
+               d(g_message ("Redirected from %s to %s\n", async_context->uri, newuri));
 
                if (newuri != NULL) {
+                       gchar *redirected_uri;
+
                        if (newuri[0]=='/') {
                                g_warning ("Hey! Relative URI returned! Working around...\n");
 
-                               uri_parsed = soup_uri_new (priv->uri);
+                               uri_parsed = soup_uri_new (uri);
                                soup_uri_set_path (uri_parsed, newuri);
                                soup_uri_set_query (uri_parsed, NULL);
                                /* g_free (newuri); */
@@ -394,60 +543,39 @@ retrieval_done (SoupSession *session,
                                soup_uri_free (uri_parsed);
                        }
 
-                       g_free (priv->uri);
+                       redirected_uri =
+                               webcal_to_http_method (newuri, FALSE);
+                       success = cal_backend_http_load (
+                               backend, cancellable, redirected_uri, error);
+                       g_free (redirected_uri);
 
-                       priv->uri = webcal_to_http_method (newuri, FALSE);
-                       begin_retrieval_cb (cbhttp);
                } else {
-                       if (!priv->opened) {
-                               e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
-                                                           _("Redirected to Invalid URI"));
-                       }
+                       g_set_error (
+                               error, SOUP_HTTP_ERROR,
+                               SOUP_STATUS_BAD_REQUEST,
+                               _("Redirected to Invalid URI"));
+                       success = FALSE;
                }
 
-               g_object_unref (cbhttp);
-               return;
+               g_object_unref (soup_message);
+               return success;
        }
 
        /* check status code */
-       if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
-               if (!priv->opened) {
-                       if (msg->status_code == 401 || msg->status_code == 403) {
-                               priv->requires_auth = TRUE;
-                               e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
-                               g_object_unref (cbhttp);
-                               return;
-                       } else if (msg->status_code == SOUP_STATUS_SSL_FAILED) {
-                               ESource *source = e_backend_get_source (E_BACKEND (cbhttp));
-                               gchar *err_msg;
-
-                               if (g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") == 0) {
-                                       err_msg = g_strdup_printf (_("Failed to connect to a server using SSL: %s"),
-                                               msg->reason_phrase && *msg->reason_phrase ? msg->reason_phrase :
-                                               (soup_status_get_phrase (msg->status_code) ? soup_status_get_phrase (msg->status_code) : _("Unknown error")));
-                               } else {
-                                       err_msg = g_strdup (_("Failed to connect to a server using SSL. "
-                                               "One possible reason is an invalid certificate being used by the server. "
-                                               "If this is expected, like self-signed certificate being used on the server, "
-                                               "then disable certificate validity tests by selecting 'Ignore invalid SSL certificate' option "
-                                               "in Properties"));
-                               }
-
-                               e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp), err_msg);
-                               g_free (err_msg);
-                       } else
-                               e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
-                                       msg->reason_phrase && *msg->reason_phrase ? msg->reason_phrase :
-                                       (soup_status_get_phrase (msg->status_code) ? soup_status_get_phrase (msg->status_code) : _("Unknown error")));
-               }
-
-               empty_cache (cbhttp);
-               g_object_unref (cbhttp);
-               return;
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
+               g_set_error (
+                       error, SOUP_HTTP_ERROR, status_code,
+                       "%s", soup_message->reason_phrase);
+               g_object_unref (soup_message);
+               empty_cache (backend);
+               return FALSE;
        }
 
        if (priv->store) {
-               const gchar *etag = soup_message_headers_get_one (msg->response_headers, "ETag");
+               const gchar *etag;
+
+               etag = soup_message_headers_get_one (
+                       soup_message->response_headers, "ETag");
 
                if (etag != NULL && *etag == '\0')
                        etag = NULL;
@@ -456,25 +584,32 @@ retrieval_done (SoupSession *session,
        }
 
        /* get the calendar from the response */
-       icalcomp = icalparser_parse_string (msg->response_body->data);
+       icalcomp = icalparser_parse_string (soup_message->response_body->data);
 
        if (!icalcomp) {
-               if (!priv->opened)
-                       e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp), _("Bad file format."));
-               empty_cache (cbhttp);
-               g_object_unref (cbhttp);
-               return;
+               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) {
-               if (!priv->opened)
-                       e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp), _("Not a calendar."));
+               g_set_error (
+                       error, SOUP_HTTP_ERROR,
+                       SOUP_STATUS_MALFORMED,
+                       _("Not a calendar."));
                icalcomponent_free (icalcomp);
-               empty_cache (cbhttp);
-               g_object_unref (cbhttp);
-               return;
+               g_object_unref (soup_message);
+               empty_cache (backend);
+               return FALSE;
        }
 
+       g_object_unref (soup_message);
+       soup_message = NULL;
+
        /* Update cache */
        old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
@@ -490,7 +625,7 @@ retrieval_done (SoupSession *session,
                g_object_unref (comp);
        }
 
-       kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbhttp));
+       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) {
@@ -514,18 +649,18 @@ retrieval_done (SoupSession *session,
 
                                e_cal_component_get_uid (comp, &uid);
 
-                               if (!put_component_to_store (cbhttp, comp)) {
+                               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 (cbhttp), orig_comp, comp);
+                                       e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp);
 
                                        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 (cbhttp), comp);
+                                       e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp);
                                }
                        }
 
@@ -546,7 +681,7 @@ retrieval_done (SoupSession *session,
        e_cal_backend_store_thaw_changes (priv->store);
 
        /* notify the removals */
-       g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, cbhttp);
+       g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend);
        g_hash_table_destroy (old_cache);
 
        /* free memory */
@@ -554,123 +689,112 @@ retrieval_done (SoupSession *session,
 
        priv->opened = TRUE;
 
-       g_object_unref (cbhttp);
-
-       d(g_message ("Retrieval really done.\n"));
+       return TRUE;
 }
 
-/* ************************************************************************* */
-/* Authentication helpers for libsoup */
-
-static void
-soup_authenticate (SoupSession *session,
-                   SoupMessage *msg,
-                   SoupAuth *auth,
-                   gboolean retrying,
-                   gpointer data)
+static const gchar *
+cal_backend_http_ensure_uri (ECalBackendHttp *backend)
 {
-       ECalBackendHttpPrivate *priv;
-       ECalBackendHttp        *cbhttp;
+       ESource *source;
+       ESourceSecurity *security_extension;
+       ESourceWebdav *webdav_extension;
+       SoupURI *soup_uri;
+       EProxy *proxy;
+       gboolean secure_connection;
+       const gchar *extension_name;
+       gchar *uri_string;
 
-       cbhttp = E_CAL_BACKEND_HTTP (data);
-       priv =  cbhttp->priv;
+       if (backend->priv->uri != NULL)
+               return backend->priv->uri;
 
-       if (!retrying && priv->credentials && e_credentials_has_key (priv->credentials, E_CREDENTIALS_KEY_USERNAME)) {
-               soup_auth_authenticate (auth, e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME), e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_PASSWORD));
-               e_credentials_clear_peek (priv->credentials);
-       }
-}
+       source = e_backend_get_source (E_BACKEND (backend));
 
-static gboolean reload_cb                  (ECalBackendHttp *cbhttp);
-static void     maybe_start_reload_timeout (ECalBackendHttp *cbhttp);
+       extension_name = E_SOURCE_EXTENSION_SECURITY;
+       security_extension = e_source_get_extension (source, extension_name);
 
-static gboolean
-begin_retrieval_cb (ECalBackendHttp *cbhttp)
-{
-       ECalBackendHttpPrivate *priv;
-       SoupMessage *soup_message;
+       extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+       webdav_extension = e_source_get_extension (source, extension_name);
 
-       priv = cbhttp->priv;
+       secure_connection = e_source_security_get_secure (security_extension);
 
-       if (!e_backend_get_online (E_BACKEND (cbhttp)))
-               return FALSE;
+       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+       uri_string = soup_uri_to_string (soup_uri, FALSE);
+       soup_uri_free (soup_uri);
 
-       maybe_start_reload_timeout (cbhttp);
+       backend->priv->uri = webcal_to_http_method (
+               uri_string, secure_connection);
 
-       d(g_message ("Starting retrieval...\n"));
+       g_free (uri_string);
 
-       if (priv->is_loading)
-               return FALSE;
+       /* set the HTTP proxy, if configuration is set to do so */
 
-       priv->is_loading = TRUE;
+       proxy = e_proxy_new ();
+       e_proxy_setup_proxy (proxy);
 
-       if (priv->uri == NULL) {
-               ESource *source = e_backend_get_source (E_BACKEND (cbhttp));
-               const gchar *secure_prop = e_source_get_property (source, "use_ssl");
-               gchar *uri = e_source_get_uri (source);
+       if (e_proxy_require_proxy_for_uri (proxy, backend->priv->uri))
+               soup_uri = e_proxy_peek_uri_for (proxy, backend->priv->uri);
+       else
+               soup_uri = NULL;
 
-               priv->uri = webcal_to_http_method (uri,
-                       (secure_prop && g_str_equal(secure_prop, "1")));
+       g_object_set (
+               G_OBJECT (backend->priv->soup_session),
+               SOUP_SESSION_PROXY_URI, soup_uri, NULL);
 
-               g_free (uri);
-       }
+       g_object_unref (proxy);
 
-       /* create the Soup session if not already created */
-       if (!priv->soup_session) {
-               EProxy *proxy;
-               SoupURI *proxy_uri = NULL;
-               ESource *source = e_backend_get_source (E_BACKEND (cbhttp));
+       return backend->priv->uri;
+}
 
-               priv->soup_session = soup_session_async_new_with_options (
-                       SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
-                       g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") != 0,
-                       NULL);
+static void     maybe_start_reload_timeout (ECalBackendHttp *cbhttp);
 
-               g_signal_connect (priv->soup_session, "authenticate",
-                                 G_CALLBACK (soup_authenticate), cbhttp);
+static gboolean
+begin_retrieval_cb (GIOSchedulerJob *job,
+                    GCancellable *cancellable,
+                    ECalBackendHttp *backend)
+{
+       ESource *source;
+       ESourceRegistry *registry;
+       const gchar *uri;
+       GError *error = NULL;
 
-               if (g_getenv ("WEBCAL_DEBUG") != NULL) {
-                       SoupLogger *logger;
+       if (!e_backend_get_online (E_BACKEND (backend)))
+               return FALSE;
 
-                       logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, 1024 * 1024);
-                       soup_session_add_feature (priv->soup_session, SOUP_SESSION_FEATURE (logger));
-                       g_object_unref (logger);
-               }
+       maybe_start_reload_timeout (backend);
 
-               /* set the HTTP proxy, if configuration is set to do so */
-               proxy = e_proxy_new ();
-               e_proxy_setup_proxy (proxy);
-               if (e_proxy_require_proxy_for_uri (proxy, priv->uri)) {
-                       proxy_uri = e_proxy_peek_uri_for (proxy, priv->uri);
-               }
+       if (backend->priv->is_loading)
+               return FALSE;
 
-               g_object_set (G_OBJECT (priv->soup_session), SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
+       d(g_message ("Starting retrieval...\n"));
 
-               g_object_unref (proxy);
-       }
+       backend->priv->is_loading = TRUE;
 
-       /* create message to be sent to server */
-       soup_message = soup_message_new (SOUP_METHOD_GET, priv->uri);
-       if (soup_message == NULL) {
-               priv->is_loading = FALSE;
-               empty_cache (cbhttp);
-               return FALSE;
+       source = e_backend_get_source (E_BACKEND (backend));
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+
+       uri = cal_backend_http_ensure_uri (backend);
+       cal_backend_http_load (backend, cancellable, uri, &error);
+
+       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+               g_clear_error (&error);
+               e_source_registry_authenticate_sync (
+                       registry, source,
+                       E_SOURCE_AUTHENTICATOR (backend),
+                       cancellable, &error);
        }
 
-       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 (priv->store) {
-               const gchar *etag = e_cal_backend_store_get_key_value (priv->store, "ETag");
+       backend->priv->is_loading = FALSE;
 
-               if (etag && *etag)
-                       soup_message_headers_append (soup_message->request_headers, "If-None-Match", etag);
+       if (error != NULL) {
+               e_cal_backend_notify_error (
+                       E_CAL_BACKEND (backend),
+                       error->message);
+               empty_cache (backend);
+               g_error_free (error);
        }
 
-       soup_session_queue_message (priv->soup_session, soup_message,
-                                   (SoupSessionCallback) retrieval_done, g_object_ref (cbhttp));
+       d(g_message ("Retrieval really done.\n"));
 
-       d(g_message ("Retrieval started.\n"));
        return FALSE;
 }
 
@@ -687,7 +811,13 @@ reload_cb (ECalBackendHttp *cbhttp)
        d(g_message ("Reload!\n"));
 
        priv->reload_timeout_id = 0;
-       begin_retrieval_cb (cbhttp);
+
+       g_io_scheduler_push_job (
+               (GIOSchedulerJobFunc) begin_retrieval_cb,
+               g_object_ref (cbhttp),
+               (GDestroyNotify) g_object_unref,
+               G_PRIORITY_DEFAULT, NULL);
+
        return FALSE;
 }
 
@@ -696,7 +826,9 @@ maybe_start_reload_timeout (ECalBackendHttp *cbhttp)
 {
        ECalBackendHttpPrivate *priv;
        ESource *source;
-       const gchar *refresh_str;
+       ESourceRefresh *extension;
+       const gchar *extension_name;
+       guint interval_in_minutes = 0;
 
        priv = cbhttp->priv;
 
@@ -711,10 +843,17 @@ maybe_start_reload_timeout (ECalBackendHttp *cbhttp)
                return;
        }
 
-       refresh_str = e_source_get_property (source, "refresh");
+       extension_name = E_SOURCE_EXTENSION_REFRESH;
+       extension = e_source_get_extension (source, extension_name);
+
+       if (e_source_refresh_get_enabled (extension))
+               interval_in_minutes =
+                       e_source_refresh_get_interval_minutes (extension);
 
-       priv->reload_timeout_id = g_timeout_add ((refresh_str ? atoi (refresh_str) : 30) * 60000,
-                                                (GSourceFunc) reload_cb, cbhttp);
+       if (interval_in_minutes > 0)
+               priv->reload_timeout_id = g_timeout_add_seconds (
+                       interval_in_minutes * 60,
+                       (GSourceFunc) reload_cb, cbhttp);
 }
 
 static void
@@ -724,27 +863,27 @@ source_changed_cb (ESource *source,
        g_return_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp));
 
        if (cbhttp->priv->uri != NULL) {
-               ESource *source;
-               const gchar *secure_prop;
-               gchar *new_uri;
+               gboolean uri_changed;
+               const gchar *new_uri;
+               gchar *old_uri;
 
-               source = e_backend_get_source (E_BACKEND (cbhttp));
-               secure_prop = e_source_get_property (source, "use_ssl");
+               old_uri = g_strdup (cbhttp->priv->uri);
 
-               new_uri = webcal_to_http_method (
-                       e_source_get_uri (source),
-                       (secure_prop && g_str_equal(secure_prop, "1")));
+               g_free (cbhttp->priv->uri);
+               cbhttp->priv->uri = NULL;
 
-               if (new_uri && !g_str_equal (cbhttp->priv->uri, new_uri)) {
-                       /* uri changed, do reload some time soon */
-                       g_free (cbhttp->priv->uri);
-                       cbhttp->priv->uri = NULL;
+               new_uri = cal_backend_http_ensure_uri (cbhttp);
 
-                       if (!cbhttp->priv->is_loading)
-                               g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
-               }
+               uri_changed = (g_strcmp0 (old_uri, new_uri) != 0);
 
-               g_free (new_uri);
+               if (uri_changed && !cbhttp->priv->is_loading)
+                       g_io_scheduler_push_job (
+                               (GIOSchedulerJobFunc) begin_retrieval_cb,
+                               g_object_ref (cbhttp),
+                               (GDestroyNotify) g_object_unref,
+                               G_PRIORITY_DEFAULT, NULL);
+
+               g_free (old_uri);
        }
 }
 
@@ -759,6 +898,12 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        ECalBackendHttp *cbhttp;
        ECalBackendHttpPrivate *priv;
        ESource *source;
+       ESourceRegistry *registry;
+       ESourceAuthentication *auth_extension;
+       const gchar *extension_name;
+       const gchar *cache_dir;
+       gboolean auth_required;
+       gboolean opened = TRUE;
        gboolean online;
        gchar *tmp;
 
@@ -772,6 +917,13 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        }
 
        source = e_backend_get_source (E_BACKEND (backend));
+       cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));
+
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+
+       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+       auth_extension = e_source_get_extension (source, extension_name);
+       auth_required = e_source_authentication_required (auth_extension);
 
        if (priv->source_changed_id == 0) {
                priv->source_changed_id = g_signal_connect (
@@ -785,10 +937,6 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        g_free (tmp);
 
        if (priv->store == NULL) {
-               const gchar *cache_dir;
-
-               cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));
-
                /* remove the old cache while migrating to ECalBackendStore */
                e_cal_backend_cache_remove (cache_dir, "cache.xml");
                priv->store = e_cal_backend_file_store_new (cache_dir);
@@ -812,54 +960,34 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        e_cal_backend_notify_online (E_CAL_BACKEND (backend), online);
 
        if (online) {
-               if (priv->soup_session)
-                       g_object_set (G_OBJECT (priv->soup_session),
-                               SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
-                               g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") != 0,
-                               NULL);
-
-               if (e_source_get_property (source, "auth")) {
-                       e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
-               } else if (priv->requires_auth && perror && !*perror) {
-                       g_propagate_error (perror, EDC_ERROR (AuthenticationRequired));
-                       e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (AuthenticationRequired));
-               } else {
-                       e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
-                       g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
+               const gchar *uri;
+               GError *local_error = NULL;
+
+               uri = cal_backend_http_ensure_uri (cbhttp);
+
+               if (!auth_required) {
+                       opened = cal_backend_http_load (
+                               cbhttp, cancellable,
+                               uri, &local_error);
+                       auth_required = g_error_matches (
+                               local_error, SOUP_HTTP_ERROR,
+                               SOUP_STATUS_UNAUTHORIZED);
                }
-       } else {
-               e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
-       }
-}
-
-static void
-e_cal_backend_http_authenticate_user (ECalBackendSync *backend,
-                                      GCancellable *cancellable,
-                                      ECredentials *credentials,
-                                      GError **error)
-{
-       ECalBackendHttp        *cbhttp;
-       ECalBackendHttpPrivate *priv;
-
-       cbhttp = E_CAL_BACKEND_HTTP (backend);
-       priv  = cbhttp->priv;
-
-       if (priv->credentials && credentials && e_credentials_equal_keys (priv->credentials, credentials, E_CREDENTIALS_KEY_USERNAME, E_CREDENTIALS_KEY_PASSWORD, NULL)) {
-               g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
-               return;
-       }
 
-       e_credentials_free (priv->credentials);
-       priv->credentials = NULL;
+               if (auth_required) {
+                       g_clear_error (&local_error);
+                       opened = e_source_registry_authenticate_sync (
+                               registry, source,
+                               E_SOURCE_AUTHENTICATOR (backend),
+                               cancellable, &local_error);
+               }
 
-       if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
-               g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
-               return;
+               if (local_error != NULL)
+                       g_propagate_error (perror, local_error);
        }
 
-       priv->credentials = e_credentials_new_clone (credentials);
-
-       g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
+       if (opened)
+               e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 }
 
 static void
@@ -927,7 +1055,11 @@ e_cal_backend_http_notify_online_cb (ECalBackend *backend,
                }
        } else {
                if (loaded)
-                       g_idle_add ((GSourceFunc) begin_retrieval_cb, backend);
+                       g_io_scheduler_push_job (
+                               (GIOSchedulerJobFunc) begin_retrieval_cb,
+                               g_object_ref (backend),
+                               (GDestroyNotify) g_object_unref,
+                               G_PRIORITY_DEFAULT, NULL);
        }
 
        if (loaded)
@@ -1248,6 +1380,7 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
                                   GSList **freebusy,
                                   GError **error)
 {
+       ESourceRegistry *registry;
        ECalBackendHttp *cbhttp;
        ECalBackendHttpPrivate *priv;
        gchar *address, *name;
@@ -1265,8 +1398,10 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
                return;
        }
 
+       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
+
        if (users == NULL) {
-               if (e_cal_backend_mail_account_get_default (&address, &name)) {
+               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);
@@ -1278,7 +1413,7 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend,
                const GSList *l;
                for (l = users; l != NULL; l = l->next ) {
                        address = l->data;
-                       if (e_cal_backend_mail_account_is_valid (address, &name)) {
+                       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);
@@ -1382,6 +1517,38 @@ e_cal_backend_http_internal_get_timezone (ECalBackend *backend,
        return zone;
 }
 
+static ESourceAuthenticationResult
+cal_backend_http_try_password_sync (ESourceAuthenticator *authenticator,
+                                    const GString *password,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+       ECalBackendHttp *backend;
+       ESourceAuthenticationResult result;
+       const gchar *uri;
+       GError *local_error = NULL;
+
+       backend = E_CAL_BACKEND_HTTP (authenticator);
+
+       g_free (backend->priv->password);
+       backend->priv->password = g_strdup (password->str);
+
+       uri = cal_backend_http_ensure_uri (backend);
+       cal_backend_http_load (backend, cancellable, uri, &local_error);
+
+       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 {
+               result = E_SOURCE_AUTHENTICATION_ERROR;
+               g_propagate_error (error, local_error);
+       }
+
+       return result;
+}
+
 /* Object initialization function for the file backend */
 static void
 e_cal_backend_http_init (ECalBackendHttp *cbhttp)
@@ -1411,10 +1578,10 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *class)
 
        object_class->dispose = e_cal_backend_http_dispose;
        object_class->finalize = e_cal_backend_http_finalize;
+       object_class->constructed = e_cal_backend_http_constructed;
 
        sync_class->get_backend_property_sync   = e_cal_backend_http_get_backend_property;
        sync_class->open_sync                   = e_cal_backend_http_open;
-       sync_class->authenticate_user_sync      = e_cal_backend_http_authenticate_user;
        sync_class->refresh_sync                = e_cal_backend_http_refresh;
        sync_class->remove_sync                 = e_cal_backend_http_remove;
        sync_class->create_objects_sync         = e_cal_backend_http_create_objects;
@@ -1430,3 +1597,10 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *class)
        backend_class->start_view               = e_cal_backend_http_start_view;
        backend_class->internal_get_timezone    = e_cal_backend_http_internal_get_timezone;
 }
+
+static void
+e_cal_backend_http_source_authenticator_init (ESourceAuthenticatorInterface *interface)
+{
+       interface->try_password_sync = cal_backend_http_try_password_sync;
+}
+