[evolution-data-server/evolution-data-server-3-12] [IMAPx] Enable concurrent connections



commit e9da82454614550c2b9ac147ffa67b1a60215af2
Author: Milan Crha <mcrha redhat com>
Date:   Thu Apr 10 08:18:02 2014 +0200

    [IMAPx] Enable concurrent connections
    
    This returns back CamelIMAPXConnManager, and enables use of concurrent
    connections with it, which helps with response time of user requests.

 camel/camel-service.c                            |    4 +
 camel/providers/imapx/Makefile.am                |    2 +
 camel/providers/imapx/camel-imapx-conn-manager.c |  914 ++++++++++++++++++++++
 camel/providers/imapx/camel-imapx-conn-manager.h |   94 +++
 camel/providers/imapx/camel-imapx-folder.c       |  115 +++-
 camel/providers/imapx/camel-imapx-mailbox.c      |   21 +
 camel/providers/imapx/camel-imapx-mailbox.h      |    2 +
 camel/providers/imapx/camel-imapx-server.c       |  281 ++++++-
 camel/providers/imapx/camel-imapx-server.h       |    8 +
 camel/providers/imapx/camel-imapx-settings.c     |   80 ++
 camel/providers/imapx/camel-imapx-settings.h     |    5 +
 camel/providers/imapx/camel-imapx-store.c        |  294 +++-----
 camel/providers/imapx/camel-imapx-store.h        |   10 +
 camel/providers/imapx/camel-imapx-utils.c        |    2 +-
 camel/providers/imapx/camel-imapx-utils.h        |    7 +-
 15 files changed, 1602 insertions(+), 237 deletions(-)
---
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 2593c23..839e409 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -492,6 +492,10 @@ service_queue_notify_connection_status (CamelService *service)
 
        session = camel_service_ref_session (service);
 
+       /* most-likely exitting the application */
+       if (!session)
+               return;
+
        /* Prioritize ahead of GTK+ redraws. */
        camel_session_idle_add (
                session, G_PRIORITY_HIGH_IDLE,
diff --git a/camel/providers/imapx/Makefile.am b/camel/providers/imapx/Makefile.am
index 7fa1a90..b8b2956 100644
--- a/camel/providers/imapx/Makefile.am
+++ b/camel/providers/imapx/Makefile.am
@@ -22,6 +22,8 @@ libcamelimapx_la_SOURCES = \
        camel-imapx-provider.c \
        camel-imapx-command.c \
        camel-imapx-command.h \
+       camel-imapx-conn-manager.c \
+       camel-imapx-conn-manager.h \
        camel-imapx-folder.c \
        camel-imapx-folder.h \
        camel-imapx-input-stream.c \
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..aeb64d3
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -0,0 +1,914 @@
+/*-*- 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 "camel-imapx-conn-manager.h"
+#include "camel-imapx-settings.h"
+#include "camel-imapx-store.h"
+#include "camel-imapx-utils.h"
+
+#define c(...) camel_imapx_debug(conman, __VA_ARGS__)
+
+#define CON_READ_LOCK(x) \
+       (g_rw_lock_reader_lock (&(x)->priv->rw_lock))
+#define CON_READ_UNLOCK(x) \
+       (g_rw_lock_reader_unlock (&(x)->priv->rw_lock))
+#define CON_WRITE_LOCK(x) \
+       (g_rw_lock_writer_lock (&(x)->priv->rw_lock))
+#define CON_WRITE_UNLOCK(x) \
+       (g_rw_lock_writer_unlock (&(x)->priv->rw_lock))
+
+#define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
+
+typedef struct _ConnectionInfo ConnectionInfo;
+
+struct _CamelIMAPXConnManagerPrivate {
+       /* XXX Might be easier for this to be a hash table,
+        *     with CamelIMAPXServer pointers as the keys. */
+       GList *connections;
+       GWeakRef store;
+       GRWLock rw_lock;
+};
+
+struct _ConnectionInfo {
+       GMutex lock;
+       CamelIMAPXServer *is;
+       GHashTable *folder_names;
+       gchar *selected_folder;
+       volatile gint ref_count;
+};
+
+enum {
+       PROP_0,
+       PROP_STORE
+};
+
+enum {
+       MAILBOX_CREATED,
+       MAILBOX_RENAMED,
+       MAILBOX_UPDATED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (
+       CamelIMAPXConnManager,
+       camel_imapx_conn_manager,
+       G_TYPE_OBJECT)
+
+static void
+imapx_conn_shutdown (CamelIMAPXServer *is, CamelIMAPXConnManager *con_man);
+
+static void
+imapx_conn_update_select (CamelIMAPXServer *is,
+                          CamelIMAPXMailbox *mailbox,
+                          CamelIMAPXConnManager *con_man);
+static void
+imapx_conn_mailbox_closed (CamelIMAPXServer *is,
+                          CamelIMAPXMailbox *mailbox,
+                          CamelIMAPXConnManager *con_man);
+
+static void
+imapx_conn_mailbox_created_cb (CamelIMAPXServer *server,
+                              CamelIMAPXMailbox *mailbox,
+                              CamelIMAPXConnManager *con_man)
+{
+       g_signal_emit (con_man, signals[MAILBOX_CREATED], 0, mailbox);
+}
+
+static void
+imapx_conn_mailbox_renamed_cb (CamelIMAPXServer *server,
+                              CamelIMAPXMailbox *mailbox,
+                              const gchar *oldname,
+                              CamelIMAPXConnManager *con_man)
+{
+       g_signal_emit (con_man, signals[MAILBOX_RENAMED], 0, mailbox, oldname);
+}
+
+static void
+imapx_conn_mailbox_updated_cb (CamelIMAPXServer *server,
+                              CamelIMAPXMailbox *mailbox,
+                              CamelIMAPXConnManager *con_man)
+{
+       g_signal_emit (con_man, signals[MAILBOX_UPDATED], 0, mailbox);
+}
+
+static ConnectionInfo *
+connection_info_new (CamelIMAPXServer *is)
+{
+       ConnectionInfo *cinfo;
+       GHashTable *folder_names;
+
+       folder_names = g_hash_table_new_full (
+               (GHashFunc) g_str_hash,
+               (GEqualFunc) g_str_equal,
+               (GDestroyNotify) g_free,
+               (GDestroyNotify) NULL);
+
+       cinfo = g_slice_new0 (ConnectionInfo);
+       g_mutex_init (&cinfo->lock);
+       cinfo->is = g_object_ref (is);
+       cinfo->folder_names = folder_names;
+       cinfo->ref_count = 1;
+
+       return cinfo;
+}
+
+static ConnectionInfo *
+connection_info_ref (ConnectionInfo *cinfo)
+{
+       g_return_val_if_fail (cinfo != NULL, NULL);
+       g_return_val_if_fail (cinfo->ref_count > 0, NULL);
+
+       g_atomic_int_inc (&cinfo->ref_count);
+
+       return cinfo;
+}
+
+static void
+connection_info_unref (ConnectionInfo *cinfo)
+{
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (cinfo->ref_count > 0);
+
+       if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
+               camel_imapx_server_shutdown (cinfo->is);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_shutdown, NULL);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_update_select, NULL);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_closed, NULL);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_created_cb, NULL);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_renamed_cb, NULL);
+               g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_updated_cb, NULL);
+
+               g_mutex_clear (&cinfo->lock);
+               g_object_unref (cinfo->is);
+               g_hash_table_destroy (cinfo->folder_names);
+               g_free (cinfo->selected_folder);
+
+               g_slice_free (ConnectionInfo, cinfo);
+       }
+}
+
+static void
+connection_info_cancel_and_unref (ConnectionInfo *cinfo)
+{
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (cinfo->ref_count > 0);
+
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_shutdown, NULL);
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_update_select, NULL);
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_closed, NULL);
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_created_cb, NULL);
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_renamed_cb, NULL);
+       g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, 
imapx_conn_mailbox_updated_cb, NULL);
+       camel_imapx_server_shutdown (cinfo->is);
+       connection_info_unref (cinfo);
+}
+
+static gboolean
+connection_info_is_available (ConnectionInfo *cinfo)
+{
+       gboolean available;
+
+       g_return_val_if_fail (cinfo != NULL, FALSE);
+
+       g_mutex_lock (&cinfo->lock);
+
+       /* Available means it's not tracking any folder names or no jobs are running. */
+       available = (g_hash_table_size (cinfo->folder_names) == 0) ||
+                   camel_imapx_server_get_command_count (cinfo->is) == 0;
+
+       g_mutex_unlock (&cinfo->lock);
+
+       return available;
+}
+
+static gboolean
+connection_info_has_folder_name (ConnectionInfo *cinfo,
+                                 const gchar *folder_name)
+{
+       gpointer value;
+
+       g_return_val_if_fail (cinfo != NULL, FALSE);
+
+       if (folder_name == NULL)
+               return FALSE;
+
+       g_mutex_lock (&cinfo->lock);
+
+       value = g_hash_table_lookup (cinfo->folder_names, folder_name);
+
+       g_mutex_unlock (&cinfo->lock);
+
+       return (value != NULL);
+}
+
+static void
+connection_info_insert_folder_name (ConnectionInfo *cinfo,
+                                    const gchar *folder_name)
+{
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (folder_name != NULL);
+
+       g_mutex_lock (&cinfo->lock);
+
+       g_hash_table_insert (
+               cinfo->folder_names,
+               g_strdup (folder_name),
+               GINT_TO_POINTER (1));
+
+       g_mutex_unlock (&cinfo->lock);
+}
+
+static void
+connection_info_remove_folder_name (ConnectionInfo *cinfo,
+                                    const gchar *folder_name)
+{
+       g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (folder_name != NULL);
+
+       g_mutex_lock (&cinfo->lock);
+
+       g_hash_table_remove (cinfo->folder_names, folder_name);
+
+       g_mutex_unlock (&cinfo->lock);
+}
+
+static gchar *
+connection_info_dup_selected_folder (ConnectionInfo *cinfo)
+{
+       gchar *selected_folder;
+
+       g_return_val_if_fail (cinfo != NULL, NULL);
+
+       g_mutex_lock (&cinfo->lock);
+
+       selected_folder = g_strdup (cinfo->selected_folder);
+
+       g_mutex_unlock (&cinfo->lock);
+
+       return selected_folder;
+}
+
+static void
+connection_info_set_selected_folder (ConnectionInfo *cinfo,
+                                     const gchar *selected_folder)
+{
+       g_return_if_fail (cinfo != NULL);
+
+       g_mutex_lock (&cinfo->lock);
+
+       g_free (cinfo->selected_folder);
+       cinfo->selected_folder = g_strdup (selected_folder);
+
+       g_mutex_unlock (&cinfo->lock);
+}
+
+static GList *
+imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
+{
+       GList *list;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+       CON_READ_LOCK (con_man);
+
+       list = g_list_copy (con_man->priv->connections);
+       g_list_foreach (list, (GFunc) connection_info_ref, NULL);
+
+       CON_READ_UNLOCK (con_man);
+
+       return list;
+}
+
+static ConnectionInfo *
+imapx_conn_manager_lookup_info (CamelIMAPXConnManager *con_man,
+                                CamelIMAPXServer *is)
+{
+       ConnectionInfo *cinfo = NULL;
+       GList *list, *link;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+
+       CON_READ_LOCK (con_man);
+
+       list = con_man->priv->connections;
+
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ConnectionInfo *candidate = link->data;
+
+               if (candidate->is == is) {
+                       cinfo = connection_info_ref (candidate);
+                       break;
+               }
+       }
+
+       CON_READ_UNLOCK (con_man);
+
+       return cinfo;
+}
+
+static gboolean
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
+                                ConnectionInfo *cinfo)
+{
+       GList *list, *link;
+       gboolean removed = FALSE;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), FALSE);
+       g_return_val_if_fail (cinfo != NULL, FALSE);
+
+       CON_WRITE_LOCK (con_man);
+
+       list = con_man->priv->connections;
+       link = g_list_find (list, cinfo);
+
+       if (link != NULL) {
+               list = g_list_delete_link (list, link);
+               connection_info_unref (cinfo);
+               removed = TRUE;
+       }
+
+       con_man->priv->connections = list;
+
+       CON_WRITE_UNLOCK (con_man);
+
+       return removed;
+}
+
+static void
+imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
+                              CamelStore *store)
+{
+       g_return_if_fail (CAMEL_IS_STORE (store));
+
+       g_weak_ref_set (&con_man->priv->store, store);
+}
+
+static void
+imapx_conn_manager_set_property (GObject *object,
+                                 guint property_id,
+                                 const GValue *value,
+                                 GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_STORE:
+                       imapx_conn_manager_set_store (
+                               CAMEL_IMAPX_CONN_MANAGER (object),
+                               g_value_get_object (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_conn_manager_get_property (GObject *object,
+                                 guint property_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_STORE:
+                       g_value_take_object (
+                               value,
+                               camel_imapx_conn_manager_ref_store (
+                               CAMEL_IMAPX_CONN_MANAGER (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+imapx_conn_manager_dispose (GObject *object)
+{
+       CamelIMAPXConnManagerPrivate *priv;
+
+       priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+
+       g_list_free_full (
+               priv->connections,
+               (GDestroyNotify) connection_info_unref);
+       priv->connections = NULL;
+
+       g_weak_ref_set (&priv->store, NULL);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->dispose (object);
+}
+
+static void
+imapx_conn_manager_finalize (GObject *object)
+{
+       CamelIMAPXConnManagerPrivate *priv;
+
+       priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+
+       g_rw_lock_clear (&priv->rw_lock);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
+}
+
+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->set_property = imapx_conn_manager_set_property;
+       object_class->get_property = imapx_conn_manager_get_property;
+       object_class->dispose = imapx_conn_manager_dispose;
+       object_class->finalize = imapx_conn_manager_finalize;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_STORE,
+               g_param_spec_object (
+                       "store",
+                       "Store",
+                       "The CamelStore to which we belong",
+                       CAMEL_TYPE_STORE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       signals[MAILBOX_CREATED] = g_signal_new (
+               "mailbox-created",
+               G_OBJECT_CLASS_TYPE (class),
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_created),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1,
+               CAMEL_TYPE_IMAPX_MAILBOX);
+
+       signals[MAILBOX_RENAMED] = g_signal_new (
+               "mailbox-renamed",
+               G_OBJECT_CLASS_TYPE (class),
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_renamed),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 2,
+               CAMEL_TYPE_IMAPX_MAILBOX,
+               G_TYPE_STRING);
+
+       signals[MAILBOX_UPDATED] = g_signal_new (
+               "mailbox-updated",
+               G_OBJECT_CLASS_TYPE (class),
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, mailbox_updated),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1,
+               CAMEL_TYPE_IMAPX_MAILBOX);
+}
+
+static void
+camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
+{
+       con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
+
+       g_rw_lock_init (&con_man->priv->rw_lock);
+}
+
+/* Static functions go here */
+
+/* TODO destroy unused connections in a time-out loop */
+static void
+imapx_conn_shutdown (CamelIMAPXServer *is,
+                     CamelIMAPXConnManager *con_man)
+{
+       ConnectionInfo *cinfo;
+
+       /* Returns a new ConnectionInfo reference. */
+       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+       if (cinfo != NULL) {
+               imapx_conn_manager_remove_info (con_man, cinfo);
+               connection_info_unref (cinfo);
+       }
+}
+
+static void
+imapx_conn_update_select (CamelIMAPXServer *is,
+                          CamelIMAPXMailbox *mailbox,
+                          CamelIMAPXConnManager *con_man)
+{
+       ConnectionInfo *cinfo;
+       gchar *old_selected_folder, *selected_folder = NULL;
+
+       /* Returns a new ConnectionInfo reference. */
+       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+       if (cinfo == NULL)
+               return;
+
+       old_selected_folder = connection_info_dup_selected_folder (cinfo);
+
+       if (old_selected_folder != NULL) {
+               if (!camel_imapx_server_folder_name_in_jobs (is, old_selected_folder)) {
+                       connection_info_remove_folder_name (cinfo, old_selected_folder);
+                       c (is->tagprefix, "Removed folder %s from connection folder list - select changed 
\n", old_selected_folder);
+               }
+
+               g_free (old_selected_folder);
+       }
+
+       if (mailbox)
+               selected_folder = camel_imapx_mailbox_dup_folder_path (mailbox);
+       connection_info_set_selected_folder (cinfo, selected_folder);
+       g_free (selected_folder);
+
+       connection_info_unref (cinfo);
+}
+
+static void
+imapx_conn_mailbox_closed (CamelIMAPXServer *is,
+                          CamelIMAPXMailbox *mailbox,
+                          CamelIMAPXConnManager *con_man)
+{
+       imapx_conn_update_select (is, NULL, 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_unlocked (CamelIMAPXConnManager *con_man,
+                                const gchar *folder_name,
+                               gboolean for_expensive_job)
+{
+       CamelStore *store;
+       CamelSettings *settings;
+       CamelIMAPXServer *is = NULL;
+       ConnectionInfo *cinfo = NULL;
+       GList *list, *link;
+       guint concurrent_connections, opened_connections, expensive_connections = 0;
+       guint min_jobs = G_MAXUINT;
+
+       /* Caller must be holding CON_WRITE_LOCK. */
+
+       store = camel_imapx_conn_manager_ref_store (con_man);
+       g_return_val_if_fail (store != NULL, NULL);
+
+       settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+
+       concurrent_connections =
+               camel_imapx_settings_get_concurrent_connections (
+               CAMEL_IMAPX_SETTINGS (settings));
+
+       g_object_unref (settings);
+
+       /* XXX Have a dedicated connection for INBOX ? */
+
+       opened_connections = g_list_length (con_man->priv->connections);
+       list = con_man->priv->connections;
+
+       /* If a folder was not given, find the least-busy connection. */
+       if (folder_name == NULL) {
+               goto least_busy;
+       }
+
+       /* First try to find a connection already handling this folder. */
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ConnectionInfo *candidate = link->data;
+
+               if (camel_imapx_server_has_expensive_command (candidate->is))
+                       expensive_connections++;
+
+               if (connection_info_has_folder_name (candidate, folder_name) &&
+                   (opened_connections >= concurrent_connections || for_expensive_job || 
!camel_imapx_server_has_expensive_command (candidate->is))) {
+                       if (cinfo) {
+                               /* group expensive jobs into one connection */
+                               if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+                                       continue;
+
+                               if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) < 
camel_imapx_server_get_command_count (candidate->is))
+                                       continue;
+
+                               connection_info_unref (cinfo);
+                       }
+
+                       cinfo = connection_info_ref (candidate);
+                       if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+                               goto exit;
+               }
+       }
+
+ least_busy:
+       if (for_expensive_job) {
+               /* allow only half connections being with expensive operations */
+               if (expensive_connections > 0 &&
+                   expensive_connections < concurrent_connections / 2 &&
+                   opened_connections < concurrent_connections)
+                       goto exit;
+
+               /* cinfo here doesn't have any expensive command, thus ignore it */
+               if (cinfo) {
+                       connection_info_unref (cinfo);
+                       cinfo = NULL;
+               }
+
+               /* Pick the connection with the least number of jobs in progress among those with expensive 
jobs. */
+               for (link = list; link != NULL; link = g_list_next (link)) {
+                       ConnectionInfo *candidate = link->data;
+                       guint jobs;
+
+                       if (!camel_imapx_server_has_expensive_command (candidate->is))
+                               continue;
+
+                       jobs = camel_imapx_server_get_command_count (candidate->is);
+
+                       if (cinfo == NULL) {
+                               cinfo = connection_info_ref (candidate);
+                               min_jobs = jobs;
+
+                       } else if (jobs < min_jobs) {
+                               connection_info_unref (cinfo);
+                               cinfo = connection_info_ref (candidate);
+                               min_jobs = jobs;
+                       }
+               }
+
+               if (cinfo)
+                       goto exit;
+       }
+
+       /* Next try to find a connection not handling any folders. */
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ConnectionInfo *candidate = link->data;
+
+               if (connection_info_is_available (candidate)) {
+                       if (cinfo)
+                               connection_info_unref (cinfo);
+                       cinfo = connection_info_ref (candidate);
+                       goto exit;
+               }
+       }
+
+       /* open a new connection, if there is a room for it */
+       if (opened_connections < concurrent_connections && (!for_expensive_job || opened_connections < 
concurrent_connections / 2)) {
+               if (cinfo && camel_imapx_server_get_command_count (cinfo->is) != 0) {
+                       connection_info_unref (cinfo);
+                       cinfo = NULL;
+               }
+               goto exit;
+       } else {
+               if (cinfo)
+                       min_jobs = camel_imapx_server_get_command_count (cinfo->is);
+       }
+
+       /* Pick the connection with the least number of jobs in progress. */
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ConnectionInfo *candidate = link->data;
+               gint n_commands = camel_imapx_server_get_command_count (candidate->is);
+
+               if (cinfo == NULL) {
+                       cinfo = connection_info_ref (candidate);
+                       min_jobs = n_commands;
+
+               } else if (n_commands < min_jobs) {
+                       connection_info_unref (cinfo);
+                       cinfo = connection_info_ref (candidate);
+                       min_jobs = n_commands;
+               }
+       }
+
+exit:
+       if (cinfo != NULL && folder_name != NULL)
+               connection_info_insert_folder_name (cinfo, folder_name);
+
+       if (camel_debug_flag (conman)) {
+               printf ("%s: for-expensive:%d will return:%p cmd-count:%d has-expensive:%d found:%d; 
connections opened:%d max:%d\n", G_STRFUNC, for_expensive_job, cinfo, cinfo ? 
camel_imapx_server_get_command_count (cinfo->is) : -2, cinfo ? camel_imapx_server_has_expensive_command 
(cinfo->is) : -2, expensive_connections, g_list_length (list), concurrent_connections);
+               for (link = list; link != NULL; link = g_list_next (link)) {
+                       ConnectionInfo *candidate = link->data;
+
+                       printf ("   cmds:%d has-expensive:%d avail:%d cinfo:%p\n", 
camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command 
(candidate->is), connection_info_is_available (candidate), candidate);
+               }
+       }
+
+       if (cinfo != NULL) {
+               is = g_object_ref (cinfo->is);
+               connection_info_unref (cinfo);
+       }
+
+       g_object_unref (store);
+
+       return is;
+}
+
+static CamelIMAPXServer *
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
+                                      const gchar *folder_name,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       CamelStore *store;
+       CamelIMAPXServer *is = NULL;
+       CamelIMAPXStore *imapx_store;
+       ConnectionInfo *cinfo = NULL;
+       gboolean success;
+
+       /* Caller must be holding CON_WRITE_LOCK. */
+
+       /* Check if we got cancelled while we were waiting. */
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return NULL;
+
+       store = camel_imapx_conn_manager_ref_store (con_man);
+       g_return_val_if_fail (store != NULL, NULL);
+
+       imapx_store = CAMEL_IMAPX_STORE (store);
+
+       is = camel_imapx_server_new (imapx_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
+        *     we should not have multiple IMAPX connections trying to
+        *     authenticate at once, so this should be thread-safe.
+        */
+       camel_imapx_store_set_connecting_server (imapx_store, is);
+       success = camel_imapx_server_connect (is, cancellable, error);
+       camel_imapx_store_set_connecting_server (imapx_store, NULL);
+
+       if (!success) {
+               g_clear_object (&is);
+               goto exit;
+       }
+
+       g_signal_connect (
+               is, "shutdown",
+               G_CALLBACK (imapx_conn_shutdown), con_man);
+
+       g_signal_connect (
+               is, "mailbox-select",
+               G_CALLBACK (imapx_conn_update_select), con_man);
+       g_signal_connect (
+               is, "mailbox-closed",
+               G_CALLBACK (imapx_conn_mailbox_closed), con_man);
+
+       g_signal_connect (
+               is, "mailbox-created",
+               G_CALLBACK (imapx_conn_mailbox_created_cb), con_man);
+
+       g_signal_connect (
+               is, "mailbox-renamed",
+               G_CALLBACK (imapx_conn_mailbox_renamed_cb), con_man);
+
+       g_signal_connect (
+               is, "mailbox-updated",
+               G_CALLBACK (imapx_conn_mailbox_updated_cb), con_man);
+
+       cinfo = connection_info_new (is);
+
+       if (folder_name != NULL)
+               connection_info_insert_folder_name (cinfo, folder_name);
+
+       /* Takes ownership of the ConnectionInfo. */
+       con_man->priv->connections = g_list_prepend (
+               con_man->priv->connections, cinfo);
+
+       c (is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, 
g_list_length (con_man->priv->connections));
+
+exit:
+       g_object_unref (store);
+
+       return is;
+}
+
+/****************************/
+
+CamelIMAPXConnManager *
+camel_imapx_conn_manager_new (CamelStore *store)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+       return g_object_new (
+               CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+}
+
+CamelStore *
+camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *con_man)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+       return g_weak_ref_get (&con_man->priv->store);
+}
+
+CamelIMAPXServer *
+camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
+                                         const gchar *folder_name,
+                                        gboolean for_expensive_job,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       CamelIMAPXServer *is = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+       /* Hold the writer lock while we requisition a CamelIMAPXServer
+        * to prevent other threads from adding or removing connections. */
+       CON_WRITE_LOCK (con_man);
+
+       /* Check if we got cancelled while waiting for the lock. */
+       if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
+               if (is == NULL)
+                       is = imapx_create_new_connection_unlocked (
+                               con_man, folder_name, cancellable, error);
+       }
+
+       CON_WRITE_UNLOCK (con_man);
+
+       return is;
+}
+
+GList *
+camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+{
+       GList *list, *link;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+       list = imapx_conn_manager_list_info (con_man);
+
+       /* Swap ConnectionInfo for CamelIMAPXServer in each link. */
+       for (link = list; link != NULL; link = g_list_next (link)) {
+               ConnectionInfo *cinfo = link->data;
+               link->data = g_object_ref (cinfo->is);
+               connection_info_unref (cinfo);
+       }
+
+       return list;
+}
+
+/* Used for handling operations that fails to execute and that needs to removed from folder list */
+void
+camel_imapx_conn_manager_update_con_info (CamelIMAPXConnManager *con_man,
+                                          CamelIMAPXServer *is,
+                                          const gchar *folder_name)
+{
+       ConnectionInfo *cinfo;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+       /* Returns a new ConnectionInfo reference. */
+       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+
+       if (cinfo == NULL)
+               return;
+
+       if (camel_imapx_server_folder_name_in_jobs (is, folder_name)) {
+               connection_info_remove_folder_name (cinfo, folder_name);
+               c (is->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
+       }
+
+       connection_info_unref (cinfo);
+}
+
+void
+camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+
+       CON_WRITE_LOCK (con_man);
+
+       g_list_free_full (
+               con_man->priv->connections,
+               (GDestroyNotify) connection_info_cancel_and_unref);
+       con_man->priv->connections = NULL;
+
+       CON_WRITE_UNLOCK (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..5ebfd71
--- /dev/null
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -0,0 +1,94 @@
+/*-*- 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"
+
+G_BEGIN_DECLS
+
+/* Standard GObject macros */
+#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_IMAPX_CONN_MANAGER_CLASS(cls) \
+       (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 {
+       GObject parent;
+
+       CamelIMAPXConnManagerPrivate *priv;
+};
+
+struct _CamelIMAPXConnManagerClass {
+       GObjectClass parent_class;
+
+       /* Signals */
+       void            (*mailbox_created)      (CamelIMAPXConnManager *con_man,
+                                                CamelIMAPXMailbox *mailbox);
+       void            (*mailbox_renamed)      (CamelIMAPXConnManager *con_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                const gchar *oldname);
+       void            (*mailbox_updated)      (CamelIMAPXConnManager *con_man,
+                                                CamelIMAPXMailbox *mailbox);
+};
+
+GType          camel_imapx_conn_manager_get_type (void);
+CamelIMAPXConnManager *
+               camel_imapx_conn_manager_new    (CamelStore *store);
+CamelStore *   camel_imapx_conn_manager_ref_store
+                                               (CamelIMAPXConnManager *con_man);
+CamelIMAPXServer *
+               camel_imapx_conn_manager_get_connection
+                                               (CamelIMAPXConnManager *con_man,
+                                                const gchar *folder_name,
+                                                gboolean for_expensive_job,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           camel_imapx_conn_manager_close_connections
+                                               (CamelIMAPXConnManager *con_man);
+GList *                camel_imapx_conn_manager_get_connections
+                                               (CamelIMAPXConnManager *con_man);
+void           camel_imapx_conn_manager_update_con_info
+                                               (CamelIMAPXConnManager *con_man,
+                                                CamelIMAPXServer *server,
+                                                const gchar *folder_name);
+
+G_END_DECLS
+
+#endif /* _CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index 29eebb9..e5962f5 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -303,7 +303,8 @@ imapx_search_by_uids (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXFolder *imapx_folder;
        CamelIMAPXSearch *imapx_search;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXServer *imapx_server = NULL;
+       const gchar *folder_name;
        CamelStore *store;
        GPtrArray *matches;
 
@@ -312,9 +313,11 @@ imapx_search_by_uids (CamelFolder *folder,
 
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL);
+       if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
NULL);
 
        g_mutex_lock (&imapx_folder->search_lock);
 
@@ -328,6 +331,9 @@ imapx_search_by_uids (CamelFolder *folder,
 
        camel_imapx_search_set_server (imapx_search, NULL);
 
+       if (imapx_server)
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        g_mutex_unlock (&imapx_folder->search_lock);
 
        g_clear_object (&imapx_server);
@@ -344,15 +350,18 @@ imapx_count_by_expression (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXFolder *imapx_folder;
        CamelIMAPXSearch *imapx_search;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXServer *imapx_server = NULL;
+       const gchar *folder_name;
        CamelStore *store;
        guint32 matches;
 
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL);
+       if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
NULL);
 
        g_mutex_lock (&imapx_folder->search_lock);
 
@@ -366,6 +375,9 @@ imapx_count_by_expression (CamelFolder *folder,
 
        camel_imapx_search_set_server (imapx_search, NULL);
 
+       if (imapx_server)
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        g_mutex_unlock (&imapx_folder->search_lock);
 
        g_clear_object (&imapx_server);
@@ -382,15 +394,18 @@ imapx_search_by_expression (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXFolder *imapx_folder;
        CamelIMAPXSearch *imapx_search;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXServer *imapx_server = NULL;
+       const gchar *folder_name;
        CamelStore *store;
        GPtrArray *matches;
 
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL);
+       if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
+               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
NULL);
 
        g_mutex_lock (&imapx_folder->search_lock);
 
@@ -404,6 +419,9 @@ imapx_search_by_expression (CamelFolder *folder,
 
        camel_imapx_search_set_server (imapx_search, NULL);
 
+       if (imapx_server)
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        g_mutex_unlock (&imapx_folder->search_lock);
 
        g_clear_object (&imapx_server);
@@ -436,15 +454,17 @@ imapx_append_message_sync (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
+       const gchar *folder_name;
        gboolean success = FALSE;
 
        if (appended_uid != NULL)
                *appended_uid = NULL;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -452,14 +472,18 @@ imapx_append_message_sync (CamelFolder *folder,
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        success = camel_imapx_server_append_message (
                imapx_server, mailbox, folder->summary,
                CAMEL_IMAPX_FOLDER (folder)->cache, message,
                info, appended_uid, cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
 exit:
        g_clear_object (&mailbox);
        g_clear_object (&imapx_server);
@@ -476,12 +500,14 @@ imapx_expunge_sync (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
+       const gchar *folder_name;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -489,8 +515,10 @@ imapx_expunge_sync (CamelFolder *folder,
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
                CamelFolder *trash;
@@ -528,6 +556,8 @@ imapx_expunge_sync (CamelFolder *folder,
        success = camel_imapx_server_expunge (
                imapx_server, mailbox, cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
 exit:
        g_clear_object (&mailbox);
        g_clear_object (&imapx_server);
@@ -607,6 +637,7 @@ imapx_get_message_sync (CamelFolder *folder,
        } else {
                CamelIMAPXServer *imapx_server;
                CamelIMAPXMailbox *mailbox;
+               const gchar *folder_name;
 
                if (offline_message) {
                        g_set_error (
@@ -616,8 +647,9 @@ imapx_get_message_sync (CamelFolder *folder,
                        return NULL;
                }
 
+               folder_name = camel_folder_get_full_name (folder);
                imapx_server = camel_imapx_store_ref_server (
-                       CAMEL_IMAPX_STORE (store), error);
+                       CAMEL_IMAPX_STORE (store), folder_name, FALSE, cancellable, error);
 
                if (imapx_server == NULL)
                        return NULL;
@@ -626,6 +658,7 @@ imapx_get_message_sync (CamelFolder *folder,
                        CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
                if (mailbox == NULL) {
+                       camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, 
folder_name);
                        g_object_unref (imapx_server);
                        return NULL;
                }
@@ -635,6 +668,8 @@ imapx_get_message_sync (CamelFolder *folder,
                        CAMEL_IMAPX_FOLDER (folder)->cache, uid,
                        cancellable, error);
 
+               camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
+
                g_clear_object (&mailbox);
                g_clear_object (&imapx_server);
        }
@@ -689,25 +724,31 @@ imapx_get_quota_info_sync (CamelFolder *folder,
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
        CamelFolderQuotaInfo *quota_info = NULL;
+       const gchar *folder_name;
        gchar **quota_roots;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        success = camel_imapx_server_update_quota_info (
                imapx_server, mailbox, cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        if (!success)
                goto exit;
 
@@ -755,12 +796,14 @@ imapx_refresh_info_sync (CamelFolder *folder,
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
        CamelFolderChangeInfo *changes;
+       const gchar *folder_name;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -768,12 +811,16 @@ imapx_refresh_info_sync (CamelFolder *folder,
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        changes = camel_imapx_server_refresh_info (
                imapx_server, mailbox, cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        if (changes != NULL) {
                if (camel_folder_change_info_changed (changes))
                        camel_folder_changed (folder, changes);
@@ -984,21 +1031,27 @@ imapx_synchronize_sync (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
+       const gchar *folder_name;
        gboolean need_to_expunge;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       /* while it can be expensive job, do not treat it as such, to avoid a blockage
+          by really expensive jobs */
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        success = camel_imapx_server_sync_changes (
                imapx_server, mailbox, cancellable, error);
@@ -1025,6 +1078,8 @@ imapx_synchronize_sync (CamelFolder *folder,
                        imapx_server, mailbox, cancellable, error);
        }
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
 exit:
        g_clear_object (&mailbox);
        g_clear_object (&imapx_server);
@@ -1042,12 +1097,14 @@ imapx_synchronize_message_sync (CamelFolder *folder,
        CamelIMAPXStore *imapx_store;
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *mailbox = NULL;
+       const gchar *folder_name;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (folder);
+       folder_name = camel_folder_get_full_name (folder);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -1055,14 +1112,18 @@ imapx_synchronize_message_sync (CamelFolder *folder,
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL)
+       if (mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        success = camel_imapx_server_sync_message (
                imapx_server, mailbox, folder->summary,
                CAMEL_IMAPX_FOLDER (folder)->cache, uid,
                cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
 exit:
        g_clear_object (&mailbox);
        g_clear_object (&imapx_server);
@@ -1084,12 +1145,14 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
        CamelIMAPXServer *imapx_server;
        CamelIMAPXMailbox *src_mailbox = NULL;
        CamelIMAPXMailbox *dst_mailbox = NULL;
+       const gchar *folder_name;
        gboolean success = FALSE;
 
        store = camel_folder_get_parent_store (source);
+       folder_name = camel_folder_get_full_name (source);
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -1097,19 +1160,25 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
        src_mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (source), cancellable, error);
 
-       if (src_mailbox == NULL)
+       if (src_mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        dst_mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (dest), cancellable, error);
 
-       if (dst_mailbox == NULL)
+       if (dst_mailbox == NULL) {
+               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
                goto exit;
+       }
 
        success = camel_imapx_server_copy_message (
                imapx_server, src_mailbox, dst_mailbox, uids,
                delete_originals, cancellable, error);
 
+       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+
        /* Update destination folder only if it's not frozen,
         * to avoid updating for each "move" action on a single
         * message while filtering. */
@@ -1452,7 +1521,7 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
 
        /* See if the CamelIMAPXServer already has the mailbox. */
 
-       server = camel_imapx_store_ref_server (imapx_store, error);
+       server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (server == NULL)
                goto exit;
diff --git a/camel/providers/imapx/camel-imapx-mailbox.c b/camel/providers/imapx/camel-imapx-mailbox.c
index 68bc6bc..dbe6313 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.c
+++ b/camel/providers/imapx/camel-imapx-mailbox.c
@@ -29,6 +29,7 @@
  **/
 
 #include "camel-imapx-mailbox.h"
+#include "camel-imapx-utils.h"
 
 #define CAMEL_IMAPX_MAILBOX_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -367,6 +368,26 @@ camel_imapx_mailbox_get_separator (CamelIMAPXMailbox *mailbox)
 }
 
 /**
+ * camel_imapx_mailbox_dup_folder_path:
+ * @mailbox: a #CamelIMAPXMailbox
+ *
+ * Returns the mailbox name as folder path.
+ *
+ * Returns: the mailbox name as folder path.
+ *
+ * Since: 3.12.1
+ **/
+gchar *
+camel_imapx_mailbox_dup_folder_path (CamelIMAPXMailbox *mailbox)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+
+       return camel_imapx_mailbox_to_folder_path (
+               camel_imapx_mailbox_get_name (mailbox),
+               camel_imapx_mailbox_get_separator (mailbox));
+}
+
+/**
  * camel_imapx_mailbox_get_namespace:
  * @mailbox: a #CamelIMAPXMailbox
  *
diff --git a/camel/providers/imapx/camel-imapx-mailbox.h b/camel/providers/imapx/camel-imapx-mailbox.h
index bc54a52..76af75d 100644
--- a/camel/providers/imapx/camel-imapx-mailbox.h
+++ b/camel/providers/imapx/camel-imapx-mailbox.h
@@ -85,6 +85,8 @@ const gchar * camel_imapx_mailbox_get_name
                                        (CamelIMAPXMailbox *mailbox);
 gchar          camel_imapx_mailbox_get_separator
                                        (CamelIMAPXMailbox *mailbox);
+gchar *                camel_imapx_mailbox_dup_folder_path
+                                       (CamelIMAPXMailbox *mailbox);
 CamelIMAPXNamespace *
                camel_imapx_mailbox_get_namespace
                                        (CamelIMAPXMailbox *mailbox);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 918dc65..2ab6b5b 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -398,6 +398,11 @@ struct _CamelIMAPXServerPrivate {
        GMainContext *idle_main_context;
        GSource *idle_pending;
        CamelIMAPXIdleState idle_state;
+
+       GMutex jobs_prop_lock;
+       GHashTable *jobs_prop_folder_paths;
+       gint jobs_prop_command_count; /* without IDLE command */
+       gint jobs_prop_expensive_command_count;
 };
 
 enum {
@@ -412,6 +417,7 @@ enum {
        MAILBOX_CREATED,
        MAILBOX_RENAMED,
        MAILBOX_UPDATED,
+       SHUTDOWN,
        LAST_SIGNAL
 };
 
@@ -576,6 +582,138 @@ imapx_weak_ref_free (GWeakRef *weak_ref)
        g_slice_free (GWeakRef, weak_ref);
 }
 
+static void
+imapx_server_command_added (CamelIMAPXServer *imapx_server,
+                           CamelIMAPXCommand *command)
+{
+       CamelIMAPXJob *job;
+
+       g_return_if_fail (command != NULL);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       job = camel_imapx_command_get_job (command);
+
+       if (job) {
+               /* without IDLE commands */
+               if (!(job->type & IMAPX_JOB_IDLE))
+                       imapx_server->priv->jobs_prop_command_count++;
+
+               if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0)
+                       imapx_server->priv->jobs_prop_expensive_command_count++;
+       }
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_command_removed (CamelIMAPXServer *imapx_server,
+                             CamelIMAPXCommand *command)
+{
+       CamelIMAPXJob *job;
+
+       g_return_if_fail (command != NULL);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       job = camel_imapx_command_get_job (command);
+
+       if (job) {
+               /* without IDLE commands */
+               if (!(job->type & IMAPX_JOB_IDLE)) {
+                       imapx_server->priv->jobs_prop_command_count--;
+                       g_warn_if_fail (imapx_server->priv->jobs_prop_command_count >= 0);
+               }
+
+               if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0) {
+                       imapx_server->priv->jobs_prop_expensive_command_count--;
+                       g_warn_if_fail (imapx_server->priv->jobs_prop_expensive_command_count >= 0);
+               }
+       }
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_add_job_mailbox (CamelIMAPXServer *imapx_server,
+                             CamelIMAPXMailbox *mailbox)
+{
+       gchar *folder_path;
+       gint n_stored;
+
+       g_return_if_fail (mailbox != NULL);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
+
+       n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, 
folder_path));
+       /* takes ownership of folder_path */
+       g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER 
(n_stored + 1));
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_remove_job_mailbox (CamelIMAPXServer *imapx_server,
+                                CamelIMAPXMailbox *mailbox)
+{
+       gchar *folder_path;
+       gint n_stored;
+
+       g_return_if_fail (mailbox != NULL);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
+
+       n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, 
folder_path));
+       g_warn_if_fail (n_stored >= 1);
+
+       n_stored--;
+       if (n_stored > 0) {
+               /* takes ownership of folder_path */
+               g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, folder_path, GINT_TO_POINTER 
(n_stored));
+       } else {
+               g_hash_table_remove (imapx_server->priv->jobs_prop_folder_paths, folder_path);
+               g_free (folder_path);
+       }
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_job_added (CamelIMAPXServer *imapx_server,
+                       CamelIMAPXJob *job)
+{
+       CamelIMAPXMailbox *mailbox;
+
+       g_return_if_fail (job != NULL);
+
+       mailbox = camel_imapx_job_ref_mailbox (job);
+
+       if (mailbox != NULL) {
+               imapx_server_add_job_mailbox (imapx_server, mailbox);
+               g_object_unref (mailbox);
+       }
+}
+
+static void
+imapx_server_job_removed (CamelIMAPXServer *imapx_server,
+                         CamelIMAPXJob *job)
+{
+       CamelIMAPXMailbox *mailbox;
+
+       g_return_if_fail (job != NULL);
+
+       mailbox = camel_imapx_job_ref_mailbox (job);
+
+       if (mailbox != NULL) {
+               imapx_server_remove_job_mailbox (imapx_server, mailbox);
+               g_object_unref (mailbox);
+       }
+}
+
 static const CamelIMAPXUntaggedRespHandlerDesc *
 replace_untagged_descriptor (GHashTable *untagged_handlers,
                              const gchar *key,
@@ -834,6 +972,7 @@ imapx_register_job (CamelIMAPXServer *is,
        if (is->state >= IMAPX_INITIALISED) {
                QUEUE_LOCK (is);
                g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
+               imapx_server_job_added (is, job);
                QUEUE_UNLOCK (is);
 
        } else {
@@ -856,8 +995,10 @@ imapx_unregister_job (CamelIMAPXServer *is,
                camel_imapx_job_done (job);
 
        QUEUE_LOCK (is);
-       if (g_queue_remove (&is->jobs, job))
+       if (g_queue_remove (&is->jobs, job)) {
+               imapx_server_job_removed (is, job);
                camel_imapx_job_unref (job);
+       }
        QUEUE_UNLOCK (is);
 }
 
@@ -878,18 +1019,12 @@ imapx_server_ref_folder (CamelIMAPXServer *is,
 {
        CamelFolder *folder;
        CamelIMAPXStore *store;
-       const gchar *mailbox_name;
        gchar *folder_path;
-       gchar separator;
        GError *local_error = NULL;
 
-       mailbox_name = camel_imapx_mailbox_get_name (mailbox);
-       separator = camel_imapx_mailbox_get_separator (mailbox);
-
        store = camel_imapx_server_ref_store (is);
 
-       folder_path = camel_imapx_mailbox_to_folder_path (
-               mailbox_name, separator);
+       folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
 
        folder = camel_store_get_folder_sync (
                CAMEL_STORE (store), folder_path, 0, NULL, &local_error);
@@ -906,7 +1041,7 @@ imapx_server_ref_folder (CamelIMAPXServer *is,
        if (local_error != NULL) {
                g_warning (
                        "%s: Failed to get folder for '%s': %s",
-                       G_STRFUNC, mailbox_name, local_error->message);
+                       G_STRFUNC, camel_imapx_mailbox_get_name (mailbox), local_error->message);
                g_error_free (local_error);
        }
 
@@ -1263,9 +1398,10 @@ imapx_command_start (CamelIMAPXServer *is,
                      CamelIMAPXCommand *ic)
 {
        CamelIMAPXCommandPart *cp;
-       GInputStream *input_stream;
-       GOutputStream *output_stream;
-       GCancellable *cancellable;
+       CamelIMAPXJob *job;
+       GInputStream *input_stream = NULL;
+       GOutputStream *output_stream = NULL;
+       GCancellable *cancellable = NULL;
        gboolean cp_continuation;
        gboolean cp_literal_plus;
        GList *head;
@@ -1289,6 +1425,25 @@ imapx_command_start (CamelIMAPXServer *is,
                is->literal = ic;
 
        camel_imapx_command_queue_push_tail (is->active, ic);
+       imapx_server_command_added (is, ic);
+
+       job = camel_imapx_command_get_job (ic);
+       if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job), 
&local_error)) {
+               camel_imapx_job_take_error (job, local_error);
+               local_error = NULL;
+
+               camel_imapx_command_queue_remove (is->active, ic);
+               imapx_server_command_removed (is, ic);
+
+               if (ic->complete != NULL)
+                       ic->complete (is, ic);
+
+               if (is->literal == ic)
+                       is->literal = NULL;
+
+               goto exit;
+       }
+
 
        input_stream = camel_imapx_server_ref_input_stream (is);
        output_stream = camel_imapx_server_ref_output_stream (is);
@@ -1336,6 +1491,7 @@ imapx_command_start (CamelIMAPXServer *is,
 
 fail:
        camel_imapx_command_queue_remove (is->active, ic);
+       imapx_server_command_removed (is, ic);
 
        /* Break the parser thread out of its loop so it disconnects. */
        g_main_loop_quit (is->priv->parser_main_loop);
@@ -1474,6 +1630,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
 
                        ic = camel_imapx_command_ref (link->data);
                        camel_imapx_command_queue_delete_link (is->queue, link);
+                       imapx_server_command_removed (is, ic);
                        imapx_command_start (is, ic);
                        camel_imapx_command_unref (ic);
 
@@ -1625,6 +1782,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
 
                        ic = camel_imapx_command_ref (link->data);
                        camel_imapx_command_queue_delete_link (is->queue, link);
+                       imapx_server_command_removed (is, ic);
                        imapx_command_start (is, ic);
                        camel_imapx_command_unref (ic);
 
@@ -1719,6 +1877,7 @@ imapx_command_start_next (CamelIMAPXServer *is)
 
                        ic = camel_imapx_command_ref (link->data);
                        camel_imapx_command_queue_delete_link (is->queue, link);
+                       imapx_server_command_removed (is, ic);
                        imapx_command_start (is, ic);
                        camel_imapx_command_unref (ic);
 
@@ -1783,6 +1942,7 @@ imapx_command_queue (CamelIMAPXServer *is,
        }
 
        camel_imapx_command_queue_insert_sorted (is->queue, ic);
+       imapx_server_command_added (is, ic);
 
        imapx_command_start_next (is);
 
@@ -2340,8 +2500,8 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                                camel_folder_change_info_change_uid (
                                        is->priv->changes, uid);
-                               g_free (uid);
                        }
+                       g_free (uid);
 
                        if (changed && imapx_in_idle (is)) {
                                camel_folder_summary_save_to_db (
@@ -3429,6 +3589,7 @@ imapx_completion (CamelIMAPXServer *is,
         * We're holding our own reference to the command so there's
         * no risk of accidentally finalizing it here. */
        camel_imapx_command_queue_remove (is->active, ic);
+       imapx_server_command_removed (is, ic);
        camel_imapx_command_queue_push_tail (is->done, ic);
 
        if (is->literal == ic)
@@ -3550,6 +3711,7 @@ imapx_command_run (CamelIMAPXServer *is,
 
        QUEUE_LOCK (is);
        camel_imapx_command_queue_remove (is->active, ic);
+       imapx_server_command_removed (is, ic);
        QUEUE_UNLOCK (is);
 
        g_object_unref (input_stream);
@@ -4070,6 +4232,7 @@ imapx_command_select_done (CamelIMAPXServer *is,
                        CamelIMAPXCommand *cw = link->data;
                        camel_imapx_command_ref (cw);
                        camel_imapx_command_queue_delete_link (is->queue, link);
+                       imapx_server_command_removed (is, cw);
                        camel_imapx_command_queue_push_tail (failed, cw);
                        camel_imapx_command_unref (cw);
                }
@@ -7563,6 +7726,14 @@ imapx_abort_all_commands (CamelIMAPXServer *is,
        camel_imapx_command_queue_transfer (is->queue, queue);
        camel_imapx_command_queue_transfer (is->active, queue);
 
+       head = camel_imapx_command_queue_peek_head_link (queue);
+       for (link = head; link != NULL; link = g_list_next (link)) {
+               CamelIMAPXCommand *ic = link->data;
+
+               if (ic)
+                       imapx_server_command_removed (is, ic);
+       }
+
        QUEUE_UNLOCK (is);
 
        head = camel_imapx_command_queue_peek_head_link (queue);
@@ -7661,7 +7832,6 @@ static gpointer
 imapx_parser_thread (gpointer user_data)
 {
        CamelIMAPXServer *is;
-       CamelIMAPXStore *store;
        GInputStream *input_stream;
        GCancellable *cancellable;
        GSource *pollable_source;
@@ -7702,14 +7872,10 @@ imapx_parser_thread (gpointer user_data)
        is->state = IMAPX_SHUTDOWN;
        QUEUE_UNLOCK (is);
 
-       /* Disconnect the CamelService. */
-       store = camel_imapx_server_ref_store (is);
-       camel_service_disconnect_sync (
-               CAMEL_SERVICE (store), FALSE, NULL, NULL);
-       g_object_unref (store);
-
        g_main_context_pop_thread_default (is->priv->parser_main_context);
 
+       g_signal_emit (is, signals[SHUTDOWN], 0);
+
        g_object_unref (is);
 
        return NULL;
@@ -7856,6 +8022,9 @@ imapx_server_finalize (GObject *object)
        g_main_loop_unref (is->priv->idle_main_loop);
        g_main_context_unref (is->priv->idle_main_context);
 
+       g_mutex_clear (&is->priv->jobs_prop_lock);
+       g_hash_table_destroy (is->priv->jobs_prop_folder_paths);
+
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_imapx_server_parent_class)->finalize (object);
 }
@@ -7879,6 +8048,8 @@ static void
 imapx_server_mailbox_select (CamelIMAPXServer *is,
                              CamelIMAPXMailbox *mailbox)
 {
+       imapx_server_add_job_mailbox (is, mailbox);
+
        e (
                is->tagprefix,
                "%s::mailbox-select (\"%s\")\n",
@@ -7890,6 +8061,8 @@ static void
 imapx_server_mailbox_closed (CamelIMAPXServer *is,
                              CamelIMAPXMailbox *mailbox)
 {
+       imapx_server_remove_job_mailbox (is, mailbox);
+
        e (
                is->tagprefix,
                "%s::mailbox-closed (\"%s\")\n",
@@ -8020,6 +8193,19 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
                G_TYPE_NONE, 1,
                CAMEL_TYPE_IMAPX_MAILBOX);
 
+       /**
+        * CamelIMAPXServer::shutdown
+        * @server: the #CamelIMAPXServer which emitted the signal
+        **/
+       signals[SHUTDOWN] = g_signal_new (
+               "shutdown",
+               G_OBJECT_CLASS_TYPE (class),
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (CamelIMAPXServerClass, shutdown),
+               NULL, NULL,
+               g_cclosure_marshal_VOID__VOID,
+               G_TYPE_NONE, 0);
+
        class->tagprefix = 'A';
 }
 
@@ -8048,6 +8234,11 @@ camel_imapx_server_init (CamelIMAPXServer *is)
        g_mutex_init (&is->priv->select_lock);
        g_mutex_init (&is->priv->search_results_lock);
        g_mutex_init (&is->priv->known_alerts_lock);
+       g_mutex_init (&is->priv->jobs_prop_lock);
+
+       is->priv->jobs_prop_folder_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       is->priv->jobs_prop_command_count = 0;
+       is->priv->jobs_prop_expensive_command_count = 0;
 
        is->queue = camel_imapx_command_queue_new ();
        is->active = camel_imapx_command_queue_new ();
@@ -9476,6 +9667,56 @@ camel_imapx_server_uid_search (CamelIMAPXServer *is,
        return results;
 }
 
+gboolean
+camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
+                                       const gchar *folder_path)
+{
+       gboolean res;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+       g_return_val_if_fail (folder_path != NULL, FALSE);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path)) 
0;
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+       return res;
+}
+
+gboolean
+camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
+{
+       gboolean res;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+       return res;
+}
+
+gint
+camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
+{
+       guint32 res;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+
+       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+       res = imapx_server->priv->jobs_prop_command_count;
+
+       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+       return res;
+}
+
 /**
  * camel_imapx_server_register_untagged_handler:
  * @is: a #CamelIMAPXServer instance
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index f429292..3842b33 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -133,6 +133,7 @@ struct _CamelIMAPXServerClass {
                                                 const gchar *oldname);
        void            (*mailbox_updated)      (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox);
+       void            (*shutdown)             (CamelIMAPXServer *is);
 };
 
 GType          camel_imapx_server_get_type     (void);
@@ -259,6 +260,13 @@ GPtrArray *        camel_imapx_server_uid_search   (CamelIMAPXServer *is,
                                                 const gchar *criteria,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       camel_imapx_server_folder_name_in_jobs
+                                               (CamelIMAPXServer *imapx_server,
+                                                const gchar *folder_path);
+gboolean       camel_imapx_server_has_expensive_command
+                                               (CamelIMAPXServer *imapx_server);
+gint           camel_imapx_server_get_command_count
+                                               (CamelIMAPXServer *imapx_server);
 const CamelIMAPXUntaggedRespHandlerDesc *
                camel_imapx_server_register_untagged_handler
                                                (CamelIMAPXServer *is,
diff --git a/camel/providers/imapx/camel-imapx-settings.c b/camel/providers/imapx/camel-imapx-settings.c
index a60907f..381bc42 100644
--- a/camel/providers/imapx/camel-imapx-settings.c
+++ b/camel/providers/imapx/camel-imapx-settings.c
@@ -32,6 +32,7 @@ struct _CamelIMAPXSettingsPrivate {
        gchar *shell_command;
 
        guint batch_fetch_count;
+       guint concurrent_connections;
 
        gboolean check_all;
        gboolean check_subscribed;
@@ -115,6 +116,12 @@ imapx_settings_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
+               case PROP_CONCURRENT_CONNECTIONS:
+                       camel_imapx_settings_set_concurrent_connections (
+                               CAMEL_IMAPX_SETTINGS (object),
+                               g_value_get_uint (value));
+                       return;
+
                case PROP_FETCH_ORDER:
                        camel_imapx_settings_set_fetch_order (
                                CAMEL_IMAPX_SETTINGS (object),
@@ -268,6 +275,13 @@ imapx_settings_get_property (GObject *object,
                                CAMEL_IMAPX_SETTINGS (object)));
                        return;
 
+               case PROP_CONCURRENT_CONNECTIONS:
+                       g_value_set_uint (
+                               value,
+                               camel_imapx_settings_get_concurrent_connections (
+                               CAMEL_IMAPX_SETTINGS (object)));
+                       return;
+
                case PROP_FETCH_ORDER:
                        g_value_set_enum (
                                value,
@@ -481,6 +495,20 @@ camel_imapx_settings_class_init (CamelIMAPXSettingsClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_CONCURRENT_CONNECTIONS,
+               g_param_spec_uint (
+                       "concurrent-connections",
+                       "Concurrent Connections",
+                       "Number of concurrent IMAP connections to use",
+                       MIN_CONCURRENT_CONNECTIONS,
+                       MAX_CONCURRENT_CONNECTIONS,
+                       3,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
                PROP_FETCH_ORDER,
                g_param_spec_enum (
                        "fetch-order",
@@ -825,6 +853,58 @@ camel_imapx_settings_set_check_subscribed (CamelIMAPXSettings *settings,
 }
 
 /**
+ * camel_imapx_settings_get_concurrent_connections:
+ * @settings: a #CamelIMAPXSettings
+ * 
+ * Returns the number of concurrent network connections to the IMAP server
+ * to use for faster command/response processing.
+ *
+ * Returns: the number of concurrent connections to use
+ *
+ * Since: 3.14
+ **/
+guint
+camel_imapx_settings_get_concurrent_connections (CamelIMAPXSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings), 1);
+
+       return settings->priv->concurrent_connections;
+}
+
+/**
+ * camel_imapx_settings_set_concurrent_connections:
+ * @settings: a #CamelIMAPXSettings
+ * @concurrent_connections: the number of concurrent connections to use
+ *
+ * Sets the number of concurrent network connections to the IMAP server to
+ * use for faster command/response processing.
+ *
+ * The minimum number of connections is 1, the maximum is 7.  The
+ * @concurrent_connections value will be clamped to these limits if
+ * necessary.
+ *
+ * Since: 3.14
+ **/
+void
+camel_imapx_settings_set_concurrent_connections (CamelIMAPXSettings *settings,
+                                                 guint concurrent_connections)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings));
+
+       concurrent_connections = CLAMP (
+               concurrent_connections,
+               MIN_CONCURRENT_CONNECTIONS,
+               MAX_CONCURRENT_CONNECTIONS);
+
+       if (settings->priv->concurrent_connections == concurrent_connections)
+               return;
+
+       settings->priv->concurrent_connections = concurrent_connections;
+
+       g_object_notify (G_OBJECT (settings), "concurrent-connections");
+}
+
+/**
  * camel_imapx_settings_get_fetch_order:
  * @settings: a #CamelIMAPXSettings
  *
diff --git a/camel/providers/imapx/camel-imapx-settings.h b/camel/providers/imapx/camel-imapx-settings.h
index 63f38ed..506953a 100644
--- a/camel/providers/imapx/camel-imapx-settings.h
+++ b/camel/providers/imapx/camel-imapx-settings.h
@@ -70,6 +70,11 @@ gboolean     camel_imapx_settings_get_check_subscribed
 void           camel_imapx_settings_set_check_subscribed
                                                (CamelIMAPXSettings *settings,
                                                 gboolean check_subscribed);
+guint          camel_imapx_settings_get_concurrent_connections
+                                               (CamelIMAPXSettings *settings);
+void           camel_imapx_settings_set_concurrent_connections
+                                               (CamelIMAPXSettings *settings,
+                                                guint concurrent_connections);
 CamelSortType  camel_imapx_settings_get_fetch_order
                                                (CamelIMAPXSettings *settings);
 void           camel_imapx_settings_set_fetch_order
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index 82753c6..eaf3603 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -37,6 +37,7 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
+#include "camel-imapx-conn-manager.h"
 #include "camel-imapx-folder.h"
 #include "camel-imapx-server.h"
 #include "camel-imapx-settings.h"
@@ -55,10 +56,8 @@
        ((obj), CAMEL_TYPE_IMAPX_STORE, CamelIMAPXStorePrivate))
 
 struct _CamelIMAPXStorePrivate {
-       CamelIMAPXServer *connected_server;
+       CamelIMAPXConnManager *con_man;
        CamelIMAPXServer *connecting_server;
-       gulong mailbox_select_handler_id;
-       gulong mailbox_closed_handler_id;
        gulong mailbox_created_handler_id;
        gulong mailbox_renamed_handler_id;
        gulong mailbox_updated_handler_id;
@@ -330,16 +329,11 @@ imapx_store_add_mailbox_to_folder (CamelIMAPXStore *store,
                                    CamelIMAPXMailbox *mailbox)
 {
        CamelIMAPXFolder *folder;
-       const gchar *name;
        gchar *folder_path;
-       gchar separator;
 
        /* Add the CamelIMAPXMailbox to a cached CamelIMAPXFolder. */
 
-       name = camel_imapx_mailbox_get_name (mailbox);
-       separator = camel_imapx_mailbox_get_separator (mailbox);
-
-       folder_path = camel_imapx_mailbox_to_folder_path (name, separator);
+       folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
 
        folder = camel_object_bag_get (
                CAMEL_STORE (store)->folders, folder_path);
@@ -539,16 +533,10 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *store,
                                     CamelIMAPXMailbox *mailbox)
 {
        CamelFolder *folder = NULL;
-       const gchar *mailbox_name;
        gchar *folder_path;
-       gchar separator;
        GError *local_error = NULL;
 
-       mailbox_name = camel_imapx_mailbox_get_name (mailbox);
-       separator = camel_imapx_mailbox_get_separator (mailbox);
-
-       folder_path = camel_imapx_mailbox_to_folder_path (
-               mailbox_name, separator);
+       folder_path = camel_imapx_mailbox_dup_folder_path (mailbox);
 
        folder = camel_store_get_folder_sync (
                CAMEL_STORE (store), folder_path, 0, NULL, &local_error);
@@ -584,21 +572,7 @@ imapx_store_process_mailbox_status (CamelIMAPXStore *store,
 }
 
 static void
-imapx_store_mailbox_select_cb (CamelIMAPXServer *server,
-                               CamelIMAPXMailbox *mailbox,
-                               CamelIMAPXStore *store)
-{
-}
-
-static void
-imapx_store_mailbox_closed_cb (CamelIMAPXServer *server,
-                               CamelIMAPXMailbox *mailbox,
-                               CamelIMAPXStore *store)
-{
-}
-
-static void
-imapx_store_mailbox_created_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_created_cb (CamelIMAPXConnManager *con_man,
                                 CamelIMAPXMailbox *mailbox,
                                 CamelIMAPXStore *store)
 {
@@ -607,7 +581,7 @@ imapx_store_mailbox_created_cb (CamelIMAPXServer *server,
 }
 
 static void
-imapx_store_mailbox_renamed_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_renamed_cb (CamelIMAPXConnManager *con_man,
                                 CamelIMAPXMailbox *mailbox,
                                 const gchar *oldname,
                                 CamelIMAPXStore *store)
@@ -617,7 +591,7 @@ imapx_store_mailbox_renamed_cb (CamelIMAPXServer *server,
 }
 
 static void
-imapx_store_mailbox_updated_cb (CamelIMAPXServer *server,
+imapx_store_mailbox_updated_cb (CamelIMAPXConnManager *con_man,
                                 CamelIMAPXMailbox *mailbox,
                                 CamelIMAPXStore *store)
 {
@@ -714,39 +688,33 @@ imapx_store_dispose (GObject *object)
 {
        CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (object);
 
-       if (imapx_store->priv->mailbox_select_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       imapx_store->priv->connected_server,
-                       imapx_store->priv->mailbox_select_handler_id);
-               imapx_store->priv->mailbox_select_handler_id = 0;
-       }
-
-       if (imapx_store->priv->mailbox_closed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       imapx_store->priv->connected_server,
-                       imapx_store->priv->mailbox_closed_handler_id);
-               imapx_store->priv->mailbox_closed_handler_id = 0;
-       }
+       /* Force disconnect so we don't have it run later,
+        * after we've cleaned up some stuff. */
+       if (imapx_store->priv->con_man != NULL) {
+               if (imapx_store->priv->mailbox_created_handler_id > 0) {
+                       g_signal_handler_disconnect (
+                               imapx_store->priv->con_man,
+                               imapx_store->priv->mailbox_created_handler_id);
+                       imapx_store->priv->mailbox_created_handler_id = 0;
+               }
 
-       if (imapx_store->priv->mailbox_created_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       imapx_store->priv->connected_server,
-                       imapx_store->priv->mailbox_created_handler_id);
-               imapx_store->priv->mailbox_created_handler_id = 0;
-       }
+               if (imapx_store->priv->mailbox_renamed_handler_id > 0) {
+                       g_signal_handler_disconnect (
+                               imapx_store->priv->con_man,
+                               imapx_store->priv->mailbox_renamed_handler_id);
+                       imapx_store->priv->mailbox_renamed_handler_id = 0;
+               }
 
-       if (imapx_store->priv->mailbox_renamed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       imapx_store->priv->connected_server,
-                       imapx_store->priv->mailbox_renamed_handler_id);
-               imapx_store->priv->mailbox_renamed_handler_id = 0;
-       }
+               if (imapx_store->priv->mailbox_updated_handler_id > 0) {
+                       g_signal_handler_disconnect (
+                               imapx_store->priv->con_man,
+                               imapx_store->priv->mailbox_updated_handler_id);
+                       imapx_store->priv->mailbox_updated_handler_id = 0;
+               }
 
-       if (imapx_store->priv->mailbox_updated_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       imapx_store->priv->connected_server,
-                       imapx_store->priv->mailbox_updated_handler_id);
-               imapx_store->priv->mailbox_updated_handler_id = 0;
+               camel_service_disconnect_sync (
+                       CAMEL_SERVICE (imapx_store), TRUE, NULL, NULL);
+               g_clear_object (&imapx_store->priv->con_man);
        }
 
        if (imapx_store->priv->settings_notify_handler_id > 0) {
@@ -758,7 +726,6 @@ imapx_store_dispose (GObject *object)
 
        g_clear_object (&imapx_store->summary);
 
-       g_clear_object (&imapx_store->priv->connected_server);
        g_clear_object (&imapx_store->priv->connecting_server);
        g_clear_object (&imapx_store->priv->settings);
 
@@ -866,81 +833,6 @@ imapx_connect_sync (CamelService *service,
 
        g_clear_object (&priv->connecting_server);
 
-       if (success) {
-               gulong handler_id;
-
-               if (priv->mailbox_select_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->connected_server,
-                               priv->mailbox_select_handler_id);
-                       priv->mailbox_select_handler_id = 0;
-               }
-
-               if (priv->mailbox_closed_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->connected_server,
-                               priv->mailbox_closed_handler_id);
-                       priv->mailbox_closed_handler_id = 0;
-               }
-
-               if (priv->mailbox_created_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->connected_server,
-                               priv->mailbox_created_handler_id);
-                       priv->mailbox_created_handler_id = 0;
-               }
-
-               if (priv->mailbox_renamed_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->connected_server,
-                               priv->mailbox_renamed_handler_id);
-                       priv->mailbox_renamed_handler_id = 0;
-               }
-
-               if (priv->mailbox_updated_handler_id > 0) {
-                       g_signal_handler_disconnect (
-                               priv->connected_server,
-                               priv->mailbox_updated_handler_id);
-                       priv->mailbox_updated_handler_id = 0;
-               }
-
-               if (priv->connected_server != NULL)
-                       camel_imapx_server_shutdown (priv->connected_server);
-
-               g_clear_object (&priv->connected_server);
-               priv->connected_server = g_object_ref (imapx_server);
-
-               handler_id = g_signal_connect (
-                       priv->connected_server, "mailbox-select",
-                       G_CALLBACK (imapx_store_mailbox_select_cb),
-                       service);
-               priv->mailbox_select_handler_id = handler_id;
-
-               handler_id = g_signal_connect (
-                       priv->connected_server, "mailbox-closed",
-                       G_CALLBACK (imapx_store_mailbox_closed_cb),
-                       service);
-               priv->mailbox_closed_handler_id = handler_id;
-
-               handler_id = g_signal_connect (
-                       priv->connected_server, "mailbox-created",
-                       G_CALLBACK (imapx_store_mailbox_created_cb),
-                       service);
-               priv->mailbox_created_handler_id = handler_id;
-
-               handler_id = g_signal_connect (
-                       priv->connected_server, "mailbox-renamed",
-                       G_CALLBACK (imapx_store_mailbox_renamed_cb),
-                       service);
-               priv->mailbox_renamed_handler_id = handler_id;
-
-               handler_id = g_signal_connect (
-                       priv->connected_server, "mailbox-updated",
-                       G_CALLBACK (imapx_store_mailbox_updated_cb),
-                       service);
-               priv->mailbox_updated_handler_id = handler_id;
-       }
-
        g_mutex_unlock (&priv->server_lock);
 
        g_clear_object (&imapx_server);
@@ -958,47 +850,11 @@ imapx_disconnect_sync (CamelService *service,
 
        priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
 
-       g_mutex_lock (&priv->server_lock);
-
-       if (priv->mailbox_select_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->connected_server,
-                       priv->mailbox_select_handler_id);
-               priv->mailbox_select_handler_id = 0;
-       }
-
-       if (priv->mailbox_closed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->connected_server,
-                       priv->mailbox_closed_handler_id);
-               priv->mailbox_closed_handler_id = 0;
-       }
-
-       if (priv->mailbox_created_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->connected_server,
-                       priv->mailbox_created_handler_id);
-               priv->mailbox_created_handler_id = 0;
-       }
+       if (priv->con_man != NULL)
+               camel_imapx_conn_manager_close_connections (priv->con_man);
 
-       if (priv->mailbox_renamed_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->connected_server,
-                       priv->mailbox_renamed_handler_id);
-               priv->mailbox_renamed_handler_id = 0;
-       }
-
-       if (priv->mailbox_updated_handler_id > 0) {
-               g_signal_handler_disconnect (
-                       priv->connected_server,
-                       priv->mailbox_updated_handler_id);
-               priv->mailbox_updated_handler_id = 0;
-       }
-
-       if (priv->connected_server != NULL)
-               camel_imapx_server_shutdown (priv->connected_server);
+       g_mutex_lock (&priv->server_lock);
 
-       g_clear_object (&priv->connected_server);
        g_clear_object (&priv->connecting_server);
 
        g_mutex_unlock (&priv->server_lock);
@@ -1544,7 +1400,7 @@ sync_folders (CamelIMAPXStore *imapx_store,
        guint ii;
        gboolean success;
 
-       server = camel_imapx_store_ref_server (imapx_store, error);
+       server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
        if (server == NULL)
                return FALSE;
 
@@ -1679,7 +1535,7 @@ discover_inbox (CamelIMAPXStore *imapx_store,
        CamelIMAPXMailbox *mailbox = NULL;
        const gchar *attribute;
 
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, NULL);
 
        if (imapx_server == NULL)
                return;
@@ -2026,7 +1882,7 @@ imapx_store_create_folder_sync (CamelStore *store,
        gboolean success;
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                return NULL;
@@ -2136,7 +1992,7 @@ imapx_store_delete_folder_sync (CamelStore *store,
                return FALSE;
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -2189,7 +2045,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
 
        g_object_unref (settings);
 
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -2389,7 +2245,7 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
        gboolean success = FALSE;
 
        imapx_store = CAMEL_IMAPX_STORE (subscribable);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -2439,7 +2295,7 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
        gboolean success = FALSE;
 
        imapx_store = CAMEL_IMAPX_STORE (subscribable);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, error);
+       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
 
        if (imapx_server == NULL)
                goto exit;
@@ -2551,8 +2407,12 @@ camel_subscribable_init (CamelSubscribableInterface *iface)
 static void
 camel_imapx_store_init (CamelIMAPXStore *store)
 {
+       gulong handler_id;
+
        store->priv = CAMEL_IMAPX_STORE_GET_PRIVATE (store);
 
+       store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+
        g_mutex_init (&store->priv->get_finfo_lock);
 
        /* Initialize to zero to ensure we always obtain fresh folder
@@ -2575,11 +2435,31 @@ camel_imapx_store_init (CamelIMAPXStore *store)
        g_signal_connect (
                store, "notify::settings",
                G_CALLBACK (imapx_store_update_store_flags), NULL);
+
+       handler_id = g_signal_connect (
+               store->priv->con_man, "mailbox-created",
+               G_CALLBACK (imapx_store_mailbox_created_cb),
+               store);
+       store->priv->mailbox_created_handler_id = handler_id;
+
+       handler_id = g_signal_connect (
+               store->priv->con_man, "mailbox-renamed",
+               G_CALLBACK (imapx_store_mailbox_renamed_cb),
+               store);
+       store->priv->mailbox_renamed_handler_id = handler_id;
+
+       handler_id = g_signal_connect (
+               store->priv->con_man, "mailbox-updated",
+               G_CALLBACK (imapx_store_mailbox_updated_cb),
+               store);
+       store->priv->mailbox_updated_handler_id = handler_id;
 }
 
 /**
  * camel_imapx_store_ref_server:
  * @store: a #CamelIMAPXStore
+ * @folder_name: name of a folder, for which it'll be used; can be %NULL
+ * @cancellable: a #GCancellable to use ofr possible new connection creation, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Returns the #CamelIMAPXServer for @store, if available.
@@ -2598,17 +2478,19 @@ camel_imapx_store_init (CamelIMAPXStore *store)
  **/
 CamelIMAPXServer *
 camel_imapx_store_ref_server (CamelIMAPXStore *store,
+                             const gchar *folder_name,
+                             gboolean for_expensive_job,
+                             GCancellable *cancellable,
                               GError **error)
 {
        CamelIMAPXServer *server = NULL;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
 
-       g_mutex_lock (&store->priv->server_lock);
+       server = camel_imapx_conn_manager_get_connection (
+               store->priv->con_man, folder_name, for_expensive_job, cancellable, error);
 
-       if (store->priv->connected_server != NULL) {
-               server = g_object_ref (store->priv->connected_server);
-       } else {
+       if (!server) {
                g_set_error (
                        error, CAMEL_SERVICE_ERROR,
                        CAMEL_SERVICE_ERROR_UNAVAILABLE,
@@ -2616,9 +2498,41 @@ camel_imapx_store_ref_server (CamelIMAPXStore *store,
                        "to complete this operation"));
        }
 
+       return server;
+}
+
+/* The caller should hold the store->priv->server_lock already, when calling this */
+void
+camel_imapx_store_set_connecting_server (CamelIMAPXStore *store,
+                                        CamelIMAPXServer *server)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
+
+       if (server)
+               g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
+
+       g_mutex_lock (&store->priv->server_lock);
+
+       if (store->priv->connecting_server != server) {
+               g_clear_object (&store->priv->connecting_server);
+               if (server)
+                       store->priv->connecting_server = g_object_ref (server);
+       }
+
        g_mutex_unlock (&store->priv->server_lock);
+}
 
-       return server;
+void
+camel_imapx_store_folder_op_done (CamelIMAPXStore *store,
+                                 CamelIMAPXServer *server,
+                                 const gchar *folder_name)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
+       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
+       g_return_if_fail (folder_name != NULL);
+
+       camel_imapx_conn_manager_update_con_info (
+               store->priv->con_man, server, folder_name);
 }
 
 CamelFolderQuotaInfo *
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index 82337d2..0da0b16 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -65,7 +65,17 @@ struct _CamelIMAPXStoreClass {
 GType          camel_imapx_store_get_type      (void);
 CamelIMAPXServer *
                camel_imapx_store_ref_server    (CamelIMAPXStore *store,
+                                                const gchar *folder_name,
+                                                gboolean for_expensive_job,
+                                                GCancellable *cancellable,
                                                 GError **error);
+void           camel_imapx_store_set_connecting_server
+                                               (CamelIMAPXStore *store,
+                                                CamelIMAPXServer *server);
+void           camel_imapx_store_folder_op_done
+                                               (CamelIMAPXStore *store,
+                                                CamelIMAPXServer *server,
+                                                const gchar *folder_name);
 CamelFolderQuotaInfo *
                camel_imapx_store_dup_quota_info
                                                (CamelIMAPXStore *store,
diff --git a/camel/providers/imapx/camel-imapx-utils.c b/camel/providers/imapx/camel-imapx-utils.c
index 2ebfd1b..bef9ffa 100644
--- a/camel/providers/imapx/camel-imapx-utils.c
+++ b/camel/providers/imapx/camel-imapx-utils.c
@@ -56,6 +56,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"
@@ -3118,4 +3119,3 @@ imapx_get_temp_uid (void)
 
        return res;
 }
-
diff --git a/camel/providers/imapx/camel-imapx-utils.h b/camel/providers/imapx/camel-imapx-utils.h
index fff969b..6e42b5c 100644
--- a/camel/providers/imapx/camel-imapx-utils.h
+++ b/camel/providers/imapx/camel-imapx-utils.h
@@ -368,13 +368,14 @@ 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 << 7)-1)
+#define CAMEL_IMAPX_DEBUG_ALL          (~0)
 
 #define camel_debug_flag(type) \
-       (camel_imapx_debug_flags & \
-       CAMEL_IMAPX_DEBUG_ALL & CAMEL_IMAPX_DEBUG_ ## type)
+       ((camel_imapx_debug_flags & \
+       CAMEL_IMAPX_DEBUG_ALL & CAMEL_IMAPX_DEBUG_ ## type) != 0)
 #define camel_imapx_debug(type, tagprefix, fmt, ...) \
        G_STMT_START { \
                if (camel_debug_flag (type)) { \


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