[evolution-data-server] Add connection manager to imapx



commit 0076e53b1f46d5c028db6ed9328c55ca40b44579
Author: Chenthill Palanisamy <pchenthill novell com>
Date:   Wed Jul 14 01:00:57 2010 +0530

    Add connection manager to imapx

 camel/providers/imapx/Makefile.am                |    4 +-
 camel/providers/imapx/camel-imapx-conn-manager.c |  337 ++++++++++++++++++++++
 camel/providers/imapx/camel-imapx-conn-manager.h |   69 +++++
 camel/providers/imapx/camel-imapx-folder.c       |   31 +-
 camel/providers/imapx/camel-imapx-provider.c     |    2 -
 camel/providers/imapx/camel-imapx-server.c       |   14 +-
 camel/providers/imapx/camel-imapx-server.h       |    2 +-
 camel/providers/imapx/camel-imapx-store.c        |   90 ++++---
 camel/providers/imapx/camel-imapx-store.h        |   12 +-
 camel/providers/imapx/camel-imapx-utils.c        |    4 +-
 camel/providers/imapx/camel-imapx-utils.h        |   13 +-
 11 files changed, 507 insertions(+), 71 deletions(-)
---
diff --git a/camel/providers/imapx/Makefile.am b/camel/providers/imapx/Makefile.am
index 6fc3b8c..1e7a0a3 100644
--- a/camel/providers/imapx/Makefile.am
+++ b/camel/providers/imapx/Makefile.am
@@ -18,7 +18,8 @@ libcamelimapx_la_SOURCES =			\
 	camel-imapx-summary.c			\
 	camel-imapx-store.c			\
 	camel-imapx-folder.c			\
-	camel-imapx-server.c			
+	camel-imapx-server.c			\
+	camel-imapx-conn-manager.c
 
 noinst_HEADERS =				\
 	camel-imapx-stream.h			\
@@ -27,6 +28,7 @@ noinst_HEADERS =				\
 	camel-imapx-folder.h			\
 	camel-imapx-store.h			\
 	camel-imapx-server.h			\
+	camel-imapx-conn-manager.h		\
 	camel-imapx-utils.h
 
 camel-imapx-tokenise.h: camel-imapx-tokens.txt
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c b/camel/providers/imapx/camel-imapx-conn-manager.c
new file mode 100644
index 0000000..669ff8a
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -0,0 +1,337 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-conn-manager.h 
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill novell com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include "camel-imapx-conn-manager.h"
+#include "camel-imapx-utils.h"
+
+#define c(x) camel_imapx_debug(conman, x)
+
+#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), CAMEL_TYPE_OBJECT, CamelIMAPXConnManager))
+
+#define CON_LOCK(x) (g_static_rec_mutex_lock(&(x)->priv->con_man_lock))
+#define CON_UNLOCK(x) (g_static_rec_mutex_unlock(&(x)->priv->con_man_lock))
+
+G_DEFINE_TYPE (CamelIMAPXConnManager, camel_imapx_conn_manager, CAMEL_TYPE_OBJECT)
+
+struct _CamelIMAPXConnManagerPrivate {
+	GSList *connections;	
+	guint n_connections;
+	CamelStore *store;
+	GStaticRecMutex con_man_lock;
+};
+
+typedef struct {
+	GHashTable *folders;
+	CamelIMAPXServer *conn;
+	gchar *selected_folder;
+} ConnectionInfo;
+
+
+static void
+free_connection (gpointer data, gpointer user_data)
+{
+	ConnectionInfo *cinfo = (ConnectionInfo *) data;
+	CamelIMAPXServer *conn = cinfo->conn;
+
+	camel_imapx_server_connect (conn, 0);
+	
+	g_object_unref (conn);
+	g_hash_table_destroy (cinfo->folders);
+
+	g_free (cinfo);
+}
+
+static void
+imapx_prune_connections (CamelIMAPXConnManager *con_man)
+{
+	CON_LOCK(con_man);
+	
+	g_slist_foreach (con_man->priv->connections, (GFunc) free_connection, NULL);
+	con_man->priv->connections = NULL;
+	
+	CON_UNLOCK(con_man);
+}
+
+static void
+imapx_conn_manager_finalize (GObject *object)
+{
+	CamelIMAPXConnManager *con_man = CAMEL_IMAPX_CONN_MANAGER(object);
+	
+	imapx_prune_connections (con_man);
+	g_static_rec_mutex_free (&con_man->priv->con_man_lock);
+	g_object_unref (con_man->priv->store);
+}
+
+static void
+camel_imapx_conn_manager_class_init (CamelIMAPXConnManagerClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (CamelIMAPXConnManagerPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = imapx_conn_manager_finalize;
+}
+
+static void
+camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
+{
+	CamelIMAPXConnManagerPrivate *priv;
+
+	priv = g_new0 (CamelIMAPXConnManagerPrivate, 1);
+	con_man->priv = priv;
+	
+	/* default is 1 connection */
+	con_man->priv->n_connections = 1;
+	g_static_rec_mutex_init (&con_man->priv->con_man_lock);
+}
+
+
+/* Static functions go here */
+
+/* TODO destroy unused connections in a time-out loop */
+static void
+imapx_conn_shutdown (CamelIMAPXServer *conn, CamelIMAPXConnManager *con_man)
+{
+	GSList *l;
+	ConnectionInfo *cinfo;
+	gboolean found = FALSE;
+	
+	CON_LOCK(con_man);
+
+	for (l = con_man->priv->connections; l != NULL; l = g_slist_next (l)) {
+		cinfo = (ConnectionInfo *) l->data;
+		if (cinfo->conn == conn) {
+			found = TRUE;	
+			break;
+		}
+	}
+
+	if (found) {
+		con_man->priv->connections = g_slist_remove (con_man->priv->connections, cinfo);
+		free_connection (cinfo, GINT_TO_POINTER (1));
+	}
+
+	CON_UNLOCK(con_man);
+}
+
+static void
+imapx_conn_update_select (CamelIMAPXServer *conn, const gchar *selected_folder, CamelIMAPXConnManager *con_man)
+{
+	GSList *l;
+	ConnectionInfo *cinfo;
+	gboolean found = FALSE;
+	
+	CON_LOCK(con_man);
+
+	for (l = con_man->priv->connections; l != NULL; l = g_slist_next (l)) {
+		cinfo = (ConnectionInfo *) l->data;
+		if (cinfo->conn == conn) {
+			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(printf ("Removed folder %s from connection folder list \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);
+}
+
+/* This should find a connection if the slots are full, returns NULL if there are slots available for a new connection for a folder */
+static CamelIMAPXServer *
+imapx_find_connection (CamelIMAPXConnManager *con_man, const gchar *folder_name)
+{
+	guint i = 0, prev_len = -1, n = -1;
+	GSList *l;
+	CamelIMAPXServer *conn = NULL;
+	ConnectionInfo *cinfo = NULL;
+	
+	CON_LOCK(con_man);
+
+	/* Have a dedicated connection for INBOX ? */
+	for (l = con_man->priv->connections, i = 0; l != NULL; l = g_slist_next (l), i++) {
+		IMAPXJobQueueInfo *jinfo = NULL;
+
+		cinfo = (ConnectionInfo *) l->data;
+		jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
+
+		if (prev_len == -1) {
+			prev_len = jinfo->queue_len;
+			n = 0;
+		}
+
+		if (jinfo->queue_len < prev_len)
+			n = i;
+
+		camel_imapx_destroy_job_queue_info (jinfo);
+
+		if (folder_name && (g_hash_table_lookup (cinfo->folders, folder_name) || g_hash_table_size (cinfo->folders) == 0)) {
+			conn = g_object_ref (cinfo->conn);
+
+			if (folder_name)
+				g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
+			c(printf ("Found connection for %s and connection number %d \n", folder_name, i+1));
+			break;
+		}
+	}
+
+	if (!conn && n != -1 && (!folder_name || con_man->priv->n_connections == g_slist_length (con_man->priv->connections))) {
+		cinfo = g_slist_nth_data (con_man->priv->connections, n);
+		conn = g_object_ref (cinfo->conn);
+
+		if (folder_name) {
+			g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
+			c(printf ("Adding folder %s to connection number %d \n", folder_name, n+1));
+		}
+	}
+
+	c(g_assert (!(con_man->priv->n_connections == g_slist_length (con_man->priv->connections) && !conn)));
+
+	CON_UNLOCK(con_man);
+
+	return conn;
+}
+
+static CamelIMAPXServer *
+imapx_create_new_connection (CamelIMAPXConnManager *con_man, const gchar *folder_name, GError **error)
+{
+	CamelIMAPXServer *conn;
+	CamelStore *store = con_man->priv->store;
+	ConnectionInfo *cinfo = NULL;
+
+	CON_LOCK(con_man);
+
+	camel_service_lock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	conn = camel_imapx_server_new (CAMEL_STORE(store), CAMEL_SERVICE(store)->url);
+	if (camel_imapx_server_connect(conn, error)) {
+		g_object_ref (conn);
+	} else {
+		g_object_unref (conn);
+		
+		camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+		CON_UNLOCK (con_man);
+
+		return NULL;
+	}
+
+	g_signal_connect (conn, "shutdown", G_CALLBACK (imapx_conn_shutdown), con_man);
+	g_signal_connect (conn, "select_changed", G_CALLBACK (imapx_conn_update_select), con_man);
+
+	camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+
+	cinfo = g_new0 (ConnectionInfo, 1);
+	cinfo->conn = conn;
+	cinfo->folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+	
+	if (folder_name)
+		g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
+
+	con_man->priv->connections = g_slist_prepend (con_man->priv->connections, cinfo);
+	
+	c(printf ("Created new connection for %s and total connections %d \n", folder_name, g_slist_length (con_man->priv->connections)));
+
+	CON_UNLOCK(con_man);
+
+	return conn;
+}
+
+/****************************/
+
+CamelIMAPXConnManager *
+camel_imapx_conn_manager_new (CamelStore *store)
+{
+	CamelIMAPXConnManager *con_man;
+
+	con_man = g_object_new (CAMEL_TYPE_IMAPX_CONN_MANAGER, NULL);
+	con_man->priv->store = g_object_ref (store);
+
+	return con_man;
+}
+
+void			
+camel_imapx_conn_manager_set_n_connections (CamelIMAPXConnManager *con_man, guint n_connections)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+	con_man->priv->n_connections = n_connections;
+}
+
+CamelIMAPXServer *	
+camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man, const gchar *folder_name, GError **error)
+{
+	CamelIMAPXServer *conn = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+	
+	CON_LOCK(con_man);
+
+	conn = imapx_find_connection (con_man, folder_name);
+	if (!conn)
+		conn = imapx_create_new_connection (con_man, folder_name, error);
+
+	CON_UNLOCK(con_man);
+
+	return conn;
+}
+
+GSList *
+camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+{
+	GSList *l, *conns = NULL;
+	
+	CON_LOCK(con_man);
+	
+	for (l = con_man->priv->connections; l != NULL; l = g_slist_next (l)) {
+		ConnectionInfo *cinfo = (ConnectionInfo *) l->data;
+
+		conns = g_slist_prepend (conns, g_object_ref (cinfo->conn));
+	}
+
+	CON_UNLOCK(con_man);
+
+	return conns;
+}
+
+void			
+camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+	imapx_prune_connections (con_man);
+}
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.h b/camel/providers/imapx/camel-imapx-conn-manager.h
new file mode 100644
index 0000000..6bd17dc
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -0,0 +1,69 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-conn-manager.h 
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill novell com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CAMEL_IMAPX_CONN_MANAGER_H
+#define _CAMEL_IMAPX_CONN_MANAGER_H
+
+#include "camel-imapx-server.h"
+
+#define CAMEL_TYPE_IMAPX_CONN_MANAGER \
+	(camel_imapx_conn_manager_get_type ())
+#define CAMEL_IMAPX_CONN_MANAGER(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManager))
+#define CAMEL_IMAPX_CONN_MANAGER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+#define CAMEL_IS_IMAPX_CONN_MANAGER(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER))
+#define CAMEL_IS_CONN_MANAGER_CLASS(obj) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), CAMEL_TYPE_IMAPX_CONN_MANAGER))
+#define CAMEL_IMAPX_CONN_MANAGER_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
+
+
+typedef struct _CamelIMAPXConnManager CamelIMAPXConnManager;
+typedef struct _CamelIMAPXConnManagerClass CamelIMAPXConnManagerClass;
+typedef struct _CamelIMAPXConnManagerPrivate CamelIMAPXConnManagerPrivate;
+
+struct _CamelIMAPXConnManager {
+	CamelObject cobject;
+	CamelIMAPXConnManagerPrivate *priv;
+};
+
+struct _CamelIMAPXConnManagerClass {
+	CamelObjectClass cclass;
+};
+
+GType			camel_imapx_conn_manager_get_type		(void);
+CamelIMAPXConnManager *	camel_imapx_conn_manager_new			(CamelStore *store);
+void			camel_imapx_conn_manager_set_n_connections 	(CamelIMAPXConnManager *con_man, 
+									guint n_connections);
+CamelIMAPXServer *	camel_imapx_conn_manager_get_connection		(CamelIMAPXConnManager *con_man,
+									const gchar *folder_name,
+									GError **error);
+void			camel_imapx_conn_manager_close_connections 	(CamelIMAPXConnManager *con_man);
+GSList *		camel_imapx_conn_manager_get_connections 	(CamelIMAPXConnManager *con_man);
+
+#endif /* ! _CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index 1d529bf..7255334 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -164,7 +164,7 @@ imapx_refresh_info (CamelFolder *folder, GError **error)
 	if (!camel_service_connect((CamelService *)istore, error))
 		return FALSE;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server(istore, camel_folder_get_full_name (folder), error);
 	if (server != NULL) {
 		success = camel_imapx_server_refresh_info(server, folder, error);
 		g_object_unref(server);
@@ -177,16 +177,16 @@ static gboolean
 imapx_expunge (CamelFolder *folder, GError **error)
 {
 	CamelStore *parent_store;
-	CamelIMAPXStore *is;
+	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 
 	parent_store = camel_folder_get_parent_store (folder);
-	is = CAMEL_IMAPX_STORE (parent_store);
+	istore = CAMEL_IMAPX_STORE (parent_store);
 
-	if (CAMEL_OFFLINE_STORE (is)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(is, error);
+	server = camel_imapx_store_get_server(istore, camel_folder_get_full_name (folder), error);
 	if (server) {
 		camel_imapx_server_expunge(server, folder, error);
 		g_object_unref(server);
@@ -200,16 +200,16 @@ static gboolean
 imapx_sync (CamelFolder *folder, gboolean expunge, GError **error)
 {
 	CamelStore *parent_store;
-	CamelIMAPXStore *is;
+	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 
 	parent_store = camel_folder_get_parent_store (folder);
-	is = CAMEL_IMAPX_STORE (parent_store);
+	istore = CAMEL_IMAPX_STORE (parent_store);
 
-	if (CAMEL_OFFLINE_STORE (is)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
+	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(is, NULL);
+	server = camel_imapx_store_get_server(istore, camel_folder_get_full_name (folder), NULL);
 	if (server)
 		camel_imapx_server_sync_changes (server, folder, NULL);
 
@@ -218,8 +218,9 @@ imapx_sync (CamelFolder *folder, gboolean expunge, GError **error)
 
 	if (server && expunge)
 		camel_imapx_server_expunge(server, folder, NULL);
-	if (server)
+	if (server) {
 		g_object_unref(server);
+	}
 
 	return TRUE;
 }
@@ -259,7 +260,7 @@ imapx_get_message (CamelFolder *folder, const gchar *uid, GError **error)
 		if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 			return NULL;
 
-		server = camel_imapx_store_get_server(istore, error);
+		server = camel_imapx_store_get_server(istore, camel_folder_get_full_name (folder), error);
 		if (server) {
 			stream = camel_imapx_server_get_message(server, folder, uid, error);
 			g_object_unref(server);
@@ -296,7 +297,7 @@ imapx_sync_message (CamelFolder *folder, const gchar *uid, GError **error)
 	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (folder), error);
 	if (server == NULL)
 		return FALSE;
 
@@ -322,7 +323,7 @@ imapx_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
 	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, camel_folder_get_full_name (source), error);
 	if (server) {
 		success = camel_imapx_server_copy_message (server, source, dest, uids, delete_originals, error);
 		g_object_unref(server);
@@ -350,9 +351,9 @@ imapx_append_message(CamelFolder *folder, CamelMimeMessage *message, const Camel
 	if (appended_uid)
 		*appended_uid = NULL;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, NULL, error);
 	if (server) {
-		success = camel_imapx_server_append_message(server, folder, message, info, error);
+		success = camel_imapx_server_append_message (server, folder, message, info, error);
 		g_object_unref(server);
 	}
 
diff --git a/camel/providers/imapx/camel-imapx-provider.c b/camel/providers/imapx/camel-imapx-provider.c
index 1c5b71a..9bf6558 100644
--- a/camel/providers/imapx/camel-imapx-provider.c
+++ b/camel/providers/imapx/camel-imapx-provider.c
@@ -55,10 +55,8 @@ CamelProviderConfEntry imapx_conf_entries[] = {
 	  N_("_Use custom command to connect to server"), "0" },
 	{ CAMEL_PROVIDER_CONF_ENTRY, "command", "use_command",
 	  N_("Command:"), "ssh -C -l %u %h exec /usr/sbin/dovecot --exec-mail imap" },
-#if 0
 	{ CAMEL_PROVIDER_CONF_CHECKSPIN, "cachedconn", NULL,
 	  N_("Numbe_r of cached connections to use"), "y:1:5:7" },
-#endif
 	{ CAMEL_PROVIDER_CONF_SECTION_END },
 #endif
 	{ CAMEL_PROVIDER_CONF_SECTION_START, "folders", NULL,
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index d62e417..b807bdd 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -2341,6 +2341,8 @@ imapx_idle_supported (CamelIMAPXServer *is)
 static void
 imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 {
+	const gchar *selected_folder = NULL;
+
 	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
 		CamelDList failed;
 		CamelIMAPXCommand *cw, *cn;
@@ -2412,6 +2414,7 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 			//ifolder->uidnext_on_server = is->uidnext;
 		}
 		ifolder->uidvalidity_on_server = is->uidvalidity;
+		selected_folder = camel_folder_get_full_name (is->select_folder);
 #if 0
 		/* This must trigger a complete index rebuild! */
 		if (is->uidvalidity && is->uidvalidity != ((CamelIMAPXSummary *)is->select_folder->summary)->uidvalidity)
@@ -2428,7 +2431,7 @@ imapx_command_select_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 	is->select_pending = NULL;
 	camel_imapx_command_free (ic);
 
-	g_signal_emit (is, signals[SELECT_CHANGED], 0);
+	g_signal_emit (is, signals[SELECT_CHANGED], 0, selected_folder);
 }
 
 /* Should have a queue lock. TODO Change the way select is written */
@@ -4790,8 +4793,8 @@ camel_imapx_server_class_init(CamelIMAPXServerClass *class)
 		G_SIGNAL_RUN_FIRST,
 		G_STRUCT_OFFSET (CamelIMAPXServerClass, select_changed),
 		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1, G_TYPE_STRING);
 
 	/**
 	 * CamelIMAPXServer::shutdown
@@ -5563,7 +5566,7 @@ camel_imapx_server_get_job_queue_info (CamelIMAPXServer *is)
 	QUEUE_LOCK(is);
 
 	jinfo->queue_len = camel_dlist_length (&is->jobs);
-	jinfo->folders = g_hash_table_new_full (g_int_hash, g_int_equal, (GDestroyNotify) g_free, NULL);
+	jinfo->folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
 
 	for (node = is->jobs.head;node->next;node = job->msg.ln.next) {
 		job = (CamelIMAPXJob *) node;
@@ -5574,6 +5577,9 @@ camel_imapx_server_get_job_queue_info (CamelIMAPXServer *is)
 		}
 	}
 
+	if (is->select_folder)
+		g_hash_table_insert (jinfo->folders, g_strdup (camel_folder_get_full_name (is->select_folder)), GINT_TO_POINTER (1));
+
 	QUEUE_UNLOCK(is);
 
 	return jinfo;
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index a23d0b2..69bf5d3 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -130,7 +130,7 @@ struct _CamelIMAPXServerClass {
 	CamelObjectClass parent_class;
 
 	/* Signals */
-	void	(*select_changed)	(CamelIMAPXServer *server);
+	void	(*select_changed)	(CamelIMAPXServer *server, const gchar *selected_folder);
 	void	(*shutdown)		(CamelIMAPXServer *server);
 
 	gchar tagprefix;
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 88de8a4..b140bf9 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -78,6 +78,8 @@ imapx_name_equal(gconstpointer a, gconstpointer b)
 static void
 imapx_parse_receiving_options (CamelIMAPXStore *istore, CamelURL *url)
 {
+	const gchar *val;
+
 	if (camel_url_get_param (url, "use_lsub"))
 		istore->rec_options |= IMAPX_SUBSCRIPTIONS;
 
@@ -109,6 +111,12 @@ imapx_parse_receiving_options (CamelIMAPXStore *istore, CamelURL *url)
 
 	if (camel_url_get_param (url, "use_qresync"))
 		istore->rec_options |= IMAPX_USE_QRESYNC;
+
+	val = camel_url_get_param (url, "cachedconn");
+	if (val) {
+		guint n = strtod (val, NULL);
+		camel_imapx_conn_manager_set_n_connections (istore->con_man, n);
+	}
 }
 
 static void
@@ -168,6 +176,7 @@ imapx_query_auth_types (CamelService *service, GError **error)
 	CamelServiceAuthType *authtype;
 	GList *sasl_types, *t, *next;
 	gboolean connected;
+	CamelIMAPXServer *server;
 
 	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
 		g_set_error (
@@ -179,12 +188,11 @@ imapx_query_auth_types (CamelService *service, GError **error)
 
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	if (istore->server == NULL)
-		istore->server = camel_imapx_server_new((CamelStore *)istore, service->url);
+	server = camel_imapx_server_new((CamelStore *)istore, service->url);
 
-	connected = istore->server->stream != NULL;
+	connected = server->stream != NULL;
 	if (!connected)
-		connected = imapx_connect_to_server (istore->server, error);
+		connected = imapx_connect_to_server (server, error);
 	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 	if (!connected)
 		return NULL;
@@ -194,12 +202,14 @@ imapx_query_auth_types (CamelService *service, GError **error)
 		authtype = t->data;
 		next = t->next;
 
-		if (!g_hash_table_lookup (istore->server->cinfo->auth_types, authtype->authproto)) {
+		if (!g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
 			sasl_types = g_list_remove_link (sasl_types, t);
 			g_list_free_1 (t);
 		}
 	}
 
+	g_object_unref (server);
+
 	return g_list_prepend (sasl_types, &camel_imapx_password_authtype);
 }
 
@@ -214,41 +224,33 @@ imapx_get_name (CamelService *service, gboolean brief)
 }
 
 CamelIMAPXServer *
-camel_imapx_store_get_server(CamelIMAPXStore *store, GError **error)
+camel_imapx_store_get_server (CamelIMAPXStore *istore, const gchar *folder_name, GError **error)
 {
 	CamelIMAPXServer *server = NULL;
 
-	camel_service_lock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+	camel_service_lock (CAMEL_SERVICE (istore), CAMEL_SERVICE_REC_CONNECT_LOCK);
+	
+	server = camel_imapx_conn_manager_get_connection (istore->con_man, folder_name, error);
 
-	if (store->server && camel_imapx_server_connect(store->server, NULL)) {
-		g_object_ref(store->server);
-		server = store->server;
-	} else {
-		if (store->server) {
-			g_object_unref(store->server);
-			store->server = NULL;
-		}
+	camel_service_unlock (CAMEL_SERVICE (istore), CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-		server = camel_imapx_server_new(CAMEL_STORE(store), CAMEL_SERVICE(store)->url);
-		if (camel_imapx_server_connect(server, error)) {
-			store->server = server;
-			g_object_ref(server);
-		} else {
-			g_object_unref(server);
-			server = NULL;
-		}
-	}
-	camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 	return server;
 }
 
+void
+camel_imapx_store_op_done (CamelIMAPXStore *istore, CamelIMAPXServer *server, const gchar *folder_name)
+{
+	g_return_if_fail (server != NULL);
+
+}
+
 static gboolean
 imapx_connect (CamelService *service, GError **error)
 {
 	CamelIMAPXStore *istore = (CamelIMAPXStore *)service;
 	CamelIMAPXServer *server;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server(istore, NULL, error);
 	if (server) {
 		g_object_unref(server);
 		return TRUE;
@@ -269,9 +271,10 @@ imapx_disconnect (CamelService *service, gboolean clean, GError **error)
 
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	if (istore->server) {
-		g_object_unref(istore->server);
-		istore->server = NULL;
+	if (istore->con_man) {
+		camel_imapx_conn_manager_close_connections (istore->con_man);
+		g_object_unref (istore->con_man);
+		istore->con_man = NULL;
 	}
 
 	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
@@ -327,18 +330,24 @@ static gboolean
 imapx_noop (CamelStore *store, GError **error)
 {
 	CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
-	CamelIMAPXServer *server;
+	GSList *servers = NULL, *l;
 	gboolean success = FALSE;
 
 	if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(istore, error);
-	if (server) {
+	servers = camel_imapx_conn_manager_get_connections (istore->con_man);
+
+	for (l = servers; l != NULL; l = g_slist_next (l)) {
+		CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (l->data);
+	
+		/* we just return last noops value, technically not correct though */	
 		success = camel_imapx_server_noop (server, NULL, error);
 		g_object_unref(server);
 	}
 
+	g_slist_free (servers);
+
 	return success;
 }
 
@@ -598,7 +607,7 @@ imapx_subscribe_folder (CamelStore *store, const gchar *folder_name, gboolean em
 	if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, NULL, error);
 	if (!server)
 		return FALSE;
 
@@ -621,7 +630,7 @@ imapx_unsubscribe_folder (CamelStore *store, const gchar *folder_name, gboolean
 	if (CAMEL_OFFLINE_STORE(store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
 		return TRUE;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, NULL, error);
 	if (!server)
 		return FALSE;
 
@@ -699,7 +708,9 @@ imapx_delete_folder (CamelStore *store, const gchar *folder_name, GError **error
 			_("You must be working online to complete this operation"));
 		return FALSE;
 	}
-	server = camel_imapx_store_get_server(istore, error);
+	/* Use INBOX connection as the implementation would try to select inbox to ensure
+	   we are not selected on the folder being deleted */
+	server = camel_imapx_store_get_server (istore, "INBOX", error);
 	if (!server)
 		return FALSE;
 
@@ -764,7 +775,9 @@ imapx_rename_folder (CamelStore *store, const gchar *old, const gchar *new, GErr
 	if (istore->rec_options & IMAPX_SUBSCRIPTIONS)
 		imapx_unsubscribe_folder (store, old, FALSE, NULL);
 
-	server = camel_imapx_store_get_server(istore, error);
+	/* Use INBOX connection as the implementation would try to select inbox to ensure
+	   we are not selected on the folder being renamed */
+	server = camel_imapx_store_get_server(istore, "INBOX", error);
 	if (server) {
 		success = camel_imapx_server_rename_folder (server, old, new, error);
 		g_object_unref(server);
@@ -818,7 +831,7 @@ imapx_create_folder (CamelStore *store, const gchar *parent_name, const gchar *f
 		return NULL;
 	}
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server(istore, NULL, error);
 	if (!server)
 		return NULL;
 
@@ -1126,7 +1139,7 @@ fetch_folders_for_namespaces (CamelIMAPXStore *istore, const gchar *pattern, gbo
 	GHashTable *folders = NULL;
 	GSList *namespaces = NULL, *l;
 
-	server = camel_imapx_store_get_server(istore, error);
+	server = camel_imapx_store_get_server (istore, NULL, error);
 	if (!server)
 		return NULL;
 
@@ -1482,4 +1495,5 @@ camel_imapx_store_init (CamelIMAPXStore *istore)
 	istore->get_finfo_lock = g_mutex_new ();
 	istore->last_refresh_time = time (NULL) - (FINFO_REFRESH_INTERVAL + 10);
 	istore->dir_sep = '/';
+	istore->con_man = camel_imapx_conn_manager_new (store);
 }
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index 922c5f2..c94de00 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -28,6 +28,7 @@
 
 #include "camel-imapx-server.h"
 #include "camel-imapx-store-summary.h"
+#include "camel-imapx-conn-manager.h"
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_IMAPX_STORE \
@@ -66,7 +67,7 @@ typedef struct _CamelIMAPXStoreClass CamelIMAPXStoreClass;
 struct _CamelIMAPXStore {
 	CamelOfflineStore parent;
 
-	CamelIMAPXServer *server;
+	CamelIMAPXConnManager *con_man;
 
 	CamelIMAPXStoreSummary *summary; /* in-memory list of folders */
 	gchar *namespace, dir_sep, *base_url, *storage_path;
@@ -91,8 +92,13 @@ struct _CamelIMAPXStoreClass {
 	CamelOfflineStoreClass parent_class;
 };
 
-GType		camel_imapx_store_get_type (void);
-CamelIMAPXServer *camel_imapx_store_get_server(CamelIMAPXStore *store, GError **error);
+GType			camel_imapx_store_get_type	(void);
+CamelIMAPXServer *	camel_imapx_store_get_server	(CamelIMAPXStore *store,
+							const gchar *folder_name,
+							GError **error);
+void			camel_imapx_store_op_done	(CamelIMAPXStore *istore, 
+							CamelIMAPXServer *server, 
+							const gchar *folder_name);
 
 G_END_DECLS
 
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index dd27f98..451da87 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -6,6 +6,7 @@
 #include "camel-imapx-folder.h"
 #include "camel-imapx-stream.h"
 #include "camel-imapx-summary.h"
+#include "camel-imapx-store.h"
 #include "camel-imapx-store-summary.h"
 #include "camel-imapx-utils.h"
 
@@ -35,6 +36,7 @@ static void camel_imapx_set_debug_flags(void)
 	debug_set_flag(io);
 	debug_set_flag(token);
 	debug_set_flag(parse);
+	debug_set_flag(conman);
 }
 
 #include "camel-imapx-tokenise.h"
@@ -2115,7 +2117,7 @@ imapx_get_temp_uid (void)
 }
 
 void
-camel_imapx_server_destroy_job_queue_info (IMAPXJobQueueInfo *jinfo)
+camel_imapx_destroy_job_queue_info (IMAPXJobQueueInfo *jinfo)
 {
 	g_hash_table_destroy (jinfo->folders);
 	g_free (jinfo);
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index 08d11ae..b0032c6 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -3,12 +3,12 @@
 #define CAMEL_IMAPX_UTILS_H
 
 #include <camel/camel.h>
-
-#include "camel-imapx-store.h"
+#include <glib.h>
 
 struct _CamelIMAPXStream;
 struct _CamelFlag;
 struct _CamelIMAPXNamespaceList;
+struct _CamelIMAPXStore;
 
 /* list of strings we know about that can be *quickly* tokenised */
 typedef enum _camel_imapx_id_t {
@@ -66,7 +66,7 @@ enum {
 
 /* ********************************************************************** */
 
-GPtrArray *imapx_parse_uids (CamelIMAPXStream *is, GError **error);
+GPtrArray *imapx_parse_uids (struct _CamelIMAPXStream *is, GError **error);
 void imapx_parse_flags(struct _CamelIMAPXStream *stream, guint32 *flagsp, struct _CamelFlag **user_flagsp, GError **error);
 void imapx_write_flags(CamelStream *stream, guint32 flags, struct _CamelFlag *user_flags, GError **error);
 gboolean imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, CamelFolder *folder, gboolean unsolicited);
@@ -217,7 +217,7 @@ typedef struct _IMAPXJobQueueInfo {
 	GHashTable *folders;
 } IMAPXJobQueueInfo;
 
-void camel_imapx_server_destroy_job_queue_info (IMAPXJobQueueInfo *jinfo);
+void camel_imapx_destroy_job_queue_info (IMAPXJobQueueInfo *jinfo);
 
 /* ********************************************************************** */
 
@@ -247,9 +247,10 @@ extern gint camel_imapx_debug_flags;
 #define CAMEL_IMAPX_DEBUG_io		(1<<3)
 #define CAMEL_IMAPX_DEBUG_token		(1<<4)
 #define CAMEL_IMAPX_DEBUG_parse		(1<<5)
+#define CAMEL_IMAPX_DEBUG_conman	(1<<6)
 
 /* Set this to zero to remove all debug output at build time */
-#define CAMEL_IMAPX_DEBUG_ALL		((1<<6)-1)
+#define CAMEL_IMAPX_DEBUG_ALL		((1<<7)-1)
 
 #define camel_imapx_debug(type, ...) do { if (camel_imapx_debug_flags & CAMEL_IMAPX_DEBUG_ALL & CAMEL_IMAPX_DEBUG_ ## type) { __VA_ARGS__ ; } } while (0)
 
@@ -259,7 +260,7 @@ void imapx_utils_init(void);
 
 /* chen adds from old imap provider - place it in right place */
 gchar *imapx_path_to_physical (const gchar *prefix, const gchar *vpath);
-gchar *imapx_concat (CamelIMAPXStore *imapx_store, const gchar *prefix, const gchar *suffix);
+gchar *imapx_concat (struct _CamelIMAPXStore *imapx_store, const gchar *prefix, const gchar *suffix);
 gchar * imapx_get_temp_uid (void);
 
 void camel_imapx_namespace_list_clear (struct _CamelIMAPXNamespaceList *nsl);



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