Re: Adding tny_camel_account_get_supported_secure_authentication().



OK. So here's the patch changed to use a TnyList of TnyPairs. Permission
to commit?

-- 
Murray Cumming
murrayc murrayc com
www.murrayc.com
www.openismus.com
Index: libtinymail-camel/tny-camel-account-priv.h
===================================================================
--- libtinymail-camel/tny-camel-account-priv.h	(revision 1964)
+++ libtinymail-camel/tny-camel-account-priv.h	(working copy)
@@ -27,8 +27,12 @@
 struct _TnyCamelAccountPriv
 {
 	TnySessionCamel *session;
+	
 	GStaticRecMutex *service_lock;
+	
+	/* Set in tny_camel_store_account_prepare(). */
 	CamelService *service;
+	
 	CamelException *ex;
 	gchar *url_string, *id, *user, *host, *proto, *mech;
 	TnyGetPassFunc get_pass_func;
Index: libtinymail-camel/tny-camel-common.c
===================================================================
--- libtinymail-camel/tny-camel-common.c	(revision 1964)
+++ libtinymail-camel/tny-camel-common.c	(working copy)
@@ -29,6 +29,18 @@
 
 #include <tny-folder-store-query.h>
 
+/* TODOL Rename to tny_camel_session_check_operation. */
+/** _tny_session_check_operation:
+ * @session: A camel session.
+ * @err: A pointer to a GError*, which will be set if the session is not ready. 
+ * This should be freed with g_error_free().
+ * @domain The error domain for the GError, if necessary.
+ * @code The error code for the GError if necessary.
+ * @result: TRUE if the session is ready to be used.
+ *
+ * Check that the session is ready to be used, and create a GError with the specified 
+ * domain and code if the session is not ready.
+ **/
 gboolean 
 _tny_session_check_operation (TnySessionCamel *session, GError **err, GQuark domain, gint code)
 {
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(revision 1964)
+++ libtinymail-camel/tny-camel-store-account.c	(working copy)
@@ -91,8 +91,11 @@
 		GList *options = apriv->options;
 		gchar *proto;
 
-		if (apriv->proto == NULL)
+		if (apriv->proto == NULL) {
+			g_warning ("%s: apriv->proto is NULL. "
+				"You might need to call tny_account_set_proto().", __FUNCTION__);
 			return;
+		}
 
 		proto = g_strdup_printf ("%s://", apriv->proto); 
 
Index: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c	(revision 1964)
+++ libtinymail-camel/tny-camel-account.c	(working copy)
@@ -29,6 +29,8 @@
 #include <tny-folder.h>
 #include <tny-camel-folder.h>
 #include <tny-error.h>
+#include <tny-simple-list.h>
+#include <tny-pair.h>
 
 #include <camel/camel.h>
 #include <camel/camel-session.h>
@@ -47,6 +49,10 @@
 #include "tny-camel-account-priv.h"
 #include "tny-session-camel-priv.h"
 
+#define TINYMAIL_ENABLE_PRIVATE_API
+#include "tny-common-priv.h"
+#undef TINYMAIL_ENABLE_PRIVATE_API
+
 static GObjectClass *parent_class = NULL;
 
 static gboolean 
@@ -282,6 +288,8 @@
 	return NULL;
 }
 
+/* TODO: Documentation.
+ */
 void 
 _tny_camel_account_start_camel_operation_n (TnyCamelAccount *self, CamelOperationStatusFunc func, gpointer user_data, const gchar *what, gboolean cancel)
 {
@@ -331,12 +339,21 @@
 	return;
 }
 
+/* TODO: Documentation. 
+ * Why would we use this instead of just calling the callback directly in an 
+ * idle handler? 
+ * How does this allow the operation to be cancelled? Can the user cancel it, 
+ * or does cancel happen only if there is an internal error?
+ * murrayc.
+ */
 void 
 _tny_camel_account_start_camel_operation (TnyCamelAccount *self, CamelOperationStatusFunc func, gpointer user_data, const gchar *what)
 {
 	_tny_camel_account_start_camel_operation_n (self, func, user_data, what, TRUE);
 }
 
+/* TODO: Documentation.
+ */
 void 
 _tny_camel_account_stop_camel_operation (TnyCamelAccount *self)
 {
@@ -1109,3 +1126,261 @@
 
 	return type;
 }
+
+typedef struct 
+{
+	TnyCamelAccount *self;
+	TnyCamelGetSupportedSecureAuthCallback callback;
+	TnyStatusCallback status_callback;
+	gpointer user_data;
+	gboolean cancelled;
+	TnyList *result;
+	/* This stops us from calling a status callback after the operation has 
+	 * finished. */
+	TnyIdleStopper* stopper;
+	GError *err;
+	TnySessionCamel *session;
+} GetSupportedAuthInfo;
+
+
+static void
+tny_camel_account_get_supported_secure_authentication_async_status (struct _CamelOperation *op, const char *what, int sofar, int oftotal, void *thr_user_data)
+{
+	printf ("DEBUG: %s\n", __FUNCTION__);
+	
+	/* Use the generic tny_progress* idle callback system 
+	 * to call our status callback,
+	 * using the IdleStopper to stop the status callback 
+	 * from being called after the main callback: */
+	GetSupportedAuthInfo *info = thr_user_data;
+	TnyProgressInfo *progress_info = tny_progress_info_new (
+		G_OBJECT (info->self), 
+		info->status_callback, 
+		TNY_GET_SUPPORTED_SECURE_AUTH_STATUS, 
+		TNY_GET_SUPPORTED_SECURE_AUTH_STATUS_GET_SECURE_AUTH, 
+		what, sofar, 
+		oftotal, info->stopper, info->user_data);
+
+	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+		tny_progress_info_idle_func, progress_info, 
+		tny_progress_info_destroy);
+}
+		
+/** This is the GDestroyNotify callback provided to g_idle_add_full()
+ * for tny_camel_account_get_supported_secure_authentication_async_callback().
+ */
+static void
+tny_camel_account_get_supported_secure_authentication_async_destroyer (gpointer thr_user_data)
+{
+	printf ("DEBUG: %s)\n", __FUNCTION__);
+		
+	GetSupportedAuthInfo *info = thr_user_data;
+	TnyCamelAccount *self = info->self;
+	TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+
+	/* thread reference */
+	g_object_unref (G_OBJECT (self));
+	if (info->err) {
+		g_error_free (info->err);
+		info->err = NULL;	
+	}
+
+	_tny_session_stop_operation (info->session);
+
+	tny_idle_stopper_destroy (info->stopper);
+	info->stopper = NULL;
+	
+	g_slice_free (GetSupportedAuthInfo, thr_user_data);
+}
+
+static gboolean
+tny_camel_account_get_supported_secure_authentication_async_callback (gpointer thr_user_data)
+{
+	printf ("DEBUG: %s\n", __FUNCTION__);
+		
+	GetSupportedAuthInfo *info = thr_user_data;
+	TnyCamelAccount *self = info->self;
+	TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+
+	if (info->callback) {
+		printf ("DEBUG: %s: Calling callback.\n", __FUNCTION__);
+		info->callback (info->self, info->cancelled, info->result, &info->err, info->user_data);
+	}
+
+	/* Prevent status callbacks from being called after this
+	 * (can happen because the 2 idle callbacks have different priorities)
+	 * by causing tny_idle_stopper_is_stopped() to return TRUE. */
+	tny_idle_stopper_stop (info->stopper);
+
+	return FALSE;
+}
+
+
+/* Starts the operation in the thread: */
+static gpointer 
+tny_camel_account_get_supported_secure_authentication_async_thread (
+	gpointer thr_user_data)
+{
+	printf ("DEBUG: %s\n", __FUNCTION__);
+		
+	GetSupportedAuthInfo *info = thr_user_data;
+	TnyCamelAccount *self = info->self;
+	TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	GError *err = NULL;
+
+	g_static_rec_mutex_lock (priv->service_lock);
+
+	info->cancelled = FALSE;
+
+	/* Make sure that the status callback is called (in an idle handler) 
+	 * while this thread is running: */
+	_tny_camel_account_start_camel_operation (TNY_CAMEL_ACCOUNT (self), 
+		tny_camel_account_get_supported_secure_authentication_async_status, info, 
+		"Querying supported secure authentication methods from server.");
+
+	/* Do the actual work:
+	 * This is happening in a thread, 
+	 * and the status callback is being called regularly while this is 
+	 * happening. */	
+	GList *authtypes = camel_service_query_auth_types (priv->service, &ex);
+	
+	/* The result will be a TnyList of TnyPairs: */
+	TnyList *result = tny_simple_list_new ();
+	GList *iter = authtypes;
+	while (iter) {
+		CamelServiceAuthType *item = (CamelServiceAuthType *)iter->data;
+		if (item) {
+			/* Get the name of the auth method:
+			 * Note that, at least for IMAP, authproto=NULL when 
+			 * name=Password. */
+			printf ("DEBUG: %s: authproto =%s, name=%s\n", __FUNCTION__, item->authproto, item->name);
+			
+			/* We don't use the value part of the TnyPair. */
+			TnyPair *pair = tny_pair_new (item->authproto, NULL);
+			tny_list_append (result, G_OBJECT (pair));
+			g_object_unref (pair);
+		}
+		
+		iter = g_list_next (iter);	
+	}
+	g_list_free (authtypes);
+	authtypes = NULL;
+	
+	
+	/* The work has finished, so clean up and provide the result via the 
+	 * main callback: */
+	info->result = result;
+	
+	info->cancelled = camel_operation_cancel_check (priv->cancel);
+	
+	_tny_camel_account_stop_camel_operation (TNY_CAMEL_ACCOUNT (self));
+
+	/* Create the GError if necessary,
+	 * from the CamelException: */
+	info->err = NULL;
+	if (camel_exception_is_set (&ex))
+	{
+		g_set_error (&err, TNY_FOLDER_ERROR, 
+			TNY_FOLDER_ERROR_REFRESH,
+			camel_exception_get_description (&ex));
+		if (err != NULL)
+			info->err = g_error_copy ((const GError *) err);
+	}
+
+	g_static_rec_mutex_unlock (priv->service_lock);
+
+	/* Call the callback, with the result, in an idle thread,
+	 * and stop this thread: */
+	if (info->callback) {
+		g_idle_add_full (G_PRIORITY_HIGH, 
+				tny_camel_account_get_supported_secure_authentication_async_callback, 
+				info, tny_camel_account_get_supported_secure_authentication_async_destroyer);
+	} else {
+		/* Thread reference */
+		g_object_unref (G_OBJECT (self));
+	}
+	g_thread_exit (NULL);
+
+	return NULL;
+}
+
+
+/*TODO: This should be a vfunc so that it is generally available 
+ * (and implementable) for other imlpementations. But this should not need a 
+ * TnyAccount instance, so we need to find some other object to put the vfunc. 
+ */
+ 
+/* tny_camel_account_get_supported_secure_authentication:
+ * @self: a #TnyCamelAccount object.
+ * @result: A GSList of gchar* secure authentication mechanisms. This 
+ * should be freed with g_slist_free() after calling g_free() on each 
+ * item's data.
+ * 
+ * Query the server for the list of supported secure authentication mechanisms.
+ * The #TnyCamelAccount must have a valid hostname and the port number 
+ * must be set if appropriate.
+ * The returned strings may be used as parameters to 
+ * tny_account_set_secure_auth_mech().
+ */
+void tny_camel_account_get_supported_secure_authentication (
+  TnyCamelAccount *self,
+  TnyCamelGetSupportedSecureAuthCallback callback,
+  TnyStatusCallback status_callback,
+  gpointer user_data)
+{ 
+	TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	g_return_if_fail (callback);
+	g_return_if_fail (priv->session);
+	
+	
+	/* Store all the interesting info in a struct 
+	 * launch a thread and keep that struct-instance around.
+	 * - While the thread is running, we regularly call the status callback in 
+	 * an idle handler.
+	 * - When the thread is finished, the main callback will 
+	 * then be called in an idle handler.
+	 */
+
+	/* Check that the session is ready, and stop with a GError if it is not: */
+	GError *err = NULL;
+	if (!_tny_session_check_operation (priv->session, &err, 
+			TNY_ACCOUNT_ERROR, TNY_ACCOUNT_ERROR_GET_SUPPORTED_AUTH))
+	{
+		if (callback)
+			callback (self, TRUE /* cancelled */, NULL, &err, user_data);
+		g_error_free (err);
+		return;
+	}
+
+
+	/* Idle info for the status callback: */
+	GetSupportedAuthInfo *info = g_slice_new (GetSupportedAuthInfo);
+	info->session = priv->session;
+	info->err = NULL;
+	info->self = self;
+	info->callback = callback;
+	info->result = NULL;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+	
+	/* Use a ref count because we do not know which of the 2 idle callbacks 
+	 * will be the last, and we can only unref self in the last callback:
+	 * This is destroyed in the idle GDestroyNotify callback.
+	 * A shared copy is taken and released by the _tny_progress* callback,
+	 * so that it can prevent the stats callback from being called after 
+	 * the main callback. */
+	info->stopper = tny_idle_stopper_new();
+
+	/* thread reference */
+	g_object_ref (G_OBJECT (self));
+
+	/* This will cause the idle status callback to be called,
+	 * via _tny_camel_account_start_camel_operation,
+	 * and also calls the idle main callback: */
+	printf ("DEBUG: %s: before calling g_thread_create()\n", __FUNCTION__);
+	GThread *thread = g_thread_create (
+		tny_camel_account_get_supported_secure_authentication_async_thread,
+		info, FALSE, NULL);
+}
+
Index: libtinymail-camel/tny-camel-account.h
===================================================================
--- libtinymail-camel/tny-camel-account.h	(revision 1964)
+++ libtinymail-camel/tny-camel-account.h	(working copy)
@@ -88,6 +88,33 @@
 void tny_camel_account_set_session (TnyCamelAccount *self, TnySessionCamel *session);
 void tny_camel_account_set_online (TnyCamelAccount *self, gboolean online, GError **err);
 
+
+/** TnyCamelGetSupportedSecureAuthCallback:
+ *
+ * @self: The TnyCamelAccount on which 
+ * tny_camel_account_get_supported_secure_authentication() was called.
+ * @cancelled: Whether the operation was cancelled.
+ * @auth_types: A TnyList of TnyPair objects. Each TnyPair in the list has a 
+ * supported secure authentication method name as its name. This list must 
+ * be freed with g_object_unref().
+ * @err: A GError if an error occurred, or NULL. This must be freed with 
+ * g_error_free().
+ * @user_data: The user data that was provided to 
+ * tny_camel_account_get_supported_secure_authentication().
+ * 
+ * The callback for tny_camel_account_get_supported_secure_authentication().
+ **/
+typedef void (*TnyCamelGetSupportedSecureAuthCallback) (
+  TnyCamelAccount *self, gboolean cancelled,
+  TnyList *auth_types, GError **err, 
+  gpointer user_data);
+
+void tny_camel_account_get_supported_secure_authentication(
+  TnyCamelAccount *self,
+  TnyCamelGetSupportedSecureAuthCallback callback,
+  TnyStatusCallback status_callback,
+  gpointer user_data);
+
 G_END_DECLS
 
 #endif
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 1964)
+++ ChangeLog	(working copy)
@@ -1,3 +1,14 @@
+2007-05-16  Murray Cumming  <murrayc murrayc com>
+
+	* libtinymail-camel/tny-camel-account.h:
+	* libtinymail-camel/tny-camel-account.c:
+	Added tny_camel_account_get_supported_secure_authentication(), 
+	to get a list of strings for use with tny_account_set_secure_auth_mech(),
+	by querying the server. This is async, providing the result via a callback.
+
+	* libtinymail/tny-error.h: Added TNY_ACCOUNT_ERROR_GET_SUPPORTED_AUTH, 
+	for use by tny_camel_account_get_supported_secure_authentication
+	
 2007-05-16  Sergio Villar Senin  <svillar igalia com>
 
 	* libtinymail-queues/Makefile.am: install libtinymail-queues header
Index: libtinymail/tny-status.h
===================================================================
--- libtinymail/tny-status.h	(revision 1964)
+++ libtinymail/tny-status.h	(working copy)
@@ -33,7 +33,8 @@
 enum _TnyStatusDomain
 {
 	TNY_FOLDER_STATUS = 1,
-	TNY_GET_MSG_QUEUE_STATUS = 2
+	TNY_GET_MSG_QUEUE_STATUS = 2,
+	TNY_GET_SUPPORTED_SECURE_AUTH_STATUS = 3
 };
 
 #define TNY_TYPE_STATUS (tny_status_get_type())
@@ -45,6 +46,7 @@
 	TNY_GET_MSG_QUEUE_STATUS_GET_MSG = 3,
 	TNY_FOLDER_STATUS_CODE_XFER_MSGS = 4,
 	TNY_FOLDER_STATUS_CODE_COPY_FOLDER = 5,
+	TNY_GET_SUPPORTED_SECURE_AUTH_STATUS_GET_SECURE_AUTH = 6
 };
 
 struct _TnyStatus 
Index: libtinymail/tny-enums.h
===================================================================
--- libtinymail/tny-enums.h	(revision 1964)
+++ libtinymail/tny-enums.h	(working copy)
@@ -10,12 +10,14 @@
 	TNY_FOLDER_STATUS_CODE_REFRESH = 1,
 	TNY_FOLDER_STATUS_CODE_GET_MSG = 2,
 	TNY_GET_MSG_QUEUE_STATUS_GET_MSG = 3
+	TNY_GET_SUPPORTED_SECURE_AUTH_STATUS_GET_SECURE_AUTH = 4
 } TnyStatusCode;
 
 typedef enum 
 {
 	TNY_FOLDER_STATUS = 1,
-	TNY_GET_MSG_QUEUE_STATUS  = 2
+	TNY_GET_MSG_QUEUE_STATUS  = 2,
+	TNY_GET_SUPPORTED_SECURE_AUTH_STATUS = 3
 } TnyStatusDomain;
 
 typedef enum {
Index: libtinymail/tny-progress-info.c
===================================================================
--- libtinymail/tny-progress-info.c	(revision 1964)
+++ libtinymail/tny-progress-info.c	(working copy)
@@ -74,6 +74,8 @@
 };
 
 
+/* TODO: What is the purpose of the status domain and code?
+ */
 /** 
  * tny_progress_info_new:
  * @self: the sender of the status event
Index: libtinymail/tny-error.h
===================================================================
--- libtinymail/tny-error.h	(revision 1964)
+++ libtinymail/tny-error.h	(working copy)
@@ -93,6 +93,7 @@
 	TNY_TRANSPORT_ACCOUNT_ERROR_SEND = 13,
 
 	TNY_ACCOUNT_ERROR_TRY_CONNECT = 14,
+	TNY_ACCOUNT_ERROR_GET_SUPPORTED_AUTH = 16,
 
 	TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT = 15
 };


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