[evolution-kolab/ek-wip-porting] CamelIMAPXExtdConnManager: implement our own paths to the IMAPX untagged



commit f4b3a3e2ee19ca269ee12bc6b8fd52ef7609d09b
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Fri Jan 20 17:19:15 2012 +0100

    CamelIMAPXExtdConnManager: implement our own paths to the IMAPX
                               untagged response handler
    
    * our extended conn manager needs to make sure that the
      code paths in our own extended objects are followed
      down the road to the IMAPX untagged response handler
    * without intervention, CamelIMAPXServer::imapx_untagged()
      will be called upon untagged responses, whereas we
      need to end in CamelIMAPXExtdServer::extd_server_untagged()

 .../imapx/camel-imapx-extd-conn-manager.c          |  258 ++++++++++++++++++--
 1 files changed, 241 insertions(+), 17 deletions(-)
---
diff --git a/src/camel/providers/imapx/camel-imapx-extd-conn-manager.c b/src/camel/providers/imapx/camel-imapx-extd-conn-manager.c
index 6b828f7..9e009db 100644
--- a/src/camel/providers/imapx/camel-imapx-extd-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-extd-conn-manager.c
@@ -29,19 +29,21 @@
 #include <config.h>
 #endif
 
+#include "camel-imapx-utils.h"
 #include "camel-imapx-extd-conn-manager.h"
+#include "camel-imapx-conn-manager-defs.h"
+#include "camel-imapx-conn-manager-friend.h"
 
 /*----------------------------------------------------------------------------*/
 
-/* dupe of enum in camel-imapx-conn-manager.c */
-enum {
-	PROP_0,
-	PROP_STORE
-};
-
 G_DEFINE_TYPE (CamelIMAPXExtdConnManager, camel_imapx_extd_conn_manager, CAMEL_TYPE_IMAPX_CONN_MANAGER)
 
 /*----------------------------------------------------------------------------*/
+/* forward declarations */
+
+static void extd_conn_manager_prune_connections (CamelIMAPXConnManager *self);
+
+/*----------------------------------------------------------------------------*/
 /* object init */
 
 static void
@@ -55,6 +57,8 @@ camel_imapx_extd_conn_manager_dispose (GObject *object)
 {
 	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (object));
 
+	extd_conn_manager_prune_connections (CAMEL_IMAPX_CONN_MANAGER (object));
+
 	G_OBJECT_CLASS (camel_imapx_extd_conn_manager_parent_class)->dispose (object);
 }
 
@@ -67,6 +71,219 @@ camel_imapx_extd_conn_manager_finalize (GObject *object)
 }
 
 /*----------------------------------------------------------------------------*/
+/* local statics */
+
+static void
+extd_conn_manager_free_connection (gpointer data,
+                                   gpointer user_data)
+{
+	/* modified dupe of free_connection() */
+
+	ConnectionInfo *cinfo = (ConnectionInfo *) data;
+	CamelIMAPXExtdServer *eserver = CAMEL_IMAPX_EXTD_SERVER (cinfo->conn);
+
+	/* modified */
+	camel_imapx_extd_server_connect (CAMEL_IMAPX_SERVER (eserver),
+	                                 NULL,
+	                                 NULL);
+
+	g_object_unref (eserver);
+	g_hash_table_destroy (cinfo->folders);
+	g_free (cinfo->selected_folder);
+
+	g_free (cinfo);
+}
+
+static void
+extd_conn_manager_prune_connections (CamelIMAPXConnManager *self)
+{
+	/* modified dupe of imapx_prune_connections */
+
+	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (self));
+
+	CON_LOCK (self);
+
+	self->priv->clearing_connections = TRUE;
+	g_list_foreach (self->priv->connections,
+	                /* modified */
+	                (GFunc) extd_conn_manager_free_connection,
+	                NULL);
+	self->priv->connections = NULL;
+	self->priv->clearing_connections = FALSE;
+
+	CON_UNLOCK (self);
+}
+
+/* TODO destroy unused connections in a time-out loop */
+static void
+extd_conn_manager_shutdown (CamelIMAPXConnManager *self,
+                            CamelIMAPXServer *server)
+{
+	/* modified dupe of imapx_conn_shutdown() */
+
+	GList *l = NULL;
+	ConnectionInfo *cinfo = NULL;
+	gboolean found = FALSE;
+
+	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (self));
+	g_assert (CAMEL_IS_IMAPX_EXTD_SERVER (server));
+
+	/* when clearing connections then other thread than a parser thread,
+	 * in which this function is called, holds the CON_LOCK, thus skip
+	 * this all, because otherwise a deadlock will happen.
+	 * The connection will be freed later anyway. */
+	if (self->priv->clearing_connections) {
+		c(server->tagprefix, "%s: called on %p when clearing connections, skipping it...\n", G_STRFUNC, server);
+		return;
+	}
+
+	CON_LOCK (self);
+
+	for (l = self->priv->connections; l != NULL; l = g_list_next (l)) {
+		cinfo = (ConnectionInfo *) l->data;
+		if (cinfo->conn == server) {
+			found = TRUE;
+			break;
+		}
+	}
+
+	if (found) {
+		self->priv->connections = g_list_remove (self->priv->connections, cinfo);
+		/* modified */
+		extd_conn_manager_free_connection (cinfo, GINT_TO_POINTER (1));
+	}
+
+	CON_UNLOCK (self);
+}
+
+static void
+extd_conn_manager_update_select (CamelIMAPXServer *self,
+                                 const gchar *selected_folder,
+                                 CamelIMAPXConnManager *con_man)
+{
+	GList *l = NULL;
+	ConnectionInfo *cinfo = NULL;
+	gboolean found = FALSE;
+
+	CON_LOCK (con_man);
+
+	for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
+		cinfo = (ConnectionInfo *) l->data;
+		if (cinfo->conn == self) {
+			found = TRUE;
+			break;
+		}
+	}
+
+	if (found) {
+		if (cinfo->selected_folder) {
+			IMAPXJobQueueInfo *jinfo;
+
+			jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
+			if (!g_hash_table_lookup (jinfo->folders, cinfo->selected_folder)) {
+				g_hash_table_remove (cinfo->folders, cinfo->selected_folder);
+				c(self->tagprefix, "Removed folder %s from connection folder list - select changed \n", cinfo->selected_folder);
+			}
+			camel_imapx_destroy_job_queue_info (jinfo);
+			g_free (cinfo->selected_folder);
+		}
+
+		cinfo->selected_folder = g_strdup (selected_folder);
+	}
+
+	CON_UNLOCK (con_man);
+}
+
+static CamelIMAPXExtdServer*
+extd_conn_manager_create_new_connection (CamelIMAPXConnManager *self,
+                                         const gchar *foldername,
+                                         GCancellable *cancellable,
+                                         GError **err)
+{
+	/* modified dupe of imapx_create_new_connection() */
+
+	CamelIMAPXExtdServer *eserver = NULL;
+	CamelIMAPXStore *imapx_store = NULL;
+	CamelStore *store = NULL;
+	CamelService *service = NULL;
+	ConnectionInfo *cinfo = NULL;
+	gboolean success = FALSE;
+
+	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (self));
+	g_assert (foldername != NULL);
+	/* cancellable may be NULL */
+	g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+
+	store = self->priv->store;
+	service = CAMEL_SERVICE (store);
+	imapx_store = CAMEL_IMAPX_STORE (store);
+
+	CON_LOCK (self);
+
+	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	eserver = camel_imapx_extd_server_new (CAMEL_IMAPX_EXTD_STORE (store));
+
+	/* 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 (eserver);
+	success = camel_imapx_extd_server_connect (CAMEL_IMAPX_SERVER (eserver),
+	                                           cancellable,
+	                                           err);
+	g_object_unref (imapx_store->authenticating_server);
+	imapx_store->authenticating_server = NULL;
+
+	if (success) {
+		g_object_ref (eserver);
+	} else {
+		g_object_unref (eserver);
+
+		camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+		CON_UNLOCK (self);
+
+		return NULL;
+	}
+
+	/* modified */
+	g_signal_connect (eserver, "shutdown", G_CALLBACK (extd_conn_manager_shutdown), self);
+	g_signal_connect (eserver, "select_changed", G_CALLBACK (extd_conn_manager_update_select), self);
+
+	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	cinfo = g_new0 (ConnectionInfo, 1);
+	cinfo->conn = CAMEL_IMAPX_SERVER (eserver);
+	cinfo->folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+
+	if (foldername)
+		g_hash_table_insert (cinfo->folders, g_strdup (foldername), GINT_TO_POINTER (1));
+
+	self->priv->connections = g_list_prepend (self->priv->connections, cinfo);
+
+	c(CAMEL_IMAPX_SERVER (eserver)->tagprefix,
+	  "Created new connection for %s and total connections %d \n",
+	  foldername,
+	  g_list_length (self->priv->connections));
+
+	CON_UNLOCK (self);
+
+	return eserver;
+}
+
+/*----------------------------------------------------------------------------*/
 /* class functions */
 
 static CamelStore*
@@ -88,25 +305,32 @@ imapx_extd_conn_manager_get_connection (CamelIMAPXConnManager *self,
                                         GCancellable *cancellable,
                                         GError **err)
 {
+	/* modified dupe of imapx_conn_manager_get_connection() */
+
+	CamelIMAPXExtdServer *eserver = NULL;
 	CamelIMAPXServer *server = NULL;
-	GError *tmp_err = NULL;
 
 	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (self));
 	g_assert (foldername != NULL);
 	/* cancellable may be NULL */
 	g_return_val_if_fail (err == NULL || *err == NULL, NULL);
 
-	server = camel_imapx_conn_manager_get_connection (self,
-	                                                  foldername,
-	                                                  cancellable,
-	                                                  &tmp_err);
-	if (server == NULL) {
-		if (tmp_err != NULL)
-			g_propagate_error (err, tmp_err);
-		return NULL;
+	CON_LOCK (self);
+
+	/* modified */
+	server = camel_imapx_conn_manager_find_connection (self, foldername);
+	if (!server) {
+		/* modified */
+		eserver = extd_conn_manager_create_new_connection (self,
+		                                                   foldername,
+		                                                   cancellable,
+		                                                   err);
 	}
 
-	g_assert (CAMEL_IS_IMAPX_EXTD_SERVER (server));
+	CON_UNLOCK (self);
+
+	if (eserver != NULL)
+		server = CAMEL_IMAPX_SERVER (eserver);
 
 	return server;
 }
@@ -116,7 +340,7 @@ imapx_extd_conn_manager_close_connections (CamelIMAPXConnManager *self)
 {
 	g_assert (CAMEL_IS_IMAPX_EXTD_CONN_MANAGER (self));
 
-	camel_imapx_conn_manager_close_connections (self);
+	extd_conn_manager_prune_connections (CAMEL_IMAPX_CONN_MANAGER (self));
 }
 
 static GList*



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