[evolution-data-server] imapx: Adapt to Camel's new authentication API.



commit 7f9d70756283db3419bb883c6153a1e06ee78557
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Oct 15 09:50:52 2011 -0400

    imapx: Adapt to Camel's new authentication API.

 camel/providers/imapx/camel-imapx-conn-manager.c |   29 +++-
 camel/providers/imapx/camel-imapx-server.c       |  258 ++++++++++------------
 camel/providers/imapx/camel-imapx-server.h       |    5 +
 camel/providers/imapx/camel-imapx-store.c        |   31 +++
 camel/providers/imapx/camel-imapx-store.h        |    1 +
 5 files changed, 178 insertions(+), 146 deletions(-)
---
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c b/camel/providers/imapx/camel-imapx-conn-manager.c
index 715912c..f1d2e79 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -21,6 +21,7 @@
 
 #include "camel-imapx-conn-manager.h"
 #include "camel-imapx-settings.h"
+#include "camel-imapx-store.h"
 #include "camel-imapx-utils.h"
 
 #define c(...) camel_imapx_debug(conman, __VA_ARGS__)
@@ -350,20 +351,46 @@ imapx_create_new_connection (CamelIMAPXConnManager *con_man,
                              GError **error)
 {
 	CamelIMAPXServer *conn;
+	CamelIMAPXStore *imapx_store;
 	CamelStore *store = con_man->priv->store;
 	CamelService *service;
 	CamelURL *url;
 	ConnectionInfo *cinfo = NULL;
+	gboolean success;
 
 	service = CAMEL_SERVICE (store);
 	url = camel_service_get_camel_url (service);
 
+	imapx_store = CAMEL_IMAPX_STORE (store);
+
 	CON_LOCK (con_man);
 
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
 	conn = camel_imapx_server_new (store, url);
-	if (camel_imapx_server_connect (conn, cancellable, error)) {
+
+	/* XXX As part of the connect operation the CamelIMAPXServer will
+	 *     have to call camel_session_authenticate_sync(), but it has
+	 *     no way to pass itself through in that call so the service
+	 *     knows which CamelIMAPXServer is trying to authenticate.
+	 *
+	 *     IMAPX is the only provider that does multiple connections
+	 *     like this, so I didn't want to pollute the CamelSession and
+	 *     CamelService authentication APIs with an extra argument.
+	 *     Instead we do this little hack so the service knows which
+	 *     CamelIMAPXServer to act on in its authenticate_sync() method.
+	 *
+	 *     Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
+	 *     (and our own CON_LOCK for that matter) we should not have
+	 *     multiple IMAPX connections trying to authenticate at once,
+	 *     so this should be thread-safe.
+	 */
+	imapx_store->authenticating_server = g_object_ref (conn);
+	success = camel_imapx_server_connect (conn, cancellable, error);
+	g_object_unref (imapx_store->authenticating_server);
+	imapx_store->authenticating_server = NULL;
+
+	if (success) {
 		g_object_ref (conn);
 	} else {
 		g_object_unref (conn);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 430d6f1..2b36485 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -3135,179 +3135,147 @@ exit:
 	return TRUE;
 }
 
-static gboolean
-imapx_reconnect (CamelIMAPXServer *is,
-                 GCancellable *cancellable,
-                 GError **error)
+CamelAuthenticationResult
+camel_imapx_server_authenticate (CamelIMAPXServer *is,
+                                 const gchar *mechanism,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
+	CamelAuthenticationResult result;
 	CamelIMAPXCommand *ic;
-	gchar *errbuf = NULL;
 	CamelService *service;
-	CamelSettings *settings;
+	CamelSasl *sasl = NULL;
 	CamelURL *url;
-	gboolean authenticated = FALSE;
-	CamelServiceAuthType *authtype = NULL;
-	guint32 prompt_flags = CAMEL_SESSION_PASSWORD_SECRET;
-	gboolean need_password = FALSE;
-	gboolean use_idle;
-	gboolean use_qresync;
+
+	g_return_val_if_fail (
+		CAMEL_IS_IMAPX_SERVER (is),
+		CAMEL_AUTHENTICATION_REJECTED);
 
 	service = CAMEL_SERVICE (is->store);
 	url = camel_service_get_camel_url (service);
-	settings = camel_service_get_settings (service);
 
-	use_idle = camel_imapx_settings_get_use_idle (
-		CAMEL_IMAPX_SETTINGS (settings));
+	if (mechanism != NULL) {
+		if (!g_hash_table_lookup (is->cinfo->auth_types, mechanism)) {
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("IMAP server %s does not support %s "
+				  "authentication"), url->host, mechanism);
+			return CAMEL_AUTHENTICATION_ERROR;
+		}
 
-	use_qresync = camel_imapx_settings_get_use_qresync (
-		CAMEL_IMAPX_SETTINGS (settings));
+		sasl = camel_sasl_new ("imap", mechanism, service);
+		if (sasl != NULL) {
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("No support for %s authentication"),
+				mechanism);
+			return CAMEL_AUTHENTICATION_ERROR;
+		}
+	}
 
-	while (!authenticated) {
-		CamelSasl *sasl = NULL;
+	if (sasl != NULL) {
+		ic = camel_imapx_command_new (
+			is, "AUTHENTICATE", NULL, cancellable,
+			"AUTHENTICATE %A", sasl);
+	} else {
 		const gchar *password;
 
-		if (authtype && authtype->need_password && !need_password) {
-			/* We tried an empty password, but it didn't work */
-			need_password = TRUE;
-			g_free (errbuf);
-			errbuf = NULL;
-		} else if (errbuf) {
-			/* We need to un-cache the password before prompting again */
-			prompt_flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
-			camel_service_set_password (service, NULL);
+		password = camel_service_get_password (service);
+
+		if (url->user == NULL) {
+			g_set_error_literal (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("Cannot authenticate without a username"));
+			return CAMEL_AUTHENTICATION_ERROR;
 		}
 
-		if (!imapx_connect_to_server (is, cancellable, error))
-			goto exception;
+		if (password == NULL) {
+			g_set_error_literal (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("Authentication password not available"));
+			return CAMEL_AUTHENTICATION_ERROR;
+		}
 
-		if (is->state == IMAPX_AUTHENTICATED)
-			goto preauthed;
+		ic = camel_imapx_command_new (
+			is, "LOGIN", NULL, cancellable,
+			"LOGIN %s %s", url->user, password);
+	}
 
-		if (!authtype && url->authmech) {
-			if (!g_hash_table_lookup (is->cinfo->auth_types, url->authmech)) {
-				if (error && !*error)
-					g_set_error (
-						error, CAMEL_SERVICE_ERROR,
-						CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
-						_("IMAP server %s does not support requested "
-						"authentication type %s"),
-						url->host, url->authmech);
-				goto exception;
-			}
+	imapx_command_run (is, ic);
 
-			authtype = camel_sasl_authtype (url->authmech);
-			if (!authtype) {
-			noauth:
-				if (error && !*error)
-					g_set_error (
-						error, CAMEL_SERVICE_ERROR,
-						CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
-						_("No support for authentication type %s"),
-						url->authmech);
-				goto exception;
-			}
+	if (ic->error == NULL) {
+		if (ic->status->result == IMAPX_OK)
+			result = CAMEL_AUTHENTICATION_ACCEPTED;
+		else
+			result = CAMEL_AUTHENTICATION_REJECTED;
+	} else {
+		g_propagate_error (error, ic->error);
+		ic->error = NULL;
+		result = CAMEL_AUTHENTICATION_ERROR;
+	}
+
+	/* Forget old capabilities after login. */
+	if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
+		if (is->cinfo) {
+			imapx_free_capability (is->cinfo);
+			is->cinfo = NULL;
 		}
 
-		if (authtype) {
-			sasl = camel_sasl_new ("imap", authtype->authproto, service);
-			if (!sasl)
-				goto noauth;
+		if (ic->status->condition == IMAPX_CAPABILITY) {
+			is->cinfo = ic->status->u.cinfo;
+			ic->status->u.cinfo = NULL;
+			c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
+		}
+	}
 
-			/* If this is the *first* attempt, set 'need_password'
-			 * as appropriate. */
-			if (!need_password)
-				need_password = authtype->need_password &&
-					!camel_sasl_try_empty_password_sync (sasl, cancellable, error);
-		} else
-			need_password = TRUE;
+	camel_imapx_command_free (ic);
 
-		password = camel_service_get_password (service);
+	if (sasl != NULL)
+		g_object_unref (sasl);
 
-		if (need_password && password == NULL) {
-			gchar *base_prompt;
-			gchar *full_prompt;
-			gchar *new_passwd;
+	return result;
+}
 
-			base_prompt = camel_session_build_password_prompt (
-					"IMAP", url->user, url->host);
+static gboolean
+imapx_reconnect (CamelIMAPXServer *is,
+                 GCancellable *cancellable,
+                 GError **error)
+{
+	CamelIMAPXCommand *ic;
+	CamelService *service;
+	CamelSession *session;
+	CamelSettings *settings;
+	CamelURL *url;
+	const gchar *mechanism;
+	gboolean use_idle;
+	gboolean use_qresync;
 
-			if (errbuf != NULL)
-				full_prompt = g_strconcat (errbuf, base_prompt, NULL);
-			else
-				full_prompt = g_strdup (base_prompt);
-
-			/* XXX This is a tad awkward.  Maybe define a
-			 *     camel_service_ask_password() that calls
-			 *     camel_session_get_password() and caches
-			 *     the password itself? */
-			new_passwd = camel_session_get_password (
-				is->session, (CamelService *) is->store,
-				full_prompt, "password", prompt_flags, error);
-			camel_service_set_password (service, new_passwd);
-			password = camel_service_get_password (service);
-			g_free (new_passwd);
-
-			g_free (base_prompt);
-			g_free (full_prompt);
-			g_free (errbuf);
-			errbuf = NULL;
-
-			if (password == NULL) {
-				if (error && !*error)
-					g_set_error (
-						error, G_IO_ERROR,
-						G_IO_ERROR_CANCELLED,
-						_("You did not enter a password."));
-				if (sasl)
-					g_object_unref (sasl);
-				goto exception;
-			}
-		}
-		if (sasl) {
-			ic = camel_imapx_command_new (
-				is, "AUTHENTICATE", NULL, cancellable,
-				"AUTHENTICATE %A", sasl);
-			g_object_unref (sasl);
-		} else {
-			ic = camel_imapx_command_new (
-				is, "LOGIN", NULL, cancellable,
-				"LOGIN %s %s", url->user, password);
-		}
+	service = CAMEL_SERVICE (is->store);
+	session = camel_service_get_session (service);
+	settings = camel_service_get_settings (service);
 
-		imapx_command_run (is, ic);
+	url = camel_service_get_camel_url (service);
+	mechanism = url->authmech;
 
-		if (ic->error == NULL && ic->status->result == IMAPX_OK) {
-			/* Forget old capabilities after login */
-			if (is->cinfo) {
-				imapx_free_capability (is->cinfo);
-				is->cinfo = NULL;
-			}
+	use_idle = camel_imapx_settings_get_use_idle (
+		CAMEL_IMAPX_SETTINGS (settings));
 
-			if (ic->status->condition == IMAPX_CAPABILITY) {
-				is->cinfo = ic->status->u.cinfo;
-				ic->status->u.cinfo = NULL;
-				c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
-			}
+	use_qresync = camel_imapx_settings_get_use_qresync (
+		CAMEL_IMAPX_SETTINGS (settings));
 
-			authenticated = TRUE;
-		} else {
-			/* If exception is set, it might be mostly due to cancellation and we would get an
-			 * io error, else re-prompt. If authentication fails for other reasons ic->status would be
-			 * set with the error message */
-			if (ic->error != NULL) {
-				g_propagate_error (error, ic->error);
-				ic->error = NULL;
-				camel_imapx_command_free (ic);
-				goto exception;
-			}
+	if (!imapx_connect_to_server (is, cancellable, error))
+		goto exception;
 
-			errbuf = g_markup_printf_escaped (
-					_("Unable to authenticate to IMAP server.\n%s\n\n"),
-					 ic->status->text);
-		}
+	if (is->state == IMAPX_AUTHENTICATED)
+		goto preauthed;
 
-		camel_imapx_command_free (ic);
-	}
+	if (!camel_session_authenticate_sync (
+		session, service, mechanism, cancellable, error))
+		goto exception;
 
 	/* After login we re-capa unless the server already told us */
 	if (!is->cinfo) {
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 94deb60..9e10bb3 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -145,6 +145,11 @@ gboolean	camel_imapx_server_connect	(CamelIMAPXServer *is,
 gboolean	imapx_connect_to_server		(CamelIMAPXServer *is,
 						 GCancellable *cancellable,
 						 GError **error);
+CamelAuthenticationResult
+		camel_imapx_server_authenticate	(CamelIMAPXServer *is,
+						 const gchar *mechanism,
+						 GCancellable *cancellable,
+						 GError **error);
 GPtrArray *	camel_imapx_server_list		(CamelIMAPXServer *is,
 						 const gchar *top,
 						 guint32 flags,
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index c9216d6..862e6bb 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -109,6 +109,11 @@ imapx_store_dispose (GObject *object)
 		imapx_store->con_man = NULL;
 	}
 
+	if (imapx_store->authenticating_server != NULL) {
+		g_object_unref (imapx_store->authenticating_server);
+		imapx_store->authenticating_server = NULL;
+	}
+
 	if (imapx_store->summary != NULL) {
 		g_object_unref (imapx_store->summary);
 		imapx_store->summary = NULL;
@@ -219,6 +224,31 @@ imapx_disconnect_sync (CamelService *service,
 	return TRUE;
 }
 
+static CamelAuthenticationResult
+imapx_authenticate_sync (CamelService *service,
+                         const gchar *mechanism,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+	CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
+	CamelIMAPXServer *server;
+
+	/* CamelIMAPXConnManager sets this before calling
+	 * camel_imapx_server_connect()(), and then clears it
+	 * immediately after, all while holding the recursive
+	 * connection lock (CAMEL_SERVICE_REC_CONNECT_LOCK).
+	 * Otherwise we'd have no way of knowing which server
+	 * is trying to authenticate. */
+	server = istore->authenticating_server;
+
+	g_return_val_if_fail (
+		CAMEL_IS_IMAPX_SERVER (server),
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	return camel_imapx_server_authenticate (
+		server, mechanism, cancellable, error);
+}
+
 extern CamelServiceAuthType camel_imapx_password_authtype;
 
 static GList *
@@ -1664,6 +1694,7 @@ camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
 	service_class->get_name = imapx_get_name;
 	service_class->connect_sync = imapx_connect_sync;
 	service_class->disconnect_sync = imapx_disconnect_sync;
+	service_class->authenticate_sync = imapx_authenticate_sync;
 	service_class->query_auth_types_sync = imapx_query_auth_types_sync;
 
 	store_class = CAMEL_STORE_CLASS (class);
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index 0baee0d..6449b16 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -60,6 +60,7 @@ struct _CamelIMAPXStore {
 	CamelIMAPXStorePrivate *priv;
 
 	CamelIMAPXConnManager *con_man;
+	CamelIMAPXServer *authenticating_server;
 
 	CamelIMAPXStoreSummary *summary; /* in-memory list of folders */
 	gchar dir_sep;



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