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



commit 68c269a66bd484768b9c1517e7dc2dd30f682485
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Oct 15 09:51:35 2011 -0400

    smtp: Adapt to Camel's new authentication API.

 camel/providers/smtp/camel-smtp-transport.c |  460 +++++++++++----------------
 1 files changed, 184 insertions(+), 276 deletions(-)
---
diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c
index 330b4c8..ef7c0fa 100644
--- a/camel/providers/smtp/camel-smtp-transport.c
+++ b/camel/providers/smtp/camel-smtp-transport.c
@@ -60,10 +60,6 @@ static GHashTable *	esmtp_get_authtypes	(const guchar *buffer);
 static gboolean		smtp_helo		(CamelSmtpTransport *transport,
 						 GCancellable *cancellable,
 						 GError **error);
-static gboolean		smtp_auth		(CamelSmtpTransport *transport,
-						 CamelSasl *sasl,
-						 GCancellable *cancellable,
-						 GError **error);
 static gboolean		smtp_mail		(CamelSmtpTransport *transport,
 						 const gchar *sender,
 						 gboolean has_8bit_parts,
@@ -286,14 +282,16 @@ smtp_transport_connect_sync (CamelService *service,
                              GError **error)
 {
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
-	CamelSasl *sasl = NULL;
 	CamelURL *url;
-	gboolean has_authtypes;
+	const gchar *mechanism;
+	gboolean auth_required;
+	gboolean success = TRUE;
 
 	url = camel_service_get_camel_url (service);
+	mechanism = url->authmech;
 
 	/* We (probably) need to check popb4smtp before we connect ... */
-	if (url->authmech && !strcmp (url->authmech, "POPB4SMTP")) {
+	if (g_strcmp0 (mechanism, "POPB4SMTP") == 0) {
 		gint truth;
 		GByteArray *chal;
 		CamelSasl *sasl;
@@ -315,141 +313,35 @@ smtp_transport_connect_sync (CamelService *service,
 		return FALSE;
 
 	/* check to see if AUTH is required, if so...then AUTH ourselves */
-	has_authtypes = transport->authtypes ? g_hash_table_size (transport->authtypes) > 0 : FALSE;
-	if (url->authmech && (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) && has_authtypes) {
-		CamelSession *session = camel_service_get_session (service);
-		CamelServiceAuthType *authtype;
-		gboolean authenticated = FALSE;
-		guint32 password_flags;
-		gchar *errbuf = NULL;
-
-		if (!g_hash_table_lookup (transport->authtypes, url->authmech)) {
-			g_set_error (
-				error, CAMEL_SERVICE_ERROR,
-				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
-				_("SMTP server %s does not support "
-				  "requested authentication type %s."),
-				url->host, url->authmech);
-			camel_service_disconnect_sync (service, TRUE, NULL);
-			return FALSE;
-		}
+	auth_required =
+		(mechanism != NULL) &&
+		(transport->authtypes != NULL) &&
+		(g_hash_table_size (transport->authtypes) > 0) &&
+		(transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP);
+
+	if (auth_required) {
+		CamelSession *session;
+
+		session = camel_service_get_session (service);
 
-		authtype = camel_sasl_authtype (url->authmech);
-		if (!authtype) {
+		if (g_hash_table_lookup (transport->authtypes, mechanism)) {
+			success = camel_session_authenticate_sync (
+				session, service, mechanism,
+				cancellable, error);
+		} else {
 			g_set_error (
 				error, CAMEL_SERVICE_ERROR,
 				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
-				_("No support for authentication type %s"),
-				url->authmech);
-			camel_service_disconnect_sync (service, TRUE, NULL);
-			return FALSE;
+				_("SMTP server %s does not support %s "
+				  "authentication"), url->host, mechanism);
+			success = FALSE;
 		}
 
-		sasl = camel_sasl_new ("smtp", url->authmech,
-				       CAMEL_SERVICE (transport));
-
-		if (!sasl) {
-		nosasl:
-			g_set_error (
-				     error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-				     _("Error creating SASL authentication object."));
+		if (!success)
 			camel_service_disconnect_sync (service, TRUE, NULL);
-			return FALSE;
-		}
-		if (!authtype->need_password ||
-		    camel_sasl_try_empty_password_sync (sasl, cancellable, error)) {
-			authenticated = smtp_auth (transport, sasl, cancellable, error);
-			if (!authenticated && !authtype->need_password) {
-				/* authentication mechanism doesn't need a password,
-				 * so if it fails there's nothing we can do */
-				camel_service_disconnect_sync (
-					service, TRUE, NULL);
-				return FALSE;
-			}
-		}
-
-		password_flags = CAMEL_SESSION_PASSWORD_SECRET;
-
-		/* keep trying to login until either we succeed or the user cancels */
-		while (!authenticated) {
-			const gchar *password;
-			GError *local_error = NULL;
-
-			if (errbuf) {
-				/* We need to un-cache the password before prompting again */
-				password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
-				camel_service_set_password (service, NULL);
-			}
-
-			password = camel_service_get_password (service);
-
-			if (password == NULL) {
-				gchar *base_prompt;
-				gchar *full_prompt;
-				gchar *new_passwd;
-
-				base_prompt = camel_session_build_password_prompt (
-					"SMTP", url->user, url->host);
-
-				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 (
-					session, service, full_prompt,
-					"password", password_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) {
-					camel_service_disconnect_sync (
-						service, TRUE, NULL);
-					return FALSE;
-				}
-			}
-			if (!sasl)
-				sasl = camel_sasl_new ("smtp", url->authmech,
-						       CAMEL_SERVICE (transport));
-			if (!sasl)
-				goto nosasl;
-
-			authenticated = smtp_auth (transport, sasl, cancellable, &local_error);
-			sasl = NULL;
-			if (!authenticated) {
-				if (g_cancellable_is_cancelled (cancellable) ||
-				    g_error_matches (local_error, CAMEL_SERVICE_ERROR, CAMEL_SERVICE_ERROR_UNAVAILABLE)) {
-					camel_service_set_password (service, NULL);
-
-					if (local_error)
-						g_clear_error (&local_error);
-
-					return FALSE;
-				}
-
-				errbuf = g_markup_printf_escaped (
-					_("Unable to authenticate "
-					  "to SMTP server.\n%s\n\n"),
-					local_error ? local_error->message : _("Unknown error"));
-				g_clear_error (&local_error);
-
-				camel_service_set_password (service, NULL);
-			}
-
-		}
 	}
 
-	return TRUE;
+	return success;
 }
 
 static gboolean
@@ -499,6 +391,164 @@ smtp_transport_disconnect_sync (CamelService *service,
 	return TRUE;
 }
 
+static CamelAuthenticationResult
+smtp_transport_authenticate_sync (CamelService *service,
+                                  const gchar *mechanism,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
+	CamelAuthenticationResult result;
+	CamelSasl *sasl;
+	gchar *cmdbuf, *respbuf = NULL, *challenge;
+	gboolean auth_challenge = FALSE;
+
+	if (mechanism == NULL) {
+		g_set_error (
+			error, CAMEL_SERVICE_ERROR,
+			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+			_("No SASL mechanism was specified"));
+		return CAMEL_AUTHENTICATION_ERROR;
+	}
+
+	sasl = camel_sasl_new ("smtp", 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;
+	}
+
+	camel_operation_push_message (cancellable, _("SMTP Authentication"));
+
+	challenge = camel_sasl_challenge_base64_sync (
+		sasl, NULL, cancellable, error);
+	if (challenge) {
+		auth_challenge = TRUE;
+		cmdbuf = g_strdup_printf (
+			"AUTH %s %s\r\n", mechanism, challenge);
+		g_free (challenge);
+	} else {
+		cmdbuf = g_strdup_printf (
+			"AUTH %s\r\n", mechanism);
+	}
+
+	d(fprintf (stderr, "sending : %s", cmdbuf));
+	if (camel_stream_write_string (
+		transport->ostream, cmdbuf,
+		cancellable, error) == -1) {
+		g_free (cmdbuf);
+		g_prefix_error (error, _("AUTH command failed: "));
+		goto lose;
+	}
+	g_free (cmdbuf);
+
+	respbuf = camel_stream_buffer_read_line (
+		CAMEL_STREAM_BUFFER (transport->istream),
+		cancellable, error);
+
+	while (!camel_sasl_get_authenticated (sasl)) {
+		if (!respbuf) {
+			g_prefix_error (error, _("AUTH command failed: "));
+			transport->connected = FALSE;
+			goto lose;
+		}
+
+		/* the server may have accepted our initial response */
+		if (strncmp (respbuf, "235", 3) == 0)
+			break;
+
+		/* the server challenge/response should follow a 334 code */
+		if (strncmp (respbuf, "334", 3) != 0) {
+			smtp_set_error (
+				transport, respbuf, cancellable, error);
+			g_prefix_error (error, _("AUTH command failed: "));
+			goto lose;
+		}
+
+		if (FALSE) {
+		broken_smtp_server:
+			d(fprintf (stderr, "Your SMTP server's implementation of the %s SASL\n"
+				   "authentication mechanism is broken. Please report this to the\n"
+				   "appropriate vendor and suggest that they re-read rfc2554 again\n"
+				   "for the first time (specifically Section 4).\n",
+				   mechanism));
+		}
+
+		/* eat whtspc */
+		for (challenge = respbuf + 4; isspace (*challenge); challenge++);
+
+		challenge = camel_sasl_challenge_base64_sync (
+			sasl, challenge, cancellable, error);
+		if (challenge == NULL)
+			goto break_and_lose;
+
+		g_free (respbuf);
+
+		/* send our challenge */
+		cmdbuf = g_strdup_printf ("%s\r\n", challenge);
+		g_free (challenge);
+		d(fprintf (stderr, "sending : %s", cmdbuf));
+		if (camel_stream_write_string (
+			transport->ostream, cmdbuf,
+			cancellable, error) == -1) {
+			g_free (cmdbuf);
+			goto lose;
+		}
+		g_free (cmdbuf);
+
+		/* get the server's response */
+		respbuf = camel_stream_buffer_read_line (
+			CAMEL_STREAM_BUFFER (transport->istream),
+			cancellable, error);
+	}
+
+	if (respbuf == NULL)
+		goto lose;
+
+	/* Work around broken SASL implementations. */
+	if (auth_challenge && strncmp (respbuf, "334", 3) == 0)
+		goto broken_smtp_server;
+
+	/* If our authentication data was rejected, destroy the
+	 * password so that the user gets prompted to try again. */
+	if (strncmp (respbuf, "535", 3) == 0)
+		result = CAMEL_AUTHENTICATION_REJECTED;
+	else
+		result = CAMEL_AUTHENTICATION_ACCEPTED;
+
+	/* Catch any other errors. */
+	if (strncmp (respbuf, "235", 3) != 0) {
+		g_set_error (
+			error, CAMEL_SERVICE_ERROR,
+			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+			_("Bad authentication response from server."));
+		goto lose;
+	}
+
+	goto exit;
+
+break_and_lose:
+	/* Get the server out of "waiting for continuation data" mode. */
+	d(fprintf (stderr, "sending : *\n"));
+	camel_stream_write (transport->ostream, "*\r\n", 3, cancellable, NULL);
+	respbuf = camel_stream_buffer_read_line (
+		CAMEL_STREAM_BUFFER (transport->istream), cancellable, NULL);
+	d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
+
+lose:
+	result = CAMEL_AUTHENTICATION_ERROR;
+
+exit:
+	camel_operation_pop_message (cancellable);
+
+	g_object_unref (sasl);
+	g_free (respbuf);
+
+	return result;
+}
+
 static GList *
 smtp_transport_query_auth_types_sync (CamelService *service,
                                       GCancellable *cancellable,
@@ -680,6 +730,7 @@ camel_smtp_transport_class_init (CamelSmtpTransportClass *class)
 	service_class->get_name = smtp_transport_get_name;
 	service_class->connect_sync = smtp_transport_connect_sync;
 	service_class->disconnect_sync = smtp_transport_disconnect_sync;
+	service_class->authenticate_sync = smtp_transport_authenticate_sync;
 	service_class->query_auth_types_sync = smtp_transport_query_auth_types_sync;
 
 	transport_class = CAMEL_TRANSPORT_CLASS (class);
@@ -1113,149 +1164,6 @@ smtp_helo (CamelSmtpTransport *transport,
 }
 
 static gboolean
-smtp_auth (CamelSmtpTransport *transport,
-           CamelSasl *sasl,
-           GCancellable *cancellable,
-           GError **error)
-{
-	CamelService *service;
-	CamelURL *url;
-	gchar *cmdbuf, *respbuf = NULL, *challenge;
-	gboolean auth_challenge = FALSE;
-
-	service = CAMEL_SERVICE (transport);
-	url = camel_service_get_camel_url (service);
-
-	camel_operation_push_message (cancellable, _("SMTP Authentication"));
-
-	challenge = camel_sasl_challenge_base64_sync (
-		sasl, NULL, cancellable, error);
-	if (challenge) {
-		auth_challenge = TRUE;
-		cmdbuf = g_strdup_printf (
-			"AUTH %s %s\r\n", url->authmech, challenge);
-		g_free (challenge);
-	} else {
-		cmdbuf = g_strdup_printf (
-			"AUTH %s\r\n", url->authmech);
-	}
-
-	d(fprintf (stderr, "sending : %s", cmdbuf));
-	if (camel_stream_write_string (
-		transport->ostream, cmdbuf,
-		cancellable, error) == -1) {
-		g_free (cmdbuf);
-		g_prefix_error (error, _("AUTH command failed: "));
-		goto lose;
-	}
-	g_free (cmdbuf);
-
-	respbuf = camel_stream_buffer_read_line (
-		CAMEL_STREAM_BUFFER (transport->istream),
-		cancellable, error);
-
-	while (!camel_sasl_get_authenticated (sasl)) {
-		if (!respbuf) {
-			g_prefix_error (error, _("AUTH command failed: "));
-			transport->connected = FALSE;
-			goto lose;
-		}
-
-		/* the server may have accepted our initial response */
-		if (strncmp (respbuf, "235", 3) == 0)
-			break;
-
-		/* the server challenge/response should follow a 334 code */
-		if (strncmp (respbuf, "334", 3) != 0) {
-			smtp_set_error (
-				transport, respbuf, cancellable, error);
-			g_prefix_error (error, _("AUTH command failed: "));
-			goto lose;
-		}
-
-		if (FALSE) {
-		broken_smtp_server:
-			d(fprintf (stderr, "Your SMTP server's implementation of the %s SASL\n"
-				   "authentication mechanism is broken. Please report this to the\n"
-				   "appropriate vendor and suggest that they re-read rfc2554 again\n"
-				   "for the first time (specifically Section 4).\n",
-				   url->authmech));
-		}
-
-		/* eat whtspc */
-		for (challenge = respbuf + 4; isspace (*challenge); challenge++);
-
-		challenge = camel_sasl_challenge_base64_sync (
-			sasl, challenge, cancellable, error);
-		if (challenge == NULL)
-			goto break_and_lose;
-
-		g_free (respbuf);
-
-		/* send our challenge */
-		cmdbuf = g_strdup_printf ("%s\r\n", challenge);
-		g_free (challenge);
-		d(fprintf (stderr, "sending : %s", cmdbuf));
-		if (camel_stream_write_string (
-			transport->ostream, cmdbuf,
-			cancellable, error) == -1) {
-			g_free (cmdbuf);
-			goto lose;
-		}
-		g_free (cmdbuf);
-
-		/* get the server's response */
-		respbuf = camel_stream_buffer_read_line (
-			CAMEL_STREAM_BUFFER (transport->istream),
-			cancellable, error);
-	}
-
-	if (respbuf == NULL)
-		goto lose;
-
-	/* Work around broken SASL implementations. */
-	if (auth_challenge && strncmp (respbuf, "334", 3) == 0)
-		goto broken_smtp_server;
-
-	/* If our authentication data was rejected, destroy the
-	 * password so that the user gets prompted to try again. */
-	if (strncmp (respbuf, "535", 3) == 0)
-		camel_service_set_password (service, NULL);
-
-	/* Catch any other errors. */
-	if (strncmp (respbuf, "235", 3) != 0) {
-		g_set_error (
-			error, CAMEL_SERVICE_ERROR,
-			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
-			_("Bad authentication response from server."));
-		goto lose;
-	}
-
-	g_object_unref (sasl);
-	camel_operation_pop_message (cancellable);
-
-	g_free (respbuf);
-
-	return TRUE;
-
- break_and_lose:
-	/* Get the server out of "waiting for continuation data" mode. */
-	d(fprintf (stderr, "sending : *\n"));
-	camel_stream_write (transport->ostream, "*\r\n", 3, cancellable, NULL);
-	respbuf = camel_stream_buffer_read_line (
-		CAMEL_STREAM_BUFFER (transport->istream), cancellable, NULL);
-	d(fprintf (stderr, "received: %s\n", respbuf ? respbuf : "(null)"));
-
- lose:
-	g_object_unref (sasl);
-	camel_operation_pop_message (cancellable);
-
-	g_free (respbuf);
-
-	return FALSE;
-}
-
-static gboolean
 smtp_mail (CamelSmtpTransport *transport,
            const gchar *sender,
            gboolean has_8bit_parts,



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