[evolution-data-server] imapx: Adapt to Camel's new authentication API.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] imapx: Adapt to Camel's new authentication API.
- Date: Sat, 15 Oct 2011 14:59:43 +0000 (UTC)
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]