[evolution-data-server] Camel: New authentication API.



commit 8226427259799ab6f8c9a6669a5ddf2cb4d40893
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Oct 15 09:35:43 2011 -0400

    Camel: New authentication API.
    
    Currently each provider has to implement its own authentication loop.
    
    The idea for these changes is add a CamelSession method that executes
    a common authentication loop for all providers:
    
        CamelSessionClass:
    
        gboolean  (*authenticate_sync)   (CamelSession *session,
                                          CamelService *service,
                                          const gchar *mechanism,
                                          GCancellable *cancellable,
                                          GError **error);
    
        void      (*authenticate)        (CamelSession *session,
                                          CamelService *service,
                                          const gchar *mechanism,
                                          gint io_priority,
                                          GCancellable *cancellable,
                                          GAsyncReadyCallback callback,
                                          gpointer user_data);
    
        gboolean  (*authenticate_finish) (CamelSession *session,
                                          GAsyncResult *result,
                                          GError **error);
    
    Each CamelService is then responsible for implementing a new
    authenticate method that makes only ONE authentication attempt and
    returns an appropriate status code:
    
        CamelServiceClass:
    
        CamelAuthenticationResult
                  (*authenticate_sync)   (CamelService *service,
                                          const gchar *mechanism,
                                          GCancellable *cancellable,
                                          GError **error);
    
        void      (*authenticate)        (CamelService *service,
                                          const gchar *mechanism,
                                          gint io_priority,
                                          GCancellable *cancellable,
                                          GAsyncReadyCallback callback,
                                          gpointer user_data);
    
        CamelAuthenticationResult
                  (*authenticate_finish) (CamelService *service,
                                          GAsyncResult *result,
                                          GError **error);
    
    The status codes are defined by the CamelAuthenticationResult enum:
    
        CAMEL_AUTHENTICATION_SUCCESS    : auth credentials were accepted
        CAMEL_AUTHENTICATION_FAILURE    : auth credentials were rejected
        CAMEL_AUTHENTICATION_ERROR      : something went horribly wrong!
    
    CAMEL_AUTHENTICATION_SUCCESS and CAMEL_AUTHENTICATION_ERROR both
    terminate the authentication loop, but CAMEL_AUTHENTICATION_FAILURE
    cycles the loop and asks the CamelService to retry authentication,
    usually after prompting the user to enter a different password.

 camel/camel-enums.h                          |   19 ++
 camel/camel-service.c                        |  213 +++++++++++++++++
 camel/camel-service.h                        |   31 +++
 camel/camel-session.c                        |  315 +++++++++++++++++++++++++-
 camel/camel-session.h                        |   36 +++
 docs/reference/camel/camel-sections.txt      |    7 +
 docs/reference/camel/tmpl/camel-service.sgml |   45 ++++
 docs/reference/camel/tmpl/camel-session.sgml |   49 ++++-
 8 files changed, 703 insertions(+), 12 deletions(-)
---
diff --git a/camel/camel-enums.h b/camel/camel-enums.h
index b0dd07e..3335be0 100644
--- a/camel/camel-enums.h
+++ b/camel/camel-enums.h
@@ -23,6 +23,25 @@
 #ifndef CAMEL_ENUMS_H
 #define CAMEL_ENUMS_H
 
+/**
+ * CamelAuthenticationResult:
+ * @CAMEL_AUTHENTICATION_ERROR:
+ *    An error occurred while authenticating.
+ * @CAMEL_AUTHENTICATION_ACCEPTED:
+ *    Server accepted our authentication attempt.
+ * @CAMEL_AUTHENTICATION_REJECTED:
+ *    Server rejected our authentication attempt.
+ *
+ * Authentication result codes used by #CamelService.
+ *
+ * Since: 3.4
+ **/
+typedef enum {
+	CAMEL_AUTHENTICATION_ERROR,
+	CAMEL_AUTHENTICATION_ACCEPTED,
+	CAMEL_AUTHENTICATION_REJECTED
+} CamelAuthenticationResult;
+
 typedef enum { /*< flags >*/
 	CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY = 1 << 0,
 	CAMEL_FOLDER_HAS_SEARCH_CAPABILITY  = 1 << 1,
diff --git a/camel/camel-service.c b/camel/camel-service.c
index f905b38..fe60401 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -71,6 +71,8 @@ struct _CamelServicePrivate {
 
 struct _AsyncContext {
 	GList *auth_types;
+	gchar *auth_mechanism;
+	CamelAuthenticationResult auth_result;
 };
 
 enum {
@@ -96,6 +98,8 @@ async_context_free (AsyncContext *async_context)
 {
 	g_list_free (async_context->auth_types);
 
+	g_free (async_context->auth_mechanism);
+
 	g_slice_free (AsyncContext, async_context);
 }
 
@@ -450,6 +454,72 @@ service_query_auth_types_sync (CamelService *service,
 }
 
 static void
+service_authenticate_thread (GSimpleAsyncResult *simple,
+                             GObject *object,
+                             GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->auth_result = camel_service_authenticate_sync (
+		CAMEL_SERVICE (object), async_context->auth_mechanism,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+static void
+service_authenticate (CamelService *service,
+                      const gchar *mechanism,
+                      gint io_priority,
+                      GCancellable *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->auth_mechanism = g_strdup (mechanism);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (service), callback, user_data, service_authenticate);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, service_authenticate_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelAuthenticationResult
+service_authenticate_finish (CamelService *service,
+                             GAsyncResult *result,
+                             GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (service), service_authenticate),
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return CAMEL_AUTHENTICATION_ERROR;
+
+	return async_context->auth_result;
+}
+
+static void
 service_query_auth_types_thread (GSimpleAsyncResult *simple,
                                  GObject *object,
                                  GCancellable *cancellable)
@@ -605,6 +675,8 @@ camel_service_class_init (CamelServiceClass *class)
 	class->disconnect_sync = service_disconnect_sync;
 	class->query_auth_types_sync = service_query_auth_types_sync;
 
+	class->authenticate = service_authenticate;
+	class->authenticate_finish = service_authenticate_finish;
 	class->query_auth_types = service_query_auth_types;
 	class->query_auth_types_finish = service_query_auth_types_finish;
 
@@ -1250,6 +1322,147 @@ camel_service_unlock (CamelService *service,
 }
 
 /**
+ * camel_service_authenticate_sync:
+ * @service: a #CamelService
+ * @mechanism: a SASL mechanism name, or %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to authenticate @service using @mechanism and, if necessary,
+ * @service's #CamelService:password property.  The function makes only
+ * ONE attempt at authentication and does not loop.
+ *
+ * If the authentication attempt completed and the server accepted the
+ * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
+ *
+ * If the authentication attempt completed but the server rejected the
+ * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
+ *
+ * If the authentication attempt failed to complete due to a network
+ * communication issue or some other mishap, the function sets @error
+ * and returns #CAMEL_AUTHENTICATION_ERROR.
+ *
+ * Generally this function should only be called from a #CamelSession
+ * subclass in order to implement its own authentication loop.
+ *
+ * Returns: the authentication result
+ *
+ * Since: 3.4
+ **/
+CamelAuthenticationResult
+camel_service_authenticate_sync (CamelService *service,
+                                 const gchar *mechanism,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+	CamelServiceClass *class;
+	CamelAuthenticationResult result;
+
+	g_return_val_if_fail (
+		CAMEL_IS_SERVICE (service),
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	class = CAMEL_SERVICE_GET_CLASS (service);
+	g_return_val_if_fail (
+		class->authenticate_sync != NULL,
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	result = class->authenticate_sync (
+		service, mechanism, cancellable, error);
+	CAMEL_CHECK_GERROR (
+		service, authenticate_sync,
+		result != CAMEL_AUTHENTICATION_ERROR, error);
+
+	return result;
+}
+
+/**
+ * camel_service_authenticate:
+ * @service: a #CamelService
+ * @mechanism: a SASL mechanism name, or %NULL
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously attempts to authenticate @service using @mechanism and,
+ * if necessary, @service's #CamelService:password property.  The function
+ * makes only ONE attempt at authentication and does not loop.
+ *
+ * Generally this function should only be called from a #CamelSession
+ * subclass in order to implement its own authentication loop.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_service_authenticate_finish() to get the result of
+ * the operation.
+ *
+ * Since: 3.4
+ **/
+void
+camel_service_authenticate (CamelService *service,
+                            const gchar *mechanism,
+                            gint io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+	CamelServiceClass *class;
+
+	g_return_if_fail (CAMEL_IS_SERVICE (service));
+
+	class = CAMEL_SERVICE_GET_CLASS (service);
+	g_return_if_fail (class->authenticate != NULL);
+
+	class->authenticate (
+		service, mechanism, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_service_authenticate_finish:
+ * @service: a #CamelService
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_service_authenticate().
+ *
+ * If the authentication attempt completed and the server accepted the
+ * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
+ *
+ * If the authentication attempt completed but the server rejected the
+ * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
+ *
+ * If the authentication attempt failed to complete due to a network
+ * communication issue or some other mishap, the function sets @error
+ * and returns #CAMEL_AUTHENTICATION_ERROR.
+ *
+ * Returns: the authentication result
+ *
+ * Since: 3.4
+ **/
+CamelAuthenticationResult
+camel_service_authenticate_finish (CamelService *service,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	CamelServiceClass *class;
+
+	g_return_val_if_fail (
+		CAMEL_IS_SERVICE (service),
+		CAMEL_AUTHENTICATION_REJECTED);
+	g_return_val_if_fail (
+		G_IS_ASYNC_RESULT (result),
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	class = CAMEL_SERVICE_GET_CLASS (service);
+	g_return_val_if_fail (
+		class->authenticate_finish,
+		CAMEL_AUTHENTICATION_REJECTED);
+
+	return class->authenticate_finish (service, result, error);
+}
+
+/**
  * camel_service_query_auth_types_sync:
  * @service: a #CamelService
  * @cancellable: optional #GCancellable object, or %NULL
diff --git a/camel/camel-service.h b/camel/camel-service.h
index c072998..7020471 100644
--- a/camel/camel-service.h
+++ b/camel/camel-service.h
@@ -117,12 +117,27 @@ struct _CamelServiceClass {
 						 gboolean clean,
 						 GCancellable *cancellable,
 						 GError **error);
+	CamelAuthenticationResult
+			(*authenticate_sync)	(CamelService *service,
+						 const gchar *mechanism,
+						 GCancellable *cancellable,
+						 GError **error);
 	GList *		(*query_auth_types_sync)
 						(CamelService *service,
 						 GCancellable *cancellable,
 						 GError **error);
 
 	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*authenticate)		(CamelService *service,
+						 const gchar *mechanism,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelAuthenticationResult
+			(*authenticate_finish)	(CamelService *service,
+						 GAsyncResult *result,
+						 GError **error);
 	void		(*query_auth_types)	(CamelService *service,
 						 gint io_priority,
 						 GCancellable *cancellable,
@@ -179,6 +194,22 @@ void		camel_service_lock		(CamelService *service,
 void		camel_service_unlock		(CamelService *service,
 						 CamelServiceLock lock);
 
+CamelAuthenticationResult
+		camel_service_authenticate_sync	(CamelService *service,
+						 const gchar *mechanism,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_service_authenticate	(CamelService *service,
+						 const gchar *mechanism,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelAuthenticationResult
+		camel_service_authenticate_finish
+						(CamelService *service,
+						 GAsyncResult *result,
+						 GError **error);
 GList *		camel_service_query_auth_types_sync
 						(CamelService *service,
 						 GCancellable *cancellable,
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 93284d0..f9df499 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -39,14 +39,15 @@
 
 #include "camel-debug.h"
 #include "camel-file-utils.h"
+#include "camel-folder.h"
 #include "camel-marshal.h"
+#include "camel-mime-message.h"
+#include "camel-sasl.h"
 #include "camel-session.h"
 #include "camel-store.h"
 #include "camel-string-utils.h"
 #include "camel-transport.h"
 #include "camel-url.h"
-#include "camel-folder.h"
-#include "camel-mime-message.h"
 
 #define CAMEL_SESSION_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -56,6 +57,7 @@
 
 #define d(x)
 
+typedef struct _AsyncContext AsyncContext;
 typedef struct _JobData JobData;
 
 struct _CamelSessionPrivate {
@@ -76,6 +78,11 @@ struct _CamelSessionPrivate {
 	guint online            : 1;
 };
 
+struct _AsyncContext {
+	CamelService *service;
+	gchar *auth_mechanism;
+};
+
 struct _JobData {
 	CamelSession *session;
 	GCancellable *cancellable;
@@ -105,6 +112,17 @@ static guint signals[LAST_SIGNAL];
 G_DEFINE_TYPE (CamelSession, camel_session, CAMEL_TYPE_OBJECT)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->service != NULL)
+		g_object_unref (async_context->service);
+
+	g_free (async_context->auth_mechanism);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 job_data_free (JobData *job_data)
 {
 	g_object_unref (job_data->session);
@@ -410,6 +428,174 @@ session_add_service (CamelSession *session,
 	return service;
 }
 
+static gboolean
+session_authenticate_sync (CamelSession *session,
+                           CamelService *service,
+                           const gchar *mechanism,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+	CamelServiceAuthType *authtype = NULL;
+	CamelAuthenticationResult result;
+	GError *local_error = NULL;
+
+	/* XXX This authenticate_sync() implementation serves only as
+	 *     a rough example and is not intended to be used as is.
+	 *
+	 *     Any CamelSession subclass should override this method
+	 *     and implement a more complete authentication loop that
+	 *     handles user prompts and password storage.
+	 */
+
+	g_warning (
+		"The default CamelSession.authenticate_sync() "
+		"method is not intended for production use.");
+
+	/* If a SASL mechanism was given and we can't find
+	 * a CamelServiceAuthType for it, fail immediately. */
+	if (mechanism != NULL) {
+		authtype = camel_sasl_authtype (mechanism);
+		if (authtype == NULL) {
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("No support for %s authentication"),
+				mechanism);
+			return FALSE;
+		}
+	}
+
+	/* If the SASL mechanism does not involve a user
+	 * password, then it gets one shot to authenticate. */
+	if (authtype != NULL && !authtype->need_password) {
+		result = camel_service_authenticate_sync (
+			service, mechanism, cancellable, error);
+		if (result == CAMEL_AUTHENTICATION_REJECTED)
+			g_set_error (
+				error, CAMEL_SERVICE_ERROR,
+				CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+				_("%s authentication failed"), mechanism);
+		return (result == CAMEL_AUTHENTICATION_ACCEPTED);
+	}
+
+	/* Some SASL mechanisms can attempt to authenticate without a
+	 * user password being provided (e.g. single-sign-on credentials),
+	 * but can fall back to a user password.  Handle that case next. */
+	if (mechanism != NULL) {
+		CamelProvider *provider;
+		CamelSasl *sasl;
+		const gchar *service_name;
+		gboolean success = FALSE;
+
+		provider = camel_service_get_provider (service);
+		service_name = provider->protocol;
+
+		/* XXX Would be nice if camel_sasl_try_empty_password_sync()
+		 *     returned CamelAuthenticationResult so it's easier to
+		 *     detect errors. */
+		sasl = camel_sasl_new (service_name, mechanism, service);
+		if (sasl != NULL) {
+			success = camel_sasl_try_empty_password_sync (
+				sasl, cancellable, &local_error);
+			g_object_unref (sasl);
+		}
+
+		if (success)
+			return TRUE;
+	}
+
+	/* Abort authentication if we got cancelled.
+	 * Otherwise clear any errors and press on. */
+	if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		return FALSE;
+
+	g_clear_error (&local_error);
+
+retry:
+	/* XXX This is where things get bogus.  In a real implementation you
+	 *     would want to fetch a stored password or prompt the user here.
+	 *     Password should be stashed using camel_service_set_password()
+	 *     before calling camel_service_authenticate_sync(). */
+
+	result = camel_service_authenticate_sync (
+		service, mechanism, cancellable, error);
+
+	if (result == CAMEL_AUTHENTICATION_REJECTED) {
+		/* XXX Request a different password here. */
+		goto retry;
+	}
+
+	if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
+		/* XXX Possibly store the password here using
+		 *     GNOME Keyring or something equivalent. */
+	}
+
+	return (result == CAMEL_AUTHENTICATION_ACCEPTED);
+}
+
+static void
+session_authenticate_thread (GSimpleAsyncResult *simple,
+                             GObject *object,
+                             GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_session_authenticate_sync (
+		CAMEL_SESSION (object), async_context->service,
+		async_context->auth_mechanism, cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+static void
+session_authenticate (CamelSession *session,
+                      CamelService *service,
+                      const gchar *mechanism,
+                      gint io_priority,
+                      GCancellable *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->service = g_object_ref (service);
+	async_context->auth_mechanism = g_strdup (mechanism);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (session), callback, user_data, session_authenticate);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, session_authenticate_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+session_authenticate_finish (CamelSession *session,
+                             GAsyncResult *result,
+                             GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (session), session_authenticate), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
 static void
 camel_session_class_init (CamelSessionClass *class)
 {
@@ -425,6 +611,11 @@ camel_session_class_init (CamelSessionClass *class)
 
 	class->add_service = session_add_service;
 
+	class->authenticate_sync = session_authenticate_sync;
+
+	class->authenticate = session_authenticate;
+	class->authenticate_finish = session_authenticate_finish;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_CHECK_JUNK,
@@ -1394,3 +1585,123 @@ camel_session_get_socks_proxy (CamelSession *session,
 
 	klass->get_socks_proxy (session, for_host, host_ret, port_ret);
 }
+
+/**
+ * camel_session_authenticate_sync:
+ * @session: a #CamelSession
+ * @service: a #CamelService
+ * @mechanism: a SASL mechanism name, or %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Authenticates @service, which may involve repeated calls to
+ * camel_service_authenticate() or camel_service_authenticate_sync().
+ * A #CamelSession subclass is largely responsible for implementing this,
+ * and should handle things like user prompts and secure password storage.
+ * These issues are out-of-scope for Camel.
+ *
+ * If an error occurs, or if authentication is aborted, the function sets
+ * @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+camel_session_authenticate_sync (CamelSession *session,
+                                 CamelService *service,
+                                 const gchar *mechanism,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+	CamelSessionClass *class;
+	gboolean success;
+
+	g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE);
+	g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
+
+	class = CAMEL_SESSION_GET_CLASS (session);
+	g_return_val_if_fail (class->authenticate_sync != NULL, FALSE);
+
+	success = class->authenticate_sync (
+		session, service, mechanism, cancellable, error);
+	CAMEL_CHECK_GERROR (session, authenticate_sync, success, error);
+
+	return success;
+}
+
+/**
+ * camel_session_authenticate:
+ * @session: a #CamelSession
+ * @service: a #CamelService
+ * @mechanism: a SASL mechanism name, or %NULL
+ * @io_priority: the I/O priority for the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously authenticates @service, which may involve repeated calls
+ * to camel_service_authenticate() or camel_service_authenticate_sync().
+ * A #CamelSession subclass is largely responsible for implementing this,
+ * and should handle things like user prompts and secure password storage.
+ * These issues are out-of-scope for Camel.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_session_authenticate_finish() to get the result of
+ * the operation.
+ *
+ * Since: 3.4
+ **/
+void
+camel_session_authenticate (CamelSession *session,
+                            CamelService *service,
+                            const gchar *mechanism,
+                            gint io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+	CamelSessionClass *class;
+
+	g_return_if_fail (CAMEL_IS_SESSION (session));
+	g_return_if_fail (CAMEL_IS_SERVICE (service));
+
+	class = CAMEL_SESSION_GET_CLASS (session);
+	g_return_if_fail (class->authenticate != NULL);
+
+	class->authenticate (
+		session, service, mechanism, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_session_authenticate_finish:
+ * @session: a #CamelSession
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_session_authenticate().
+ *
+ * If an error occurred, or if authentication was aborted, the function
+ * sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+camel_session_authenticate_finish (CamelSession *session,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	CamelSessionClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_SESSION_GET_CLASS (session);
+	g_return_val_if_fail (class->authenticate_finish != NULL, FALSE);
+
+	return class->authenticate_finish (session, result, error);
+}
+
diff --git a/camel/camel-session.h b/camel/camel-session.h
index 26861b2..d53ce44 100644
--- a/camel/camel-session.h
+++ b/camel/camel-session.h
@@ -140,6 +140,25 @@ struct _CamelSessionClass {
 						 gchar **host_ret,
 						 gint *port_ret);
 
+	/* Synchronous I/O Methods */
+	gboolean	(*authenticate_sync)	(CamelSession *session,
+						 CamelService *service,
+						 const gchar *mechanism,
+						 GCancellable *cancellable,
+						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*authenticate)		(CamelSession *session,
+						 CamelService *service,
+						 const gchar *mechanism,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*authenticate_finish)	(CamelSession *session,
+						 GAsyncResult *result,
+						 GError **error);
+
 	/* Signals */
 	void		(*job_started)		(CamelSession *session,
 						 GCancellable *cancellable);
@@ -230,6 +249,23 @@ void		camel_session_lock		(CamelSession *session,
 void		camel_session_unlock		(CamelSession *session,
 						 CamelSessionLock lock);
 
+gboolean	camel_session_authenticate_sync	(CamelSession *session,
+						 CamelService *service,
+						 const gchar *mechanism,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_session_authenticate	(CamelSession *session,
+						 CamelService *service,
+						 const gchar *mechanism,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_session_authenticate_finish
+						(CamelSession *session,
+						 GAsyncResult *result,
+						 GError **error);
+
 G_END_DECLS
 
 #endif /* CAMEL_SESSION_H */
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index b68550c..194c36f 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -1971,6 +1971,10 @@ camel_service_get_connection_status
 CamelServiceLock
 camel_service_lock
 camel_service_unlock
+CamelAuthenticationResult
+camel_service_authenticate_sync
+camel_service_authenticate
+camel_service_authenticate_finish
 camel_service_query_auth_types_sync
 camel_service_query_auth_types
 camel_service_query_auth_types_finish
@@ -2024,6 +2028,9 @@ camel_session_forward_to
 CamelSessionLock
 camel_session_lock
 camel_session_unlock
+camel_session_authenticate_sync
+camel_session_authenticate
+camel_session_authenticate_finish
 <SUBSECTION Standard>
 CAMEL_SESSION
 CAMEL_IS_SESSION
diff --git a/docs/reference/camel/tmpl/camel-service.sgml b/docs/reference/camel/tmpl/camel-service.sgml
index f9d6c93..b3b8517 100644
--- a/docs/reference/camel/tmpl/camel-service.sgml
+++ b/docs/reference/camel/tmpl/camel-service.sgml
@@ -281,6 +281,51 @@ CamelService
 @lock: 
 
 
+<!-- ##### ENUM CamelAuthenticationResult ##### -->
+<para>
+
+</para>
+
+ CAMEL_AUTHENTICATION_ERROR: 
+ CAMEL_AUTHENTICATION_ACCEPTED: 
+ CAMEL_AUTHENTICATION_REJECTED: 
+
+<!-- ##### FUNCTION camel_service_authenticate_sync ##### -->
+<para>
+
+</para>
+
+ service: 
+ mechanism: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_service_authenticate ##### -->
+<para>
+
+</para>
+
+ service: 
+ mechanism: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_service_authenticate_finish ##### -->
+<para>
+
+</para>
+
+ service: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_service_query_auth_types_sync ##### -->
 <para>
 
diff --git a/docs/reference/camel/tmpl/camel-session.sgml b/docs/reference/camel/tmpl/camel-session.sgml
index 3589b46..a979b69 100644
--- a/docs/reference/camel/tmpl/camel-session.sgml
+++ b/docs/reference/camel/tmpl/camel-session.sgml
@@ -91,22 +91,13 @@ CamelSession
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_session_set_socks_proxy ##### -->
-<para>
-
-</para>
-
- session: 
- socks_host: 
- socks_port: 
-
-
 <!-- ##### FUNCTION camel_session_get_socks_proxy ##### -->
 <para>
 
 </para>
 
 @session: 
+ for_host: 
 @host_ret: 
 @port_ret: 
 
@@ -395,3 +386,41 @@ CamelSession
 @lock: 
 
 
+<!-- ##### FUNCTION camel_session_authenticate_sync ##### -->
+<para>
+
+</para>
+
+ session: 
+ service: 
+ mechanism: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_session_authenticate ##### -->
+<para>
+
+</para>
+
+ session: 
+ service: 
+ mechanism: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_session_authenticate_finish ##### -->
+<para>
+
+</para>
+
+ session: 
+ result: 
+ error: 
+ Returns: 
+
+



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