From: Matthew Barnes Date: Fri, 12 Nov 2010 22:46:14 +0000 (-0500) Subject: Adapt address book backends to the new ESource API. X-Git-Tag: upstream/3.7.4~868 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7bba8f8700c7a22cb085df7d6f9f849661b41fdb;p=platform%2Fupstream%2Fevolution-data-server.git Adapt address book backends to the new ESource API. --- diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c index 337e637..042f894 100644 --- a/addressbook/backends/file/e-book-backend-file.c +++ b/addressbook/backends/file/e-book-backend-file.c @@ -323,36 +323,45 @@ maybe_delete_unused_uris (EBookBackendFile *bf, } static gchar * -e_book_backend_file_extract_path_from_source (ESource *source, +e_book_backend_file_extract_path_from_source (ESourceRegistry *registry, + ESource *source, GetPathType path_type) { + ESource *builtin_source; const gchar *user_data_dir; - const gchar *source_dir; - gchar *mangled_source_dir; + const gchar *uid; gchar *filename = NULL; + uid = e_source_get_uid (source); + g_return_val_if_fail (uid != NULL, NULL); + user_data_dir = e_get_user_data_dir (); - source_dir = e_source_peek_relative_uri (source); - if (!source_dir || !g_str_equal (source_dir, "system")) - source_dir = e_source_get_uid (source); + builtin_source = e_source_registry_ref_builtin_address_book (registry); - /* Mangle the URI to not contain invalid characters. */ - mangled_source_dir = g_strdelimit (g_strdup (source_dir), ":/", '_'); + /* XXX Backward-compatibility hack: + * + * The special built-in "Personal" data source UIDs are now named + * "system-$COMPONENT" but since the data directories are already + * split out by component, we'll continue to use the old "system" + * directories for these particular data sources. */ + if (e_source_equal (source, builtin_source)) + uid = "system"; switch (path_type) { - case GET_PATH_DB_DIR: - filename = g_build_filename - (user_data_dir, "addressbook", mangled_source_dir, NULL); - break; - case GET_PATH_PHOTO_DIR: - filename = g_build_filename - (user_data_dir, "addressbook", mangled_source_dir, "photos", NULL); - break; - default: - break; + case GET_PATH_DB_DIR: + filename = g_build_filename ( + user_data_dir, "addressbook", uid, NULL); + break; + case GET_PATH_PHOTO_DIR: + filename = g_build_filename ( + user_data_dir, "addressbook", uid, "photos", NULL); + break; + default: + g_warn_if_reached (); } - g_free (mangled_source_dir); + + g_object_unref (builtin_source); return filename; } @@ -1701,15 +1710,6 @@ e_book_backend_file_stop_book_view (EBookBackend *backend, g_thread_join (closure->thread); } -static void -e_book_backend_file_authenticate_user (EBookBackendSync *backend, - GCancellable *cancellable, - ECredentials *credentials, - GError **perror) -{ - /* Success */ -} - /* ** versions: ** @@ -1879,6 +1879,7 @@ e_book_backend_file_open (EBookBackendSync *backend, EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend); gchar *dirname, *filename; gboolean readonly = TRUE; + ESourceRegistry *registry; ESource *source; gint db_error; DB *db; @@ -1891,8 +1892,9 @@ e_book_backend_file_open (EBookBackendSync *backend, #endif source = e_backend_get_source (E_BACKEND (backend)); + registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend)); dirname = e_book_backend_file_extract_path_from_source ( - source, GET_PATH_DB_DIR); + registry, source, GET_PATH_DB_DIR); filename = g_build_filename (dirname, "addressbook.db", NULL); db_error = e_db3_utils_maybe_recover (filename); @@ -2122,7 +2124,7 @@ e_book_backend_file_open (EBookBackendSync *backend, /* Resolve the photo directory here */ dirname = e_book_backend_file_extract_path_from_source ( - source, GET_PATH_PHOTO_DIR); + registry, source, GET_PATH_PHOTO_DIR); if (!only_if_exists && !create_directory (dirname, perror)) return; bf->priv->photo_dirname = dirname; @@ -2469,7 +2471,6 @@ e_book_backend_file_class_init (EBookBackendFileClass *class) sync_class->get_contact_sync = e_book_backend_file_get_contact; sync_class->get_contact_list_sync = e_book_backend_file_get_contact_list; sync_class->get_contact_list_uids_sync = e_book_backend_file_get_contact_list_uids; - sync_class->authenticate_user_sync = e_book_backend_file_authenticate_user; object_class->dispose = e_book_backend_file_dispose; object_class->finalize = e_book_backend_file_finalize; diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c index 5b94625..7480784 100644 --- a/addressbook/backends/google/e-book-backend-google.c +++ b/addressbook/backends/google/e-book-backend-google.c @@ -27,7 +27,11 @@ #include #include -#include +#include +#include +#include +#include +#include #include #include #include @@ -63,10 +67,17 @@ #define EDB_ERROR(_code) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, NULL) #define EDB_ERROR_EX(_code, _msg) e_data_book_create_error (E_DATA_BOOK_STATUS_ ## _code, _msg) -G_DEFINE_TYPE ( +/* Forward Declarations */ +static void e_book_backend_google_source_authenticator_init + (ESourceAuthenticatorInterface *interface); + +G_DEFINE_TYPE_WITH_CODE ( EBookBackendGoogle, e_book_backend_google, - E_TYPE_BOOK_BACKEND) + E_TYPE_BOOK_BACKEND, + G_IMPLEMENT_INTERFACE ( + E_TYPE_SOURCE_AUTHENTICATOR, + e_book_backend_google_source_authenticator_init)) typedef enum { NO_CACHE, @@ -1232,12 +1243,18 @@ proxy_settings_changed (EProxy *proxy, g_free (uri); } -static void -request_authorization (EBookBackend *backend) +static gboolean +request_authorization (EBookBackend *backend, + GCancellable *cancellable, + GError **error) { EBookBackendGooglePrivate *priv; + ESourceRegistry *registry; + ESource *source; priv = E_BOOK_BACKEND_GOOGLE_GET_PRIVATE (backend); + source = e_backend_get_source (E_BACKEND (backend)); + registry = e_book_backend_get_registry (backend); /* Make sure we have the GDataService configured * before requesting authorization. */ @@ -1280,10 +1297,13 @@ request_authorization (EBookBackend *backend) * is concerned it's always authorized. The GDataAuthorizer * will take care of everything in the background. */ if (E_IS_GDATA_GOA_AUTHORIZER (priv->authorizer)) - return; + return TRUE; #endif - e_book_backend_notify_auth_required (backend, TRUE, NULL); + /* Otherwise it's up to us to obtain a login secret. */ + return e_source_registry_authenticate_sync ( + registry, source, E_SOURCE_AUTHENTICATOR (backend), + cancellable, error); } typedef struct { @@ -2106,6 +2126,7 @@ e_book_backend_google_start_book_view (EBookBackend *backend, { EBookBackendGooglePrivate *priv; GList *cached_contacts; + GError *error = NULL; g_return_if_fail (E_IS_BOOK_BACKEND_GOOGLE (backend)); g_return_if_fail (E_IS_DATA_BOOK_VIEW (bookview)); @@ -2124,9 +2145,11 @@ e_book_backend_google_start_book_view (EBookBackend *backend, /* Update the cache if necessary */ if (cache_needs_update (backend, NULL)) { + /* XXX We ought to be authorized by now, I would think. + * Not sure when we wouldn't be or how to handle it. */ if (!backend_is_authorized (backend)) { - /* We need authorization first */ - request_authorization (backend); + error = EDB_ERROR (AUTHENTICATION_REQUIRED); + goto exit; } else { /* Update in an idle function, so that this call doesn't block */ priv->idle_id = g_idle_add ((GSourceFunc) on_refresh_idle, backend); @@ -2144,7 +2167,9 @@ e_book_backend_google_start_book_view (EBookBackend *backend, g_object_unref (contact); } - e_data_book_view_notify_complete (bookview, NULL /* Success */); +exit: + /* This function frees the GError passed to it. */ + e_data_book_view_notify_complete (bookview, error); } static void @@ -2169,96 +2194,6 @@ e_book_backend_google_stop_book_view (EBookBackend *backend, set_live_mode (backend, FALSE); } -typedef struct { - EBookBackend *backend; - guint32 opid; -} AuthenticateUserData; - -static void -authenticate_client_login_cb (GDataClientLoginAuthorizer *authorizer, - GAsyncResult *result, - AuthenticateUserData *data) -{ - GError *gdata_error = NULL; - GError *book_error = NULL; - - __debug__ (G_STRFUNC); - - /* Finish authenticating */ - gdata_client_login_authorizer_authenticate_finish ( - authorizer, result, &gdata_error); - - if (gdata_error != NULL) { - data_book_error_from_gdata_error (&book_error, gdata_error); - __debug__ ("Authentication failed: %s", gdata_error->message); - } - - finish_operation (data->backend, data->opid, gdata_error); - e_book_backend_notify_readonly (data->backend, gdata_error != NULL); - e_book_backend_notify_opened (data->backend, book_error); - - g_object_unref (data->backend); - g_slice_free (AuthenticateUserData, data); - - g_clear_error (&gdata_error); -} - -static void -e_book_backend_google_authenticate_user (EBookBackend *backend, - GCancellable *cancellable, - ECredentials *credentials) -{ - EBookBackendGooglePrivate *priv; - AuthenticateUserData *data; - guint32 opid; - - priv = E_BOOK_BACKEND_GOOGLE_GET_PRIVATE (backend); - - __debug__ (G_STRFUNC); - - if (!e_backend_get_online (E_BACKEND (backend))) { - e_book_backend_notify_readonly (backend, TRUE); - e_book_backend_notify_online (backend, FALSE); - e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS)); - return; - } - - if (backend_is_authorized (backend)) { - g_warning ("Connection to Google already established."); - e_book_backend_notify_readonly (backend, FALSE); - e_book_backend_notify_opened (backend, NULL); - return; - } - - if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME) || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PASSWORD)) { - e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_REQUIRED)); - return; - } - - opid = -1; - while (g_hash_table_lookup (priv->cancellables, GUINT_TO_POINTER (opid))) - opid--; - - /* Authenticate with the server asynchronously */ - data = g_slice_new (AuthenticateUserData); - data->backend = g_object_ref (backend); - data->opid = opid; - - cancellable = start_operation ( - backend, opid, cancellable, - _("Authenticating with the server…")); - - gdata_client_login_authorizer_authenticate_async ( - GDATA_CLIENT_LOGIN_AUTHORIZER (priv->authorizer), - e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME), - e_credentials_peek (credentials, E_CREDENTIALS_KEY_PASSWORD), - cancellable, - (GAsyncReadyCallback) authenticate_client_login_cb, - data); - - g_object_unref (cancellable); -} - static void e_book_backend_google_remove (EBookBackend *backend, EDataBook *book, @@ -2277,11 +2212,15 @@ e_book_backend_google_open (EBookBackend *backend, gboolean only_if_exists) { EBookBackendGooglePrivate *priv; - const gchar *refresh_interval_str, *use_ssl_str, *use_cache_str; - guint refresh_interval; - gboolean use_ssl, use_cache; + ESourceOffline *offline_extension; + ESourceRefresh *refresh_extension; + ESourceSecurity *security_extension; ESource *source; + guint interval_in_minutes; + gboolean use_ssl, use_cache; + const gchar *extension_name; gboolean is_online; + GError *error = NULL; priv = E_BOOK_BACKEND_GOOGLE_GET_PRIVATE (backend); @@ -2294,24 +2233,22 @@ e_book_backend_google_open (EBookBackend *backend, source = e_backend_get_source (E_BACKEND (backend)); - /* Parse various other properties */ - refresh_interval_str = e_source_get_property (source, "refresh-interval"); - use_ssl_str = e_source_get_property (source, "ssl"); - use_cache_str = e_source_get_property (source, "offline_sync"); + extension_name = E_SOURCE_EXTENSION_OFFLINE; + offline_extension = e_source_get_extension (source, extension_name); - refresh_interval = 3600; - if (refresh_interval_str && sscanf (refresh_interval_str, "%u", &refresh_interval) != 1) { - g_warning ("Could not parse refresh-interval!"); - refresh_interval = 3600; - } + extension_name = E_SOURCE_EXTENSION_REFRESH; + refresh_extension = e_source_get_extension (source, extension_name); - use_ssl = TRUE; - if (use_ssl_str && (g_ascii_strcasecmp (use_ssl_str, "false") == 0 || strcmp (use_ssl_str, "0") == 0)) - use_ssl = FALSE; + extension_name = E_SOURCE_EXTENSION_SECURITY; + security_extension = e_source_get_extension (source, extension_name); - use_cache = TRUE; - if (use_cache_str && (g_ascii_strcasecmp (use_cache_str, "false") == 0 || strcmp (use_cache_str, "0") == 0)) - use_cache = FALSE; + interval_in_minutes = + e_source_refresh_get_enabled (refresh_extension) ? + e_source_refresh_get_interval_minutes (refresh_extension) : 0; + + use_ssl = e_source_security_get_secure (security_extension); + + use_cache = e_source_offline_get_stay_synchronized (offline_extension); /* Set up our object */ if (!priv->cancellables) { @@ -2323,10 +2260,10 @@ e_book_backend_google_open (EBookBackend *backend, cache_init (backend, use_cache); priv->use_ssl = use_ssl; - priv->refresh_interval = refresh_interval; + priv->refresh_interval = interval_in_minutes * 60; /* Remove and re-add the timeout */ - if (priv->refresh_id != 0) { + if (priv->refresh_id != 0 && priv->refresh_interval > 0) { g_source_remove (priv->refresh_id); priv->refresh_id = g_timeout_add_seconds (priv->refresh_interval, (GSourceFunc) on_refresh_timeout, backend); } @@ -2337,11 +2274,11 @@ e_book_backend_google_open (EBookBackend *backend, e_book_backend_notify_readonly (backend, TRUE); if (is_online) { - request_authorization (backend); - - /* Refresh the authorizer. This may block. */ - gdata_authorizer_refresh_authorization ( - priv->authorizer, cancellable, NULL); + if (request_authorization (backend, cancellable, &error)) { + /* Refresh the authorizer. This may block. */ + gdata_authorizer_refresh_authorization ( + priv->authorizer, cancellable, &error); + } } if (!is_online || backend_is_authorized (backend)) { @@ -2350,7 +2287,8 @@ e_book_backend_google_open (EBookBackend *backend, e_book_backend_notify_opened (backend, NULL /* Success */); } - e_data_book_respond_open (book, opid, NULL /* Success */); + /* This function frees the GError passed to it. */ + e_data_book_respond_open (book, opid, error); } static void @@ -2552,7 +2490,7 @@ e_book_backend_google_notify_online_cb (EBookBackend *backend, e_book_backend_notify_online (backend, is_online); if (is_online && e_book_backend_is_opened (backend)) { - request_authorization (backend); + request_authorization (backend, NULL, NULL); if (backend_is_authorized (backend)) e_book_backend_notify_readonly (backend, FALSE); } else { @@ -2628,6 +2566,63 @@ e_book_backend_google_finalize (GObject *object) G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object); } +static ESourceAuthenticationResult +book_backend_google_try_password_sync (ESourceAuthenticator *authenticator, + const GString *password, + GCancellable *cancellable, + GError **error) +{ + EBookBackendGooglePrivate *priv; + ESourceAuthentication *auth_extension; + ESourceAuthenticationResult result; + ESource *source; + const gchar *extension_name; + gchar *user; + GError *local_error = NULL; + + __debug__ (G_STRFUNC); + + /* We should not have gotten here if we're offline. */ + g_return_val_if_fail ( + e_backend_get_online (E_BACKEND (authenticator)), + E_SOURCE_AUTHENTICATION_ERROR); + + /* Nor should we have gotten here if we're already authorized. */ + g_return_val_if_fail ( + !backend_is_authorized (E_BOOK_BACKEND (authenticator)), + E_SOURCE_AUTHENTICATION_ERROR); + + priv = E_BOOK_BACKEND_GOOGLE (authenticator)->priv; + + source = e_backend_get_source (E_BACKEND (authenticator)); + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + auth_extension = e_source_get_extension (source, extension_name); + user = e_source_authentication_dup_user (auth_extension); + + gdata_client_login_authorizer_authenticate ( + GDATA_CLIENT_LOGIN_AUTHORIZER (priv->authorizer), + user, password->str, cancellable, &local_error); + + g_free (user); + + if (local_error == NULL) { + result = E_SOURCE_AUTHENTICATION_ACCEPTED; + + } else if (g_error_matches ( + local_error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, + GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION)) { + + g_clear_error (&local_error); + result = E_SOURCE_AUTHENTICATION_REJECTED; + + } else { + g_propagate_error (error, local_error); + result = E_SOURCE_AUTHENTICATION_ERROR; + } + + return result; +} + static void e_book_backend_google_class_init (EBookBackendGoogleClass *class) { @@ -2648,7 +2643,6 @@ e_book_backend_google_class_init (EBookBackendGoogleClass *class) backend_class->get_contact = e_book_backend_google_get_contact; backend_class->get_contact_list = e_book_backend_google_get_contact_list; backend_class->get_contact_list_uids = e_book_backend_google_get_contact_list_uids; - backend_class->authenticate_user = e_book_backend_google_authenticate_user; object_class->dispose = e_book_backend_google_dispose; object_class->finalize = e_book_backend_google_finalize; @@ -2657,6 +2651,12 @@ e_book_backend_google_class_init (EBookBackendGoogleClass *class) } static void +e_book_backend_google_source_authenticator_init (ESourceAuthenticatorInterface *interface) +{ + interface->try_password_sync = book_backend_google_try_password_sync; +} + +static void e_book_backend_google_init (EBookBackendGoogle *backend) { __debug__ (G_STRFUNC); diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c b/addressbook/backends/webdav/e-book-backend-webdav.c index 4ca5e43..1a97d7e 100644 --- a/addressbook/backends/webdav/e-book-backend-webdav.c +++ b/addressbook/backends/webdav/e-book-backend-webdav.c @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include #include @@ -63,10 +66,17 @@ #define WEBDAV_CLOSURE_NAME "EBookBackendWebdav.BookView::closure" #define WEBDAV_CTAG_KEY "WEBDAV_CTAG" -G_DEFINE_TYPE ( +/* Forward Declarations */ +static void e_book_backend_webdav_source_authenticator_init + (ESourceAuthenticatorInterface *interface); + +G_DEFINE_TYPE_WITH_CODE ( EBookBackendWebdav, e_book_backend_webdav, - E_TYPE_BOOK_BACKEND) + E_TYPE_BOOK_BACKEND, + G_IMPLEMENT_INTERFACE ( + E_TYPE_SOURCE_AUTHENTICATOR, + e_book_backend_webdav_source_authenticator_init)) struct _EBookBackendWebdavPrivate { gboolean marked_for_offline; @@ -196,14 +206,20 @@ upload_contact (EBookBackendWebdav *webdav, gchar **reason) { ESource *source; + ESourceWebdav *webdav_extension; SoupMessage *message; gchar *uri; gchar *etag; const gchar *new_etag, *redir_uri; gchar *request; guint status; - const gchar *property; gboolean avoid_ifmatch; + const gchar *extension_name; + + source = e_backend_get_source (E_BACKEND (webdav)); + + extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; + webdav_extension = e_source_get_extension (source, extension_name); source = e_backend_get_source (E_BACKEND (webdav)); @@ -217,12 +233,7 @@ upload_contact (EBookBackendWebdav *webdav, soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT); soup_message_headers_append (message->request_headers, "Connection", "close"); - property = e_source_get_property(source, "avoid_ifmatch"); - if (property != NULL && strcmp(property, "1") == 0) { - avoid_ifmatch = TRUE; - } else { - avoid_ifmatch = FALSE; - } + avoid_ifmatch = e_source_webdav_get_avoid_ifmatch (webdav_extension); /* some servers (like apache < 2.2.8) don't handle If-Match, correctly so * we can leave it out */ @@ -296,7 +307,7 @@ webdav_handle_auth_request (EBookBackendWebdav *webdav) if (priv->username != NULL) { g_free (priv->username); priv->username = NULL; - e_credentials_util_safe_free_string (priv->password); + g_free (priv->password); priv->password = NULL; return EDB_ERROR (AUTHENTICATION_FAILED); @@ -1200,61 +1211,6 @@ e_book_backend_webdav_get_contact_list_uids (EBookBackend *backend, g_slist_free (uids_list); } -static void -e_book_backend_webdav_authenticate_user (EBookBackend *backend, - GCancellable *cancellable, - ECredentials *credentials) -{ - EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); - EBookBackendWebdavPrivate *priv = webdav->priv; - SoupMessage *message; - - priv->username = e_credentials_get (credentials, E_CREDENTIALS_KEY_USERNAME); - priv->password = e_credentials_get (credentials, E_CREDENTIALS_KEY_PASSWORD); - - /* Evolution API requires a direct feedback on the authentication, - * so we send a PROPFIND to test wether user/password is correct */ - message = send_propfind (webdav); - - if (message->status_code == 401 || message->status_code == 407) { - g_free (priv->username); - priv->username = NULL; - e_credentials_util_safe_free_string (priv->password); - priv->password = NULL; - - e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED)); - } else if (SOUP_STATUS_IS_SUCCESSFUL (message->status_code) || message->status_code == 207) { - e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS)); - } else if (message->status_code == SOUP_STATUS_SSL_FAILED) { - ESource *source = e_backend_get_source (E_BACKEND (backend)); - - if (g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") == 0) { - e_book_backend_notify_opened (backend, - e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR, - _("Failed to connect to a server using SSL: %s"), - message->reason_phrase && *message->reason_phrase ? message->reason_phrase : - (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error")))); - } else { - e_book_backend_notify_opened (backend, EDB_ERROR_EX (OTHER_ERROR, - _("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"))); - } - } else { - e_book_backend_notify_opened (backend, - e_data_book_create_error_fmt ( - E_DATA_BOOK_STATUS_OTHER_ERROR, - _("Unexpected HTTP status code %d returned (%s)"), - message->status_code, - message->reason_phrase && *message->reason_phrase ? message->reason_phrase : - (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error")))); - } - - g_object_unref (message); -} - /** authentication callback for libsoup */ static void soup_authenticate (SoupSession *session, @@ -1301,86 +1257,44 @@ e_book_backend_webdav_open (EBookBackend *backend, { EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend); EBookBackendWebdavPrivate *priv = webdav->priv; - ESource *source; - gchar *uri; + ESourceAuthentication *auth_extension; + ESourceOffline *offline_extension; + ESourceWebdav *webdav_extension; + ESourceRegistry *registry; + ESource *source; + const gchar *extension_name; const gchar *cache_dir; - const gchar *offline; - const gchar *use_ssl; gchar *filename; SoupSession *session; SoupURI *suri; - gint port; + GError *error = NULL; /* will try fetch ctag for the first time, if it fails then sets this to FALSE */ priv->supports_getctag = TRUE; + registry = e_book_backend_get_registry (backend); + source = e_backend_get_source (E_BACKEND (backend)); cache_dir = e_book_backend_get_cache_dir (backend); - uri = e_source_get_uri (source); - if (uri == NULL) { - e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "No uri given for addressbook")); - return; - } + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + auth_extension = e_source_get_extension (source, extension_name); - suri = soup_uri_new (uri); - g_free (uri); + extension_name = E_SOURCE_EXTENSION_OFFLINE; + offline_extension = e_source_get_extension (source, extension_name); - if (!suri) { - e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Invalid uri given for addressbook")); - return; - } + extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; + webdav_extension = e_source_get_extension (source, extension_name); - offline = e_source_get_property(source, "offline_sync"); - if (offline && g_str_equal(offline, "1")) - priv->marked_for_offline = TRUE; + priv->marked_for_offline = + e_source_offline_get_stay_synchronized (offline_extension); if (!e_backend_get_online (E_BACKEND (backend)) && !priv->marked_for_offline ) { - soup_uri_free (suri); e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE)); return; } - if (!suri->scheme || !g_str_equal (suri->scheme, "webdav")) { - /* the book is not for us */ - soup_uri_free (suri); - e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Not a webdav uri")); - return; - } - - port = soup_uri_get_port (suri); - use_ssl = e_source_get_property (source, "use_ssl"); - if (use_ssl != NULL && strcmp (use_ssl, "1") == 0) { - soup_uri_set_scheme (suri, "https"); - } else { - soup_uri_set_scheme (suri, "http"); - } - - if (port > 0 && port != soup_uri_get_port (suri)) - soup_uri_set_port (suri, port); - - /* append slash if missing */ - if (!suri->path || !*suri->path || suri->path[strlen (suri->path) - 1] != '/') { - gchar *new_path = g_strconcat (suri->path ? suri->path : "", "/", NULL); - soup_uri_set_path (suri, new_path); - g_free (new_path); - } - - if (suri->host && strchr (suri->host, '@')) { - gchar *at = strchr (suri->host, '@'); - gchar *new_user; - - *at = '\0'; - - new_user = g_strconcat (suri->user ? suri->user : "", "@", suri->host, NULL); - - *at = '@'; - - soup_uri_set_host (suri, at + 1); - soup_uri_set_user (suri, new_user); - - g_free (new_user); - } + suri = e_source_webdav_dup_soup_uri (webdav_extension); priv->uri = soup_uri_to_string (suri, FALSE); if (!priv->uri) { @@ -1393,10 +1307,14 @@ e_book_backend_webdav_open (EBookBackend *backend, priv->cache = e_book_backend_cache_new (filename); g_free (filename); - session = soup_session_sync_new_with_options ( - SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, - g_strcmp0 (e_source_get_property (source, "ignore-invalid-cert"), "1") != 0, - NULL); + session = soup_session_sync_new (); + + g_object_bind_property ( + webdav_extension, "ignore-invalid-cert", + session, SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, + G_BINDING_SYNC_CREATE | + G_BINDING_INVERT_BOOLEAN); + g_signal_connect ( session, "authenticate", G_CALLBACK (soup_authenticate), webdav); @@ -1410,13 +1328,19 @@ e_book_backend_webdav_open (EBookBackend *backend, proxy_settings_changed (priv->proxy, priv); webdav_debug_setup (priv->session); - e_book_backend_notify_auth_required (backend, TRUE, NULL); e_book_backend_notify_online (backend, TRUE); e_book_backend_notify_readonly (backend, FALSE); + if (e_source_authentication_required (auth_extension)) + e_source_registry_authenticate_sync ( + registry, source, + E_SOURCE_AUTHENTICATOR (backend), + cancellable, &error); + soup_uri_free (suri); - e_data_book_respond_open (book, opid, NULL /* Success */); + /* This function frees the GError passed to it. */ + e_data_book_respond_open (book, opid, error); } static void @@ -1495,13 +1419,65 @@ e_book_backend_webdav_dispose (GObject *object) g_free (priv->uri); g_free (priv->username); - if (priv->password) { e_credentials_util_safe_free_string (priv->password); priv->password = NULL; } + g_free (priv->password); #undef do_unref G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->dispose (object); } +static ESourceAuthenticationResult +book_backend_webdav_try_password_sync (ESourceAuthenticator *authenticator, + const GString *password, + GCancellable *cancellable, + GError **error) +{ + EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (authenticator); + ESourceAuthentication *auth_extension; + ESourceAuthenticationResult result; + ESource *source; + SoupMessage *message; + const gchar *extension_name; + + source = e_backend_get_source (E_BACKEND (authenticator)); + extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; + auth_extension = e_source_get_extension (source, extension_name); + + webdav->priv->username = + e_source_authentication_dup_user (auth_extension); + webdav->priv->password = g_strdup (password->str); + + /* Send a PROPFIND to test whether user/password is correct. */ + message = send_propfind (webdav); + + switch (message->status_code) { + case SOUP_STATUS_OK: + result = E_SOURCE_AUTHENTICATION_ACCEPTED; + break; + + case SOUP_STATUS_UNAUTHORIZED: + case SOUP_STATUS_PROXY_UNAUTHORIZED: /* XXX really? */ + g_free (webdav->priv->username); + webdav->priv->username = NULL; + g_free (webdav->priv->password); + webdav->priv->password = NULL; + result = E_SOURCE_AUTHENTICATION_REJECTED; + break; + + default: + g_set_error ( + error, SOUP_HTTP_ERROR, + message->status_code, + "%s", message->reason_phrase); + result = E_SOURCE_AUTHENTICATION_ERROR; + break; + } + + g_object_unref (message); + + return result; +} + static void e_book_backend_webdav_class_init (EBookBackendWebdavClass *class) { @@ -1524,13 +1500,18 @@ e_book_backend_webdav_class_init (EBookBackendWebdavClass *class) backend_class->get_contact_list_uids = e_book_backend_webdav_get_contact_list_uids; backend_class->start_book_view = e_book_backend_webdav_start_book_view; backend_class->stop_book_view = e_book_backend_webdav_stop_book_view; - backend_class->authenticate_user = e_book_backend_webdav_authenticate_user; backend_class->remove = e_book_backend_webdav_remove; object_class->dispose = e_book_backend_webdav_dispose; } static void +e_book_backend_webdav_source_authenticator_init (ESourceAuthenticatorInterface *interface) +{ + interface->try_password_sync = book_backend_webdav_try_password_sync; +} + +static void e_book_backend_webdav_init (EBookBackendWebdav *backend) { backend->priv = E_BOOK_BACKEND_WEBDAV_GET_PRIVATE (backend);