[evolution-data-server] Bug 745545 - [IMAPx] Rewrite job queue to one central



commit 267f78c1c878675f215ea845166d3f37e31f38fa
Author: Milan Crha <mcrha redhat com>
Date:   Tue Aug 4 19:17:57 2015 +0200

    Bug 745545 - [IMAPx] Rewrite job queue to one central

 camel/camel-operation.c                          |   46 +-
 camel/providers/imapx/camel-imapx-command.c      |  380 +-
 camel/providers/imapx/camel-imapx-command.h      |   69 +-
 camel/providers/imapx/camel-imapx-conn-manager.c | 2188 +++++--
 camel/providers/imapx/camel-imapx-conn-manager.h |  138 +-
 camel/providers/imapx/camel-imapx-folder.c       |  392 +-
 camel/providers/imapx/camel-imapx-input-stream.c |    5 +-
 camel/providers/imapx/camel-imapx-job.c          |  719 +-
 camel/providers/imapx/camel-imapx-job.h          |  136 +-
 camel/providers/imapx/camel-imapx-search.c       |   25 +-
 camel/providers/imapx/camel-imapx-server.c       | 8468 ++++++----------------
 camel/providers/imapx/camel-imapx-server.h       |  129 +-
 camel/providers/imapx/camel-imapx-store.c        |  433 +-
 camel/providers/imapx/camel-imapx-store.h        |   20 +-
 po/POTFILES.in                                   |    1 +
 15 files changed, 4784 insertions(+), 8365 deletions(-)
---
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 74e458e..b064c2c 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -50,6 +50,9 @@ struct _CamelOperationPrivate {
 
 enum {
        STATUS,
+       PUSH_MESSAGE,
+       POP_MESSAGE,
+       PROGRESS,
        LAST_SIGNAL
 };
 
@@ -174,6 +177,32 @@ camel_operation_class_init (CamelOperationClass *class)
                G_TYPE_NONE, 2,
                G_TYPE_STRING,
                G_TYPE_INT);
+
+       signals[PUSH_MESSAGE] = g_signal_new (
+               "push-message",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               NULL,
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1,
+               G_TYPE_STRING);
+
+       signals[POP_MESSAGE] = g_signal_new (
+               "pop-message",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               NULL,
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 0);
+
+       signals[PROGRESS] = g_signal_new (
+               "progress",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               NULL,
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1,
+               G_TYPE_INT);
 }
 
 static void
@@ -250,6 +279,7 @@ camel_operation_push_message (GCancellable *cancellable,
 {
        CamelOperation *operation;
        StatusNode *node;
+       gchar *message;
        va_list ap;
 
        if (cancellable == NULL)
@@ -260,14 +290,18 @@ camel_operation_push_message (GCancellable *cancellable,
 
        g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
 
+       va_start (ap, format);
+       message = g_strdup_vprintf (format, ap);
+       va_end (ap);
+
+       g_signal_emit (cancellable, signals[PUSH_MESSAGE], 0, message);
+
        LOCK ();
 
        operation = CAMEL_OPERATION (cancellable);
 
-       va_start (ap, format);
-
        node = status_node_new ();
-       node->message = g_strdup_vprintf (format, ap);
+       node->message = message; /* takes ownership */
        node->operation = g_object_ref (operation);
 
        if (g_queue_is_empty (&operation->priv->status_stack)) {
@@ -289,8 +323,6 @@ camel_operation_push_message (GCancellable *cancellable,
 
        g_queue_push_head (&operation->priv->status_stack, node);
 
-       va_end (ap);
-
        UNLOCK ();
 }
 
@@ -318,6 +350,8 @@ camel_operation_pop_message (GCancellable *cancellable)
 
        g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
 
+       g_signal_emit (cancellable, signals[POP_MESSAGE], 0);
+
        LOCK ();
 
        operation = CAMEL_OPERATION (cancellable);
@@ -377,6 +411,8 @@ camel_operation_progress (GCancellable *cancellable,
 
        g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
 
+       g_signal_emit (cancellable, signals[PROGRESS], 0, percent);
+
        LOCK ();
 
        operation = CAMEL_OPERATION (cancellable);
diff --git a/camel/providers/imapx/camel-imapx-command.c b/camel/providers/imapx/camel-imapx-command.c
index 83fc2d3..0677736 100644
--- a/camel/providers/imapx/camel-imapx-command.c
+++ b/camel/providers/imapx/camel-imapx-command.c
@@ -36,21 +36,11 @@ struct _CamelIMAPXRealCommand {
 
        volatile gint ref_count;
 
-       CamelIMAPXJob *job;
-
        /* For building the part. */
        GString *buffer;
 
-       /* Mailbox to select before running command. */
-       GWeakRef mailbox;
-
        /* For network/parse errors. */
        GError *error;
-
-       /* Used for running some commands synchronously. */
-       GCond done_sync_cond;
-       GMutex done_sync_mutex;
-       gboolean done_sync_flag;
 };
 
 /* Safe to cast to a GQueue. */
@@ -60,8 +50,7 @@ struct _CamelIMAPXCommandQueue {
 
 CamelIMAPXCommand *
 camel_imapx_command_new (CamelIMAPXServer *is,
-                         const gchar *name,
-                         CamelIMAPXMailbox *mailbox,
+                         guint32 job_kind,
                          const gchar *format,
                          ...)
 {
@@ -74,14 +63,13 @@ camel_imapx_command_new (CamelIMAPXServer *is,
        /* Initialize private bits. */
        real_ic->ref_count = 1;
        real_ic->buffer = g_string_sized_new (512);
-       g_weak_ref_init (&real_ic->mailbox, mailbox);
-       g_cond_init (&real_ic->done_sync_cond);
-       g_mutex_init (&real_ic->done_sync_mutex);
 
        /* Initialize public bits. */
        real_ic->public.is = is;
        real_ic->public.tag = tag++;
-       real_ic->public.name = name;
+       real_ic->public.job_kind = job_kind;
+       real_ic->public.status = NULL;
+       real_ic->public.completed = FALSE;
        g_queue_init (&real_ic->public.parts);
 
        if (format != NULL && *format != '\0') {
@@ -141,22 +129,10 @@ camel_imapx_command_unref (CamelIMAPXCommand *ic)
 
                /* Free the private stuff. */
 
-               if (real_ic->job != NULL)
-                       camel_imapx_job_unref (real_ic->job);
-
                g_string_free (real_ic->buffer, TRUE);
 
-               g_weak_ref_clear (&real_ic->mailbox);
-
                g_clear_error (&real_ic->error);
 
-               g_cond_clear (&real_ic->done_sync_cond);
-               g_mutex_clear (&real_ic->done_sync_mutex);
-
-               /* Do NOT try to free the GError.  If set it should have been
-                * propagated to the CamelIMAPXJob, so it's either NULL or the
-                * CamelIMAPXJob owns it now. */
-
                /* Fill the memory with a bit pattern before releasing
                 * it back to the slab allocator, so we can more easily
                 * identify dangling CamelIMAPXCommand pointers. */
@@ -180,64 +156,6 @@ camel_imapx_command_check (CamelIMAPXCommand *ic)
        return (real_ic != NULL && real_ic->ref_count > 0);
 }
 
-gint
-camel_imapx_command_compare (CamelIMAPXCommand *ic1,
-                             CamelIMAPXCommand *ic2)
-{
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic1), 0);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic2), 0);
-
-       if (ic1->pri == ic2->pri)
-               return 0;
-
-       return (ic1->pri < ic2->pri) ? -1 : 1;
-}
-
-CamelIMAPXJob *
-camel_imapx_command_get_job (CamelIMAPXCommand *ic)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       return real_ic->job;
-}
-
-void
-camel_imapx_command_set_job (CamelIMAPXCommand *ic,
-                             CamelIMAPXJob *job)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       if (job != NULL) {
-               g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-               camel_imapx_job_ref (job);
-       }
-
-       if (real_ic->job != NULL)
-               camel_imapx_job_unref (real_ic->job);
-
-       real_ic->job = job;
-}
-
-CamelIMAPXMailbox *
-camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       return g_weak_ref_get (&real_ic->mailbox);
-}
-
 void
 camel_imapx_command_add (CamelIMAPXCommand *ic,
                          const gchar *format,
@@ -280,7 +198,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
 
        g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
 
-       c (ic->is->tagprefix, "adding command, format = '%s'\n", format);
+       c (camel_imapx_server_get_tagprefix (ic->is), "adding command, format = '%s'\n", format);
 
        buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
 
@@ -330,12 +248,12 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
                                break;
                        case 'D': /* datawrapper */
                                D = va_arg (ap, CamelDataWrapper *);
-                               c (ic->is->tagprefix, "got data wrapper '%p'\n", D);
+                               c (camel_imapx_server_get_tagprefix (ic->is), "got data wrapper '%p'\n", D);
                                camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_DATAWRAPPER, D);
                                break;
                        case 'P': /* filename path */
                                P = va_arg (ap, gchar *);
-                               c (ic->is->tagprefix, "got file path '%s'\n", P);
+                               c (camel_imapx_server_get_tagprefix (ic->is), "got file path '%s'\n", P);
                                camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
                                break;
                        case 't': /* token */
@@ -344,7 +262,7 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
                                break;
                        case 's': /* simple string */
                                s = va_arg (ap, gchar *);
-                               c (ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (format, "LOGIN") 
? "***" : s);
+                               c (camel_imapx_server_get_tagprefix (ic->is), "got string '%s'\n", 
g_str_has_prefix (format, "LOGIN") ? "***" : s);
                        output_string:
                                if (s && *s) {
                                        guchar mask = imapx_is_mask (s);
@@ -400,19 +318,19 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
                        case 'u':
                                if (llong == 1) {
                                        l = va_arg (ap, glong);
-                                       c (ic->is->tagprefix, "got glong '%d'\n", (gint) l);
+                                       c (camel_imapx_server_get_tagprefix (ic->is), "got glong '%d'\n", 
(gint) l);
                                        memcpy (literal_format, start, p - start);
                                        literal_format[p - start] = 0;
                                        g_string_append_printf (buffer, literal_format, l);
                                } else if (llong == 2) {
                                        guint64 i64 = va_arg (ap, guint64);
-                                       c (ic->is->tagprefix, "got guint64 '%d'\n", (gint) i64);
+                                       c (camel_imapx_server_get_tagprefix (ic->is), "got guint64 '%d'\n", 
(gint) i64);
                                        memcpy (literal_format, start, p - start);
                                        literal_format[p - start] = 0;
                                        g_string_append_printf (buffer, literal_format, i64);
                                } else {
                                        d = va_arg (ap, gint);
-                                       c (ic->is->tagprefix, "got gint '%d'\n", d);
+                                       c (camel_imapx_server_get_tagprefix (ic->is), "got gint '%d'\n", d);
                                        memcpy (literal_format, start, p - start);
                                        literal_format[p - start] = 0;
                                        g_string_append_printf (buffer, literal_format, d);
@@ -502,7 +420,7 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
        if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
                g_string_append_c (buffer, '{');
                g_string_append_printf (buffer, "%u", ob_size);
-               if (CAMEL_IMAPX_HAVE_CAPABILITY (ic->is->cinfo, LITERALPLUS)) {
+               if (CAMEL_IMAPX_HAVE_CAPABILITY (camel_imapx_server_get_capability_info (ic->is), 
LITERALPLUS)) {
                        g_string_append_c (buffer, '+');
                } else {
                        type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
@@ -533,282 +451,12 @@ camel_imapx_command_close (CamelIMAPXCommand *ic)
        buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
 
        if (buffer->len > 5 && g_ascii_strncasecmp (buffer->str, "LOGIN", 5) == 0) {
-               c (ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", (gint) buffer->len);
+               c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d] 
'LOGIN...'\n", (gint) buffer->len);
        } else {
-               c (ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", (gint) buffer->len, 
(gint) buffer->len, buffer->str);
+               c (camel_imapx_server_get_tagprefix (ic->is), "completing command buffer is [%d] '%.*s'\n", 
(gint) buffer->len, (gint) buffer->len, buffer->str);
        }
        if (buffer->len > 0)
                camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
 
        g_string_set_size (buffer, 0);
 }
-
-void
-camel_imapx_command_wait (CamelIMAPXCommand *ic)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       g_mutex_lock (&real_ic->done_sync_mutex);
-       while (!real_ic->done_sync_flag)
-               g_cond_wait (
-                       &real_ic->done_sync_cond,
-                       &real_ic->done_sync_mutex);
-       g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-void
-camel_imapx_command_done (CamelIMAPXCommand *ic)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       g_mutex_lock (&real_ic->done_sync_mutex);
-       real_ic->done_sync_flag = TRUE;
-       g_cond_broadcast (&real_ic->done_sync_cond);
-       g_mutex_unlock (&real_ic->done_sync_mutex);
-}
-
-/**
- * camel_imapx_command_failed:
- * @ic: a #CamelIMAPXCommand
- * @error: the error which caused the failure
- *
- * Copies @error to be returned in camel_imapx_command_set_error_if_failed().
- * Call this function if a networking or parsing error occurred to force all
- * active IMAP commands to abort processing.
- *
- * Since: 3.10
- **/
-void
-camel_imapx_command_failed (CamelIMAPXCommand *ic,
-                            const GError *error)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-       g_return_if_fail (error != NULL);
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       /* Do not overwrite errors, the first passed in wins */
-       if (real_ic->error != NULL)
-               return;
-
-       real_ic->error = g_error_copy (error);
-}
-
-gboolean
-camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
-                                         GError **error)
-{
-       CamelIMAPXRealCommand *real_ic;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
-       real_ic = (CamelIMAPXRealCommand *) ic;
-
-       /* Check for a networking or parsing error. */
-       if (real_ic->error != NULL) {
-               g_propagate_error (error, real_ic->error);
-               real_ic->error = NULL;
-               return TRUE;
-       }
-
-       /* Check if the IMAP server rejected the command. */
-       if (ic->status != NULL && ic->status->result != IMAPX_OK) {
-
-               /* FIXME Map IMAP response codes to more
-                *       meaningful GError domains/codes.
-                *
-                *       switch (ic->status->condition) {
-                *               case IMAPX_AUTHENTICATIONFAILED:
-                *                      g_set_error (...);
-                *                      break;
-                *               ...
-                *       }
-                */
-
-               if (ic->status->text != NULL)
-                       g_set_error (
-                               error, CAMEL_IMAPX_ERROR, 1,
-                               "%s", ic->status->text);
-               else
-                       g_set_error (
-                               error, CAMEL_IMAPX_ERROR, 1,
-                               "%s", _("Unknown error"));
-               return TRUE;
-       }
-
-       if (real_ic->job)
-               return camel_imapx_job_set_error_if_failed (real_ic->job, error);
-
-       return FALSE;
-}
-
-CamelIMAPXCommandQueue *
-camel_imapx_command_queue_new (void)
-{
-       /* An initialized GQueue is simply zero-filled,
-        * so we can skip calling g_queue_init() here. */
-       return g_slice_new0 (CamelIMAPXCommandQueue);
-}
-
-void
-camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue)
-{
-       CamelIMAPXCommand *ic;
-
-       g_return_if_fail (queue != NULL);
-
-       while ((ic = g_queue_pop_head ((GQueue *) queue)) != NULL)
-               camel_imapx_command_unref (ic);
-
-       g_slice_free (CamelIMAPXCommandQueue, queue);
-}
-
-void
-camel_imapx_command_queue_transfer (CamelIMAPXCommandQueue *from,
-                                    CamelIMAPXCommandQueue *to)
-{
-       GList *link;
-
-       g_return_if_fail (from != NULL);
-       g_return_if_fail (to != NULL);
-
-       while ((link = g_queue_pop_head_link ((GQueue *) from)) != NULL)
-               g_queue_push_tail_link ((GQueue *) to, link);
-}
-
-void
-camel_imapx_command_queue_push_tail (CamelIMAPXCommandQueue *queue,
-                                     CamelIMAPXCommand *ic)
-{
-       g_return_if_fail (queue != NULL);
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
-       camel_imapx_command_ref (ic);
-
-       g_queue_push_tail ((GQueue *) queue, ic);
-}
-
-void
-camel_imapx_command_queue_insert_sorted (CamelIMAPXCommandQueue *queue,
-                                         CamelIMAPXCommand *ic)
-{
-       g_return_if_fail (queue != NULL);
-       g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
-
-       camel_imapx_command_ref (ic);
-
-       g_queue_insert_sorted (
-               (GQueue *) queue, ic, (GCompareDataFunc)
-               camel_imapx_command_compare, NULL);
-}
-
-gboolean
-camel_imapx_command_queue_is_empty (CamelIMAPXCommandQueue *queue)
-{
-       g_return_val_if_fail (queue != NULL, TRUE);
-
-       return g_queue_is_empty ((GQueue *) queue);
-}
-
-guint
-camel_imapx_command_queue_get_length (CamelIMAPXCommandQueue *queue)
-{
-       g_return_val_if_fail (queue != NULL, 0);
-
-       return g_queue_get_length ((GQueue *) queue);
-}
-
-CamelIMAPXCommand *
-camel_imapx_command_queue_peek_head (CamelIMAPXCommandQueue *queue)
-{
-       g_return_val_if_fail (queue != NULL, NULL);
-
-       return g_queue_peek_head ((GQueue *) queue);
-}
-
-GList *
-camel_imapx_command_queue_peek_head_link (CamelIMAPXCommandQueue *queue)
-{
-       g_return_val_if_fail (queue != NULL, NULL);
-
-       return g_queue_peek_head_link ((GQueue *) queue);
-}
-
-gboolean
-camel_imapx_command_queue_remove (CamelIMAPXCommandQueue *queue,
-                                  CamelIMAPXCommand *ic)
-{
-       g_return_val_if_fail (queue != NULL, FALSE);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
-
-       if (g_queue_remove ((GQueue *) queue, ic)) {
-               camel_imapx_command_unref (ic);
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-void
-camel_imapx_command_queue_delete_link (CamelIMAPXCommandQueue *queue,
-                                       GList *link)
-{
-       g_return_if_fail (queue != NULL);
-       g_return_if_fail (link != NULL);
-
-       /* Verify the link is actually in the queue. */
-       if (g_queue_link_index ((GQueue *) queue, link) == -1) {
-               g_warning ("%s: Link not found in queue", G_STRFUNC);
-               return;
-       }
-
-       camel_imapx_command_unref ((CamelIMAPXCommand *) link->data);
-       g_queue_delete_link ((GQueue *) queue, link);
-}
-
-/**
- * camel_imapx_command_queue_ref_by_tag:
- * @queue: a #CamelIMAPXCommandQueue
- * @tag: a #CamelIMAPXCommand tag
- *
- * Returns the #CamelIMAPXCommand in @queue with a matching @tag, or %NULL
- * if no match is found.
- *
- * The returned #CamelIMAPXCommand is referenced for thread-safety and should
- * be unreferenced with camel_imapx_command_unref() when finished with it.
- *
- * Since: 3.10
- **/
-CamelIMAPXCommand *
-camel_imapx_command_queue_ref_by_tag (CamelIMAPXCommandQueue *queue,
-                                      guint32 tag)
-{
-       CamelIMAPXCommand *match = NULL;
-       GList *head, *link;
-
-       g_return_val_if_fail (queue != NULL, NULL);
-
-       head = camel_imapx_command_queue_peek_head_link (queue);
-
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               CamelIMAPXCommand *command = link->data;
-
-               if (command->tag == tag) {
-                       match = camel_imapx_command_ref (command);
-                       break;
-               }
-       }
-
-       return match;
-}
-
diff --git a/camel/providers/imapx/camel-imapx-command.h b/camel/providers/imapx/camel-imapx-command.h
index 36f6e8f..b8e56d4 100644
--- a/camel/providers/imapx/camel-imapx-command.h
+++ b/camel/providers/imapx/camel-imapx-command.h
@@ -18,7 +18,6 @@
 #ifndef CAMEL_IMAPX_COMMAND_H
 #define CAMEL_IMAPX_COMMAND_H
 
-#include "camel-imapx-mailbox.h"
 #include "camel-imapx-utils.h"
 
 #define CAMEL_IS_IMAPX_COMMAND(command) \
@@ -27,7 +26,6 @@
 G_BEGIN_DECLS
 
 /* Avoid a circular reference. */
-struct _CamelIMAPXJob;
 struct _CamelIMAPXServer;
 
 typedef struct _CamelIMAPXCommand CamelIMAPXCommand;
@@ -62,43 +60,33 @@ struct _CamelIMAPXCommandPart {
        gpointer ob;
 };
 
+
+
 struct _CamelIMAPXCommand {
        struct _CamelIMAPXServer *is;
        gint pri;
 
-       /* Command name/type (e.g. FETCH) */
-       const gchar *name;
+       guint32 job_kind; /* CamelIMAPXJobKind */
 
-       /* Status for command, indicates it is complete if != NULL. */
+       /* Status for command. */
        struct _status_info *status;
 
        guint32 tag;
+       gboolean completed;
 
        GQueue parts;
        GList *current_part;
-
-       /* Responsible for free'ing the command. */
-       CamelIMAPXCommandFunc complete;
 };
 
 CamelIMAPXCommand *
                camel_imapx_command_new         (struct _CamelIMAPXServer *is,
-                                                const gchar *name,
-                                                CamelIMAPXMailbox *mailbox,
+                                                guint32 job_kind,
                                                 const gchar *format,
                                                 ...);
 CamelIMAPXCommand *
                camel_imapx_command_ref         (CamelIMAPXCommand *ic);
 void           camel_imapx_command_unref       (CamelIMAPXCommand *ic);
 gboolean       camel_imapx_command_check       (CamelIMAPXCommand *ic);
-gint           camel_imapx_command_compare     (CamelIMAPXCommand *ic1,
-                                                CamelIMAPXCommand *ic2);
-struct _CamelIMAPXJob *
-               camel_imapx_command_get_job     (CamelIMAPXCommand *ic);
-void           camel_imapx_command_set_job     (CamelIMAPXCommand *ic,
-                                                struct _CamelIMAPXJob *job);
-CamelIMAPXMailbox *
-               camel_imapx_command_ref_mailbox (CamelIMAPXCommand *ic);
 void           camel_imapx_command_add         (CamelIMAPXCommand *ic,
                                                 const gchar *format,
                                                 ...);
@@ -109,51 +97,6 @@ void                camel_imapx_command_add_part    (CamelIMAPXCommand *ic,
                                                 CamelIMAPXCommandPartType type,
                                                 gpointer data);
 void           camel_imapx_command_close       (CamelIMAPXCommand *ic);
-void           camel_imapx_command_wait        (CamelIMAPXCommand *ic);
-void           camel_imapx_command_done        (CamelIMAPXCommand *ic);
-void           camel_imapx_command_failed      (CamelIMAPXCommand *ic,
-                                                const GError *error);
-gboolean       camel_imapx_command_set_error_if_failed
-                                               (CamelIMAPXCommand *ic,
-                                                GError **error);
-
-/* These are simple GQueue wrappers for CamelIMAPXCommands.
- * They help make sure reference counting is done properly.
- * Add more wrappers as needed, don't circumvent them. */
-
-typedef struct _CamelIMAPXCommandQueue CamelIMAPXCommandQueue;
-
-CamelIMAPXCommandQueue *
-               camel_imapx_command_queue_new   (void);
-void           camel_imapx_command_queue_free  (CamelIMAPXCommandQueue *queue);
-void           camel_imapx_command_queue_transfer
-                                               (CamelIMAPXCommandQueue *from,
-                                                CamelIMAPXCommandQueue *to);
-void           camel_imapx_command_queue_push_tail
-                                               (CamelIMAPXCommandQueue *queue,
-                                                CamelIMAPXCommand *ic);
-void           camel_imapx_command_queue_insert_sorted
-                                               (CamelIMAPXCommandQueue *queue,
-                                                CamelIMAPXCommand *ic);
-gboolean       camel_imapx_command_queue_is_empty
-                                               (CamelIMAPXCommandQueue *queue);
-guint          camel_imapx_command_queue_get_length
-                                               (CamelIMAPXCommandQueue *queue);
-CamelIMAPXCommand *
-               camel_imapx_command_queue_peek_head
-                                               (CamelIMAPXCommandQueue *queue);
-GList *                camel_imapx_command_queue_peek_head_link
-                                               (CamelIMAPXCommandQueue *queue);
-gboolean       camel_imapx_command_queue_remove
-                                               (CamelIMAPXCommandQueue *queue,
-                                                CamelIMAPXCommand *ic);
-void           camel_imapx_command_queue_delete_link
-                                               (CamelIMAPXCommandQueue *queue,
-                                                GList *link);
-CamelIMAPXCommand *
-               camel_imapx_command_queue_ref_by_tag
-                                               (CamelIMAPXCommandQueue *queue,
-                                                guint32 tag);
 
 G_END_DECLS
 
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c 
b/camel/providers/imapx/camel-imapx-conn-manager.c
index 505cba0..7956443 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -18,7 +18,15 @@
  * Authors: Chenthill Palanisamy <pchenthill novell com>
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
 #include "camel-imapx-conn-manager.h"
+#include "camel-imapx-job.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-store.h"
 #include "camel-imapx-utils.h"
@@ -34,6 +42,9 @@
 #define CON_WRITE_UNLOCK(x) \
        (g_rw_lock_writer_unlock (&(x)->priv->rw_lock))
 
+#define JOB_QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->priv->job_queue_lock)
+#define JOB_QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->job_queue_lock)
+
 #define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
@@ -41,9 +52,7 @@
 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;
+       GList *connections; /* ConnectionInfo * */
        GWeakRef store;
        GRWLock rw_lock;
        guint limit_max_connections;
@@ -52,14 +61,19 @@ struct _CamelIMAPXConnManagerPrivate {
        GSList *pending_connections; /* GCancellable * */
 
        gchar last_tagprefix;
+
+       GRecMutex job_queue_lock;
+       GSList *job_queue; /* CamelIMAPXJob * */
+
+       GMutex busy_connections_lock;
+       GCond busy_connections_cond;
 };
 
 struct _ConnectionInfo {
        GMutex lock;
        CamelIMAPXServer *is;
-       GHashTable *folder_names;
-       gchar *selected_folder;
-       GError *shutdown_error;
+       gboolean busy;
+       gulong refresh_mailbox_handler_id;
        volatile gint ref_count;
 };
 
@@ -68,42 +82,91 @@ enum {
        PROP_STORE
 };
 
+enum {
+       CONNECTION_CREATED,
+       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,
-                    const GError *error,
-                    CamelIMAPXConnManager *con_man);
+
+typedef struct _MailboxRefreshData {
+       CamelIMAPXConnManager *conn_man;
+       CamelIMAPXMailbox *mailbox;
+} MailboxRefreshData;
 
 static void
-imapx_conn_update_select (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox,
-                          CamelIMAPXConnManager *con_man);
+mailbox_refresh_data_free (MailboxRefreshData *data)
+{
+       if (data) {
+               g_clear_object (&data->conn_man);
+               g_clear_object (&data->mailbox);
+               g_free (data);
+       }
+}
+
+static gpointer
+imapx_conn_manager_idle_mailbox_refresh_thread (gpointer user_data)
+{
+       MailboxRefreshData *data = user_data;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (data != NULL, NULL);
+
+       /* passing NULL cancellable means to use only the job's abort cancellable */
+       if (!camel_imapx_conn_manager_refresh_info_sync (data->conn_man, data->mailbox, NULL, &local_error)) {
+               c ('*', "%s: Failed to refresh mailbox '%s': %s\n", G_STRFUNC,
+                       camel_imapx_mailbox_get_name (data->mailbox),
+                       local_error ? local_error->message : "Unknown error");
+       }
+
+       mailbox_refresh_data_free (data);
+       g_clear_error (&local_error);
+
+       return NULL;
+}
+
 static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox,
-                          CamelIMAPXConnManager *con_man);
+imapx_conn_manager_refresh_mailbox_cb (CamelIMAPXServer *is,
+                                      CamelIMAPXMailbox *mailbox,
+                                      CamelIMAPXConnManager *conn_man)
+{
+       MailboxRefreshData *data;
+       GThread *thread;
+       GError *local_error = NULL;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+       g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+       data = g_new0 (MailboxRefreshData, 1);
+       data->conn_man = g_object_ref (conn_man);
+       data->mailbox = g_object_ref (mailbox);
+
+       thread = g_thread_try_new (NULL, imapx_conn_manager_idle_mailbox_refresh_thread, data, &local_error);
+       if (!thread) {
+               g_warning ("%s: Failed to create IDLE mailbox refresh thread: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
+               mailbox_refresh_data_free (data);
+       } else {
+               g_thread_unref (thread);
+       }
+
+       g_clear_error (&local_error);
+}
 
 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->shutdown_error = NULL;
        cinfo->ref_count = 1;
 
        return cinfo;
@@ -127,208 +190,81 @@ connection_info_unref (ConnectionInfo *cinfo)
        g_return_if_fail (cinfo->ref_count > 0);
 
        if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
-               camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
-               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);
+               if (cinfo->refresh_mailbox_handler_id)
+                       g_signal_handler_disconnect (cinfo->is, cinfo->refresh_mailbox_handler_id);
 
                g_mutex_clear (&cinfo->lock);
                g_object_unref (cinfo->is);
-               g_hash_table_destroy (cinfo->folder_names);
-               g_free (cinfo->selected_folder);
-               g_clear_error (&cinfo->shutdown_error);
 
                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);
-       camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
-       connection_info_unref (cinfo);
-}
-
 static gboolean
-connection_info_is_available (ConnectionInfo *cinfo)
+connection_info_get_busy (ConnectionInfo *cinfo)
 {
-       gboolean available;
+       gboolean busy;
 
        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;
+       busy = cinfo->busy;
 
        g_mutex_unlock (&cinfo->lock);
 
-       return available;
+       return busy;
 }
 
 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)
+connection_info_set_busy (ConnectionInfo *cinfo,
+                         gboolean busy)
 {
        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);
+       cinfo->busy = busy;
 
        g_mutex_unlock (&cinfo->lock);
-
-       return selected_folder;
 }
 
 static void
-connection_info_set_selected_folder (ConnectionInfo *cinfo,
-                                     const gchar *selected_folder)
+imapx_conn_manager_signal_busy_connections (CamelIMAPXConnManager *conn_man)
 {
-       g_return_if_fail (cinfo != NULL);
-
-       g_mutex_lock (&cinfo->lock);
-
-       g_free (cinfo->selected_folder);
-       cinfo->selected_folder = g_strdup (selected_folder);
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
 
-       g_mutex_unlock (&cinfo->lock);
+       g_mutex_lock (&conn_man->priv->busy_connections_lock);
+       g_cond_broadcast (&conn_man->priv->busy_connections_cond);
+       g_mutex_unlock (&conn_man->priv->busy_connections_lock);
 }
 
 static void
-connection_info_set_shutdown_error (ConnectionInfo *cinfo,
-                                    const GError *shutdown_error)
+imapx_conn_manager_unmark_busy (CamelIMAPXConnManager *conn_man,
+                               ConnectionInfo *cinfo)
 {
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
        g_return_if_fail (cinfo != NULL);
+       g_return_if_fail (connection_info_get_busy (cinfo));
 
-       g_mutex_lock (&cinfo->lock);
-
-       if (cinfo->shutdown_error != shutdown_error) {
-               g_clear_error (&cinfo->shutdown_error);
-               if (shutdown_error)
-                       cinfo->shutdown_error = g_error_copy (shutdown_error);
-       }
-
-       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;
+       connection_info_set_busy (cinfo, FALSE);
 
-               if (candidate->is == is) {
-                       cinfo = connection_info_ref (candidate);
-                       break;
-               }
-       }
-
-       CON_READ_UNLOCK (con_man);
-
-       return cinfo;
+       imapx_conn_manager_signal_busy_connections (conn_man);
 }
 
 static gboolean
-imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *conn_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 (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
        g_return_val_if_fail (cinfo != NULL, FALSE);
 
-       CON_WRITE_LOCK (con_man);
+       CON_WRITE_LOCK (conn_man);
 
-       list = con_man->priv->connections;
+       list = conn_man->priv->connections;
        link = g_list_find (list, cinfo);
 
        if (link != NULL) {
@@ -337,37 +273,59 @@ imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
                removed = TRUE;
        }
 
-       con_man->priv->connections = list;
+       conn_man->priv->connections = list;
 
-       CON_WRITE_UNLOCK (con_man);
+       CON_WRITE_UNLOCK (conn_man);
+
+       if (removed)
+               imapx_conn_manager_signal_busy_connections (conn_man);
 
        return removed;
 }
 
 static void
-imax_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *con_man)
+imapx_conn_manager_cancel_pending_connections (CamelIMAPXConnManager *conn_man)
 {
        GSList *link;
 
-       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
 
-       g_mutex_lock (&con_man->priv->pending_connections_lock);
-       for (link = con_man->priv->pending_connections; link; link = g_slist_next (link)) {
+       g_mutex_lock (&conn_man->priv->pending_connections_lock);
+       for (link = conn_man->priv->pending_connections; link; link = g_slist_next (link)) {
                GCancellable *cancellable = link->data;
 
                if (cancellable)
                        g_cancellable_cancel (cancellable);
        }
-       g_mutex_unlock (&con_man->priv->pending_connections_lock);
+       g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+}
+
+static void
+imapx_conn_manager_abort_jobs (CamelIMAPXConnManager *conn_man)
+{
+       GSList *link;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+       JOB_QUEUE_LOCK (conn_man);
+
+       for (link = conn_man->priv->job_queue; link; link = g_slist_next (link)) {
+               CamelIMAPXJob *job = link->data;
+
+               if (job)
+                       camel_imapx_job_abort (job);
+       }
+
+       JOB_QUEUE_UNLOCK (conn_man);
 }
 
 static void
-imapx_conn_manager_set_store (CamelIMAPXConnManager *con_man,
+imapx_conn_manager_set_store (CamelIMAPXConnManager *conn_man,
                               CamelStore *store)
 {
        g_return_if_fail (CAMEL_IS_STORE (store));
 
-       g_weak_ref_set (&con_man->priv->store, store);
+       g_weak_ref_set (&conn_man->priv->store, store);
 }
 
 static void
@@ -408,18 +366,19 @@ imapx_conn_manager_get_property (GObject *object,
 static void
 imapx_conn_manager_dispose (GObject *object)
 {
-       CamelIMAPXConnManagerPrivate *priv;
+       CamelIMAPXConnManager *conn_man;
 
-       priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
+       conn_man = CAMEL_IMAPX_CONN_MANAGER (object);
+
+       imapx_conn_manager_cancel_pending_connections (conn_man);
+       imapx_conn_manager_abort_jobs (conn_man);
 
        g_list_free_full (
-               priv->connections,
+               conn_man->priv->connections,
                (GDestroyNotify) connection_info_unref);
-       priv->connections = NULL;
+       conn_man->priv->connections = NULL;
 
-       imax_conn_manager_cancel_pending_connections (CAMEL_IMAPX_CONN_MANAGER (object));
-
-       g_weak_ref_set (&priv->store, NULL);
+       g_weak_ref_set (&conn_man->priv->store, NULL);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->dispose (object);
@@ -433,9 +392,13 @@ imapx_conn_manager_finalize (GObject *object)
        priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
 
        g_warn_if_fail (priv->pending_connections == NULL);
+       g_warn_if_fail (priv->job_queue == NULL);
 
        g_rw_lock_clear (&priv->rw_lock);
+       g_rec_mutex_clear (&priv->job_queue_lock);
        g_mutex_clear (&priv->pending_connections_lock);
+       g_mutex_clear (&priv->busy_connections_lock);
+       g_cond_clear (&priv->busy_connections_cond);
        g_weak_ref_clear (&priv->store);
 
        /* Chain up to parent's finalize() method. */
@@ -461,559 +424,1638 @@ camel_imapx_conn_manager_class_init (CamelIMAPXConnManagerClass *class)
                g_param_spec_object (
                        "store",
                        "Store",
-                       "The CamelStore to which we belong",
-                       CAMEL_TYPE_STORE,
+                       "The CamelIMAPXStore to which we belong",
+                       CAMEL_TYPE_IMAPX_STORE,
                        G_PARAM_READWRITE |
                        G_PARAM_CONSTRUCT_ONLY |
                        G_PARAM_STATIC_STRINGS));
+
+       signals[CONNECTION_CREATED] = g_signal_new (
+               "connection-created",
+               G_OBJECT_CLASS_TYPE (class),
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (CamelIMAPXConnManagerClass, connection_created),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1,
+               CAMEL_TYPE_IMAPX_SERVER);
 }
 
 static void
-camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_init (CamelIMAPXConnManager *conn_man)
 {
-       con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
+       conn_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (conn_man);
 
-       g_rw_lock_init (&con_man->priv->rw_lock);
-       g_mutex_init (&con_man->priv->pending_connections_lock);
-       g_weak_ref_init (&con_man->priv->store, NULL);
+       g_rw_lock_init (&conn_man->priv->rw_lock);
+       g_rec_mutex_init (&conn_man->priv->job_queue_lock);
+       g_mutex_init (&conn_man->priv->pending_connections_lock);
+       g_mutex_init (&conn_man->priv->busy_connections_lock);
+       g_cond_init (&conn_man->priv->busy_connections_cond);
+       g_weak_ref_init (&conn_man->priv->store, NULL);
 
-       con_man->priv->last_tagprefix = 'A' - 1;
+       conn_man->priv->last_tagprefix = 'A' - 1;
 }
 
-static void
-imapx_conn_shutdown (CamelIMAPXServer *is,
-                    const GError *error,
-                     CamelIMAPXConnManager *con_man)
+static gchar
+imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *conn_man)
 {
-       ConnectionInfo *cinfo;
+       gchar adept;
+       gint ii;
+       GList *iter;
 
-       /* Returns a new ConnectionInfo reference. */
-       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+       adept = conn_man->priv->last_tagprefix + 1;
 
-       if (cinfo != NULL) {
-               imapx_conn_manager_remove_info (con_man, cinfo);
-               connection_info_unref (cinfo);
-       }
+       /* the 'Z' is dedicated to auth types query */
+       if (adept >= 'Z')
+               adept = 'A';
+       else if (adept < 'A')
+               adept = 'A';
 
-       /* If one connection ends with this error, then it means all
-          other opened connections also may end with the same error,
-          thus better to kill them all from the list of connections.
-       */
-       if (g_error_matches (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               camel_imapx_conn_manager_close_connections (con_man, error);
+       for (ii = 0; ii < 26; ii++) {
+               for (iter = conn_man->priv->connections; iter; iter = g_list_next (iter)) {
+                       ConnectionInfo *cinfo = iter->data;
+
+                       if (!cinfo || !cinfo->is)
+                               continue;
+
+                       if (camel_imapx_server_get_tagprefix (cinfo->is) == adept)
+                               break;
+               }
+
+               /* Read all current active connections and none has the same tag prefix */
+               if (!iter)
+                       break;
+
+               adept++;
+               if (adept >= 'Z')
+                       adept = 'A';
        }
+
+       g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+
+       conn_man->priv->last_tagprefix = adept;
+
+       return adept;
 }
 
-static void
-imapx_conn_update_select (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox,
-                          CamelIMAPXConnManager *con_man)
+static ConnectionInfo *
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *conn_man,
+                                      CamelIMAPXMailbox *mailbox,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       ConnectionInfo *cinfo;
-       gchar *old_selected_folder, *selected_folder = NULL;
+       CamelIMAPXServer *is = NULL;
+       CamelIMAPXStore *imapx_store;
+       ConnectionInfo *cinfo = NULL;
+       gboolean success;
 
-       /* Returns a new ConnectionInfo reference. */
-       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+       /* Caller must be holding CON_WRITE_LOCK. */
 
-       if (cinfo == NULL)
-               return;
+       /* Check if we got cancelled while we were waiting. */
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return NULL;
 
-       old_selected_folder = connection_info_dup_selected_folder (cinfo);
+       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+       g_return_val_if_fail (imapx_store != NULL, NULL);
 
-       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);
-               }
+       is = camel_imapx_server_new (imapx_store);
+       camel_imapx_server_set_tagprefix (is, imapx_conn_manager_get_next_free_tagprefix_unlocked (conn_man));
 
-               g_free (old_selected_folder);
-       }
+       g_signal_emit (conn_man, signals[CONNECTION_CREATED], 0, is);
+
+       /* 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, conn_man->priv->connections != NULL);
+       success = camel_imapx_server_connect_sync (is, cancellable, error);
+       camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
+
+       if (!success)
+               goto exit;
+
+       cinfo = connection_info_new (is);
+
+       cinfo->refresh_mailbox_handler_id = g_signal_connect (
+               is, "refresh-mailbox", G_CALLBACK (imapx_conn_manager_refresh_mailbox_cb), conn_man);
+
+       /* Takes ownership of the ConnectionInfo. */
+       conn_man->priv->connections = g_list_append (conn_man->priv->connections, cinfo);
+
+       c (camel_imapx_server_get_tagprefix (is), "Created new connection %p (server:%p) for %s; total 
connections %d\n",
+               cinfo, cinfo->is,
+               mailbox ? camel_imapx_mailbox_get_name (mailbox) : "[null]",
+               g_list_length (conn_man->priv->connections));
 
-       if (mailbox)
-               selected_folder = camel_imapx_mailbox_dup_folder_path (mailbox);
-       connection_info_set_selected_folder (cinfo, selected_folder);
-       g_free (selected_folder);
+exit:
+       g_object_unref (imapx_store);
+       g_clear_object (&is);
 
-       connection_info_unref (cinfo);
+       return cinfo;
+}
+
+static gint
+imapx_conn_manager_get_max_connections (CamelIMAPXConnManager *conn_man)
+{
+       CamelIMAPXStore *imapx_store;
+       CamelSettings *settings;
+       gint max_connections;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), -1);
+
+       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+       if (!imapx_store)
+               return -1;
+
+       settings = camel_service_ref_settings (CAMEL_SERVICE (imapx_store));
+
+       max_connections = camel_imapx_settings_get_concurrent_connections (CAMEL_IMAPX_SETTINGS (settings));
+
+       if (conn_man->priv->limit_max_connections > 0 &&
+           conn_man->priv->limit_max_connections < max_connections)
+               max_connections = conn_man->priv->limit_max_connections;
+
+       g_object_unref (settings);
+       g_object_unref (imapx_store);
+
+       return max_connections > 0 ? max_connections : 1;
 }
 
 static void
-imapx_conn_mailbox_closed (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox,
-                          CamelIMAPXConnManager *con_man)
+imapx_conn_manager_connection_wait_cancelled_cb (GCancellable *cancellable,
+                                                CamelIMAPXConnManager *conn_man)
 {
-       imapx_conn_update_select (is, NULL, con_man);
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+       imapx_conn_manager_signal_busy_connections (conn_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)
+static ConnectionInfo *
+camel_imapx_conn_manager_ref_connection (CamelIMAPXConnManager *conn_man,
+                                        CamelIMAPXMailbox *mailbox,
+                                        gboolean mark_as_busy,
+                                        GCancellable *cancellable,
+                                        GError **error)
 {
-       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;
+       CamelIMAPXStore *imapx_store;
+       CamelSession *session;
+       GError *local_error = NULL;
 
-       /* Caller must be holding CON_WRITE_LOCK. */
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
 
-       store = camel_imapx_conn_manager_ref_store (con_man);
-       g_return_val_if_fail (store != NULL, NULL);
+       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+       if (!imapx_store)
+               return NULL;
 
-       settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+       session = camel_service_ref_session (CAMEL_SERVICE (imapx_store));
 
-       concurrent_connections =
-               camel_imapx_settings_get_concurrent_connections (
-               CAMEL_IMAPX_SETTINGS (settings));
+       if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (imapx_store)) &&
+           camel_session_get_online (session)) {
 
-       if (con_man->priv->limit_max_connections > 0 &&
-           con_man->priv->limit_max_connections < concurrent_connections)
-               concurrent_connections = con_man->priv->limit_max_connections;
+               g_mutex_lock (&conn_man->priv->pending_connections_lock);
+               if (cancellable) {
+                       g_object_ref (cancellable);
+               } else {
+                       cancellable = g_cancellable_new ();
+               }
+               conn_man->priv->pending_connections = g_slist_prepend (conn_man->priv->pending_connections, 
cancellable);
+               g_mutex_unlock (&conn_man->priv->pending_connections_lock);
 
-       g_object_unref (settings);
+               /* Hold the writer lock while we requisition a CamelIMAPXServer
+                * to prevent other threads from adding or removing connections. */
+               CON_READ_LOCK (conn_man);
 
-       /* XXX Have a dedicated connection for INBOX ? */
+               /* Check if we've got cancelled while waiting for the lock. */
+               while (!cinfo && !g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+                       gint opened_connections, max_connections;
+                       GList *link;
 
-       opened_connections = g_list_length (con_man->priv->connections);
-       list = con_man->priv->connections;
+                       for (link = conn_man->priv->connections; link; link = g_list_next (link)) {
+                               ConnectionInfo *candidate = link->data;
 
-       /* If a folder was not given, find the least-busy connection. */
-       if (folder_name == NULL) {
-               goto least_busy;
-       }
+                               if (candidate && !connection_info_get_busy (candidate)) {
+                                       cinfo = connection_info_ref (candidate);
+                                       break;
+                               }
+                       }
 
-       /* 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 (cinfo)
+                               break;
 
-               if (camel_imapx_server_has_expensive_command (candidate->is))
-                       expensive_connections++;
+                       opened_connections = g_list_length (conn_man->priv->connections);
+                       max_connections = imapx_conn_manager_get_max_connections (conn_man);
+
+                       if (max_connections <= 0)
+                               break;
+
+                       if (!cinfo && opened_connections < max_connections) {
+                               GError *local_error_2 = NULL;
+
+                               CON_READ_UNLOCK (conn_man);
+                               CON_WRITE_LOCK (conn_man);
+                               cinfo = imapx_create_new_connection_unlocked (conn_man, mailbox, cancellable, 
&local_error_2);
+                               CON_WRITE_UNLOCK (conn_man);
+                               CON_READ_LOCK (conn_man);
+
+                               if (!cinfo) {
+                                       gboolean limit_connections =
+                                               g_error_matches (local_error_2, CAMEL_IMAPX_SERVER_ERROR,
+                                               CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
+                                               conn_man->priv->connections;
+
+                                       c ('*', "Failed to open a new connection, while having %d opened, 
with error: %s; will limit connections: %s\n",
+                                               g_list_length (conn_man->priv->connections),
+                                               local_error_2 ? local_error_2->message : "Unknown error",
+                                               limit_connections ? "yes" : "no");
+
+                                       if (limit_connections) {
+                                               /* limit to one-less than current connection count - be nice 
to the server */
+                                               conn_man->priv->limit_max_connections = g_list_length 
(conn_man->priv->connections) - 1;
+                                               if (!conn_man->priv->limit_max_connections)
+                                                       conn_man->priv->limit_max_connections = 1;
+
+                                               g_clear_error (&local_error_2);
+                                       } else {
+                                               if (local_error_2)
+                                                       g_propagate_error (&local_error, local_error_2);
+                                               break;
+                                       }
+                               } else {
+                                       connection_info_ref (cinfo);
+                               }
+                       }
 
-               if (connection_info_has_folder_name (candidate, folder_name) && 
camel_imapx_server_is_connected (candidate->is) &&
-                   (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 (!cinfo) {
+                               gulong handler_id;
 
-                               if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) < 
camel_imapx_server_get_command_count (candidate->is))
-                                       continue;
+                               CON_READ_UNLOCK (conn_man);
 
-                               connection_info_unref (cinfo);
+                               handler_id = g_cancellable_connect (cancellable, G_CALLBACK 
(imapx_conn_manager_connection_wait_cancelled_cb), conn_man, NULL);
+
+                               g_mutex_lock (&conn_man->priv->busy_connections_lock);
+                               g_cond_wait (&conn_man->priv->busy_connections_cond, 
&conn_man->priv->busy_connections_lock);
+                               g_mutex_unlock (&conn_man->priv->busy_connections_lock);
+
+                               if (handler_id)
+                                       g_cancellable_disconnect (cancellable, handler_id);
+
+                               CON_READ_LOCK (conn_man);
                        }
+               }
+
+               if (cinfo && mark_as_busy)
+                       connection_info_set_busy (cinfo, TRUE);
+
+               CON_READ_UNLOCK (conn_man);
 
-                       cinfo = connection_info_ref (candidate);
-                       if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
-                               goto exit;
+               g_mutex_lock (&conn_man->priv->pending_connections_lock);
+               conn_man->priv->pending_connections = g_slist_remove (conn_man->priv->pending_connections, 
cancellable);
+               g_object_unref (cancellable);
+               g_mutex_unlock (&conn_man->priv->pending_connections_lock);
+       }
+
+       g_clear_object (&imapx_store);
+       g_clear_object (&session);
+
+       if (!cinfo && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
+               if (local_error) {
+                       g_set_error (
+                               error, CAMEL_SERVICE_ERROR,
+                               CAMEL_SERVICE_ERROR_UNAVAILABLE,
+                               _("You must be working online to complete this operation (%s)"),
+                               local_error->message);
+
+                       g_clear_error (&local_error);
+               } else {
+                       g_set_error (
+                               &local_error, CAMEL_SERVICE_ERROR,
+                               CAMEL_SERVICE_ERROR_UNAVAILABLE,
+                               _("You must be working online to complete this operation"));
                }
        }
 
- 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;
+       if (local_error)
+               g_propagate_error (error, local_error);
 
-               /* cinfo here doesn't have any expensive command, thus ignore it */
-               if (cinfo) {
-                       connection_info_unref (cinfo);
-                       cinfo = NULL;
-               }
+       return cinfo;
+}
 
-               /* 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_is_connected (candidate->is) ||
-                           !camel_imapx_server_has_expensive_command (candidate->is))
-                               continue;
+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);
+}
 
-                       jobs = camel_imapx_server_get_command_count (candidate->is);
+CamelIMAPXStore *
+camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *conn_man)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
 
-                       if (cinfo == NULL) {
-                               cinfo = connection_info_ref (candidate);
-                               min_jobs = jobs;
+       return g_weak_ref_get (&conn_man->priv->store);
+}
 
-                       } else if (jobs < min_jobs) {
-                               connection_info_unref (cinfo);
-                               cinfo = connection_info_ref (candidate);
-                               min_jobs = jobs;
-                       }
-               }
+gboolean
+camel_imapx_conn_manager_connect_sync (CamelIMAPXConnManager *conn_man,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       ConnectionInfo *cinfo;
 
-               if (cinfo)
-                       goto exit;
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       CON_READ_LOCK (conn_man);
+       if (conn_man->priv->connections) {
+               CON_READ_UNLOCK (conn_man);
+               return TRUE;
        }
+       CON_READ_UNLOCK (conn_man);
 
-       /* Next try to find a connection not handling any folders. */
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ConnectionInfo *candidate = link->data;
+       cinfo = camel_imapx_conn_manager_ref_connection (conn_man, NULL, FALSE, cancellable, error);
+       if (cinfo) {
+               connection_info_unref (cinfo);
+       }
 
-               if (camel_imapx_server_is_connected (candidate->is) &&
-                   connection_info_is_available (candidate)) {
-                       if (cinfo)
-                               connection_info_unref (cinfo);
-                       cinfo = connection_info_ref (candidate);
-                       goto exit;
+       return cinfo != NULL;
+}
+
+gboolean
+camel_imapx_conn_manager_disconnect_sync (CamelIMAPXConnManager *conn_man,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       GList *link, *connections;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
+
+       /* Do this before acquiring the write lock, because any pending
+          connection holds the write lock, thus makes this request starve. */
+       imapx_conn_manager_cancel_pending_connections (conn_man);
+       imapx_conn_manager_abort_jobs (conn_man);
+
+       CON_WRITE_LOCK (conn_man);
+
+       c ('*', "Disconnecting all %d connections\n", g_list_length (conn_man->priv->connections));
+
+       connections = conn_man->priv->connections;
+       conn_man->priv->connections = NULL;
+
+       CON_WRITE_UNLOCK (conn_man);
+
+       for (link = connections; link; link = g_list_next (link)) {
+               ConnectionInfo *cinfo = link->data;
+               GError *local_error = NULL;
+
+               if (!cinfo)
+                       continue;
+
+               if (!camel_imapx_server_disconnect_sync (cinfo->is, cancellable, &local_error)) {
+                       c (camel_imapx_server_get_tagprefix (cinfo->is), "   Failed to disconnect from the 
server: %s\n",
+                               local_error ? local_error->message : "Unknown error");
                }
+
+               connection_info_unref (cinfo);
+               g_clear_error (&local_error);
        }
 
-       /* 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);
+       g_list_free (connections);
+
+       return TRUE;
+}
+
+gboolean
+camel_imapx_conn_manager_run_job_sync (CamelIMAPXConnManager *conn_man,
+                                      CamelIMAPXJob *job,
+                                      CamelIMAPXJobMatchesFunc finish_before_job,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       GSList *link;
+       ConnectionInfo *cinfo;
+       gboolean success = FALSE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+       g_return_val_if_fail (job != NULL, FALSE);
+
+       JOB_QUEUE_LOCK (conn_man);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               JOB_QUEUE_UNLOCK (conn_man);
+               return FALSE;
        }
 
-       /* 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;
+       link = conn_man->priv->job_queue;
+       while (link) {
+               CamelIMAPXJob *queued_job = link->data;
+               gboolean matches;
 
-               if (!camel_imapx_server_is_connected (candidate->is))
+               g_warn_if_fail (queued_job != NULL);
+               g_warn_if_fail (queued_job != job);
+
+               if (!queued_job) {
+                       link = g_slist_next (link);
                        continue;
+               }
 
-               n_commands = camel_imapx_server_get_command_count (candidate->is);
+               matches = camel_imapx_job_matches (job, queued_job);
+               if (matches || (finish_before_job && finish_before_job (job, queued_job))) {
+                       camel_imapx_job_ref (queued_job);
 
-               if (cinfo == NULL) {
-                       cinfo = connection_info_ref (candidate);
-                       min_jobs = n_commands;
+                       JOB_QUEUE_UNLOCK (conn_man);
 
-               } else if (n_commands < min_jobs) {
-                       connection_info_unref (cinfo);
-                       cinfo = connection_info_ref (candidate);
-                       min_jobs = n_commands;
+                       camel_imapx_job_wait_sync (queued_job, cancellable);
+
+                       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+                               camel_imapx_job_unref (queued_job);
+                               return FALSE;
+                       }
+
+                       if (matches) {
+                               gpointer result = NULL;
+                               GDestroyNotify destroy_result = NULL;
+
+                               if (camel_imapx_job_copy_result (queued_job, &success, &result, &local_error, 
&destroy_result)) {
+                                       camel_imapx_job_set_result (job, success, result, local_error, 
destroy_result);
+                                       camel_imapx_job_unref (queued_job);
+
+                                       if (local_error)
+                                               g_propagate_error (error, local_error);
+
+                                       return success;
+                               }
+                       }
+
+                       JOB_QUEUE_LOCK (conn_man);
+
+                       camel_imapx_job_unref (queued_job);
+
+                       /* The queue could change, start from the beginning. */
+                       link = conn_man->priv->job_queue;
+               } else {
+                       link = g_slist_next (link);
                }
        }
 
-exit:
-       if (cinfo != NULL && folder_name != NULL)
-               connection_info_insert_folder_name (cinfo, folder_name);
+       conn_man->priv->job_queue = g_slist_prepend (conn_man->priv->job_queue, job);
+
+       JOB_QUEUE_UNLOCK (conn_man);
+
+       do {
+               g_clear_error (&local_error);
+
+               cinfo = camel_imapx_conn_manager_ref_connection (conn_man, camel_imapx_job_get_mailbox (job), 
TRUE, cancellable, error);
+               if (cinfo) {
+                       success = camel_imapx_server_stop_idle_sync (cinfo->is, cancellable, &local_error);
+
+                       if (success)
+                               success = camel_imapx_job_run_sync (job, cinfo->is, cancellable, 
&local_error);
+
+                       if (success) {
+                               CamelIMAPXMailbox *idle_mailbox = NULL;
+                               gboolean is_first_connection;
+
+                               CON_READ_LOCK (conn_man);
+                               is_first_connection = conn_man->priv->connections && 
conn_man->priv->connections->data == cinfo;
+                               CON_READ_UNLOCK (conn_man);
+
+                               if (is_first_connection) {
+                                       CamelIMAPXStore *imapx_store;
+
+                                       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
+                                       idle_mailbox = imapx_store ? camel_imapx_store_ref_mailbox 
(imapx_store, "INBOX") : NULL;
+
+                                       g_clear_object (&imapx_store);
+                               }
 
-       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;
+                               camel_imapx_server_schedule_idle_sync (cinfo->is, idle_mailbox, cancellable, 
NULL);
 
-                       printf ("   cmds:%d has-expensive:%d avail:%d cinfo:%p server:%p\n", 
camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command 
(candidate->is), connection_info_is_available (candidate), candidate, candidate->is);
+                               g_clear_object (&idle_mailbox);
+
+                               imapx_conn_manager_unmark_busy (conn_man, cinfo);
+                       } else if (local_error && (local_error->domain == G_IO_ERROR || local_error->domain 
== G_TLS_ERROR || local_error->domain == CAMEL_IMAPX_ERROR ||
+                                  g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) &&
+                                  !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
+                               c (camel_imapx_server_get_tagprefix (cinfo->is), "Removed connection %p 
(server:%p) due to error: %s\n",
+                                       cinfo, cinfo->is, local_error ? local_error->message : "Unknown 
error");
+
+                               camel_imapx_server_disconnect_sync (cinfo->is, cancellable, NULL);
+                               imapx_conn_manager_remove_info (conn_man, cinfo);
+
+                               if (!local_error || local_error->domain == CAMEL_IMAPX_ERROR ||
+                                   g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_MISC)) {
+                                       GError *tmp = local_error;
+
+                                       local_error = NULL;
+
+                                       /* This message won't get into UI. */
+                                       g_set_error (&local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+                                               "Reconnect after failure: %s", tmp ? tmp->message : "Unknown 
error");
+
+                                       g_clear_error (&tmp);
+                               }
+                       } else {
+                               imapx_conn_manager_unmark_busy (conn_man, cinfo);
+                       }
+
+                       connection_info_unref (cinfo);
                }
-       }
+       } while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT));
 
-       if (cinfo != NULL) {
-               is = g_object_ref (cinfo->is);
-               connection_info_unref (cinfo);
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       JOB_QUEUE_LOCK (conn_man);
+       conn_man->priv->job_queue = g_slist_remove (conn_man->priv->job_queue, job);
+       JOB_QUEUE_UNLOCK (conn_man);
+
+       camel_imapx_job_done (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_nothing_matches (CamelIMAPXJob *job,
+                                   CamelIMAPXJob *other_job)
+{
+       /* For jobs where none can match. */
+       return FALSE;
+}
+
+static gboolean
+imapx_conn_manager_matches_sync_changes_or_refresh_info (CamelIMAPXJob *job,
+                                                        CamelIMAPXJob *other_job)
+{
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (other_job != NULL, FALSE);
+       g_return_val_if_fail (job != other_job, FALSE);
+
+       if (camel_imapx_job_get_mailbox (job) != camel_imapx_job_get_mailbox (other_job))
+               return FALSE;
+
+       return camel_imapx_job_get_kind (other_job) == CAMEL_IMAPX_JOB_SYNC_CHANGES ||
+               camel_imapx_job_get_kind (other_job) == CAMEL_IMAPX_JOB_REFRESH_INFO;
+}
+
+struct ListJobData {
+       gchar *pattern;
+       CamelStoreGetFolderInfoFlags flags;
+};
+
+static void
+list_job_data_free (gpointer ptr)
+{
+       struct ListJobData *job_data = ptr;
+
+       if (job_data) {
+               g_free (job_data->pattern);
+               g_free (job_data);
        }
+}
 
-       g_object_unref (store);
+static gboolean
+imapx_conn_manager_list_run_sync (CamelIMAPXJob *job,
+                                 CamelIMAPXServer *server,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       struct ListJobData *job_data;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
 
-       return is;
+       return camel_imapx_server_list_sync (server, job_data->pattern, job_data->flags, cancellable, error);
 }
 
-static gchar
-imapx_conn_manager_get_next_free_tagprefix_unlocked (CamelIMAPXConnManager *con_man)
+static gboolean
+imapx_conn_manager_list_matches (CamelIMAPXJob *job,
+                                CamelIMAPXJob *other_job)
 {
-       gchar adept;
-       gint ii;
-       GList *iter;
+       struct ListJobData *job_data, *other_job_data;
 
-       adept = con_man->priv->last_tagprefix + 1;
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (other_job != NULL, FALSE);
 
-       /* the 'Z' is dedicated to auth types query */
-       if (adept >= 'Z')
-               adept = 'A';
-       else if (adept < 'A')
-               adept = 'A';
+       if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_LIST ||
+           camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+               return FALSE;
 
-       for (ii = 0; ii < 26; ii++) {
-               for (iter = con_man->priv->connections; iter; iter = g_list_next (iter)) {
-                       ConnectionInfo *cinfo = iter->data;
+       job_data = camel_imapx_job_get_user_data (job);
+       other_job_data = camel_imapx_job_get_user_data (other_job);
 
-                       if (!cinfo || !cinfo->is)
-                               continue;
+       if (!job_data || !other_job_data)
+               return FALSE;
 
-                       if (cinfo->is->tagprefix == adept)
-                               break;
-               }
+       return job_data->flags == other_job_data->flags &&
+              g_strcmp0 (job_data->pattern, other_job_data->pattern) == 0;
+}
 
-               /* Read all current active connections and none has the same tag prefix */
-               if (!iter)
-                       break;
+gboolean
+camel_imapx_conn_manager_list_sync (CamelIMAPXConnManager *conn_man,
+                                   const gchar *pattern,
+                                   CamelStoreGetFolderInfoFlags flags,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+       CamelIMAPXJob *job;
+       struct ListJobData *job_data;
+       gboolean success = FALSE;
 
-               adept++;
-               if (adept >= 'Z')
-                       adept = 'A';
-       }
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
 
-       g_return_val_if_fail (adept >= 'A' && adept < 'Z', 'Z');
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_LIST, NULL,
+               imapx_conn_manager_list_run_sync,
+               imapx_conn_manager_list_matches,
+               NULL);
 
-       con_man->priv->last_tagprefix = adept;
+       job_data = g_new0 (struct ListJobData, 1);
+       job_data->pattern = g_strdup (pattern);
+       job_data->flags = flags;
 
-       return adept;
+       camel_imapx_job_set_user_data (job, job_data, list_job_data_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+       if (success)
+               camel_imapx_job_copy_result (job, &success, NULL, error, NULL);
+
+       camel_imapx_job_unref (job);
+
+       return success;
 }
 
-static CamelIMAPXServer *
-imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
-                                      const gchar *folder_name,
-                                      GCancellable *cancellable,
-                                      GError **error)
+static gboolean
+imapx_conn_manager_refresh_info_run_sync (CamelIMAPXJob *job,
+                                         CamelIMAPXServer *server,
+                                         GCancellable *cancellable,
+                                         GError **error)
 {
-       CamelStore *store;
-       CamelIMAPXServer *is = NULL;
-       CamelIMAPXStore *imapx_store;
-       ConnectionInfo *cinfo = NULL;
+       CamelIMAPXMailbox *mailbox;
        gboolean success;
+       GError *local_error = NULL;
 
-       /* Caller must be holding CON_WRITE_LOCK. */
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
 
-       /* Check if we got cancelled while we were waiting. */
-       if (g_cancellable_set_error_if_cancelled (cancellable, error))
-               return NULL;
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       store = camel_imapx_conn_manager_ref_store (con_man);
-       g_return_val_if_fail (store != NULL, NULL);
+       success = camel_imapx_server_refresh_info_sync (server, mailbox, cancellable, &local_error);
 
-       imapx_store = CAMEL_IMAPX_STORE (store);
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
 
-       is = camel_imapx_server_new (imapx_store);
-       is->tagprefix = imapx_conn_manager_get_next_free_tagprefix_unlocked (con_man);
+       if (local_error)
+               g_propagate_error (error, local_error);
 
-       /* 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, con_man->priv->connections != NULL);
-       success = camel_imapx_server_connect (is, cancellable, error);
-       camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
+       return success;
+}
 
-       if (!success) {
-               g_clear_object (&is);
-               goto exit;
-       }
+gboolean
+camel_imapx_conn_manager_refresh_info_sync (CamelIMAPXConnManager *conn_man,
+                                           CamelIMAPXMailbox *mailbox,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
 
-       g_signal_connect (
-               is, "shutdown",
-               G_CALLBACK (imapx_conn_shutdown), con_man);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
 
-       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);
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_REFRESH_INFO, mailbox,
+               imapx_conn_manager_refresh_info_run_sync, NULL, NULL);
 
-       cinfo = connection_info_new (is);
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+               imapx_conn_manager_matches_sync_changes_or_refresh_info,
+               cancellable, error);
 
-       if (folder_name != NULL)
-               connection_info_insert_folder_name (cinfo, folder_name);
+       camel_imapx_job_unref (job);
 
-       /* Takes ownership of the ConnectionInfo. */
-       con_man->priv->connections = g_list_prepend (
-               con_man->priv->connections, cinfo);
+       return success;
+}
 
-       c (is->tagprefix, "Created new connection %p (server:%p) for %s; total connections %d\n", cinfo, 
cinfo->is, folder_name, g_list_length (con_man->priv->connections));
+static gboolean
+imapx_conn_manager_sync_changes_run_sync (CamelIMAPXJob *job,
+                                         CamelIMAPXServer *server,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
 
-exit:
-       g_object_unref (store);
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       success = camel_imapx_server_sync_changes_sync (server, mailbox, cancellable, &local_error);
 
-       return is;
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
 }
 
-/****************************/
+gboolean
+camel_imapx_conn_manager_sync_changes_sync (CamelIMAPXConnManager *conn_man,
+                                           CamelIMAPXMailbox *mailbox,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
 
-CamelIMAPXConnManager *
-camel_imapx_conn_manager_new (CamelStore *store)
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_CHANGES, mailbox,
+               imapx_conn_manager_sync_changes_run_sync, NULL, NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job,
+               imapx_conn_manager_matches_sync_changes_or_refresh_info,
+               cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_expunge_run_sync (CamelIMAPXJob *job,
+                                    CamelIMAPXServer *server,
+                                    GCancellable *cancellable,
+                                    GError **error)
 {
-       g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
 
-       return g_object_new (
-               CAMEL_TYPE_IMAPX_CONN_MANAGER, "store", store, NULL);
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       success = camel_imapx_server_expunge_sync (server, mailbox, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_expunge_sync (CamelIMAPXConnManager *conn_man,
+                                      CamelIMAPXMailbox *mailbox,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_EXPUNGE, mailbox,
+               imapx_conn_manager_expunge_run_sync, NULL, NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
 }
 
-CamelStore *
-camel_imapx_conn_manager_ref_store (CamelIMAPXConnManager *con_man)
+struct GetMessageJobData {
+       CamelFolderSummary *summary;
+       CamelDataCache *message_cache;
+       gchar *message_uid;
+};
+
+static void
+get_message_job_data_free (gpointer ptr)
 {
-       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+       struct GetMessageJobData *job_data = ptr;
 
-       return g_weak_ref_get (&con_man->priv->store);
+       if (job_data) {
+               g_clear_object (&job_data->summary);
+               g_clear_object (&job_data->message_cache);
+               g_free (job_data->message_uid);
+               g_free (job_data);
+       }
 }
 
-CamelIMAPXServer *
-camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
-                                         const gchar *folder_name,
-                                        gboolean for_expensive_job,
-                                         GCancellable *cancellable,
-                                         GError **error)
+static gboolean
+imapx_conn_manager_get_message_run_sync (CamelIMAPXJob *job,
+                                        CamelIMAPXServer *server,
+                                        GCancellable *cancellable,
+                                        GError **error)
 {
-       CamelIMAPXServer *is = NULL;
+       struct GetMessageJobData *job_data;
+       CamelIMAPXMailbox *mailbox;
+       CamelStream *result;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+       g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+       g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+       result = camel_imapx_server_get_message_sync (
+               server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+               cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, result != NULL, result, local_error, result ? g_object_unref : NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return result != NULL;
+}
+
+static gboolean
+imapx_conn_manager_get_message_matches (CamelIMAPXJob *job,
+                                       CamelIMAPXJob *other_job)
+{
+       struct GetMessageJobData *job_data, *other_job_data;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (other_job != NULL, FALSE);
+
+       if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_GET_MESSAGE ||
+           camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+               return FALSE;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+       job_data = camel_imapx_job_get_user_data (job);
+       other_job_data = camel_imapx_job_get_user_data (other_job);
 
-       g_mutex_lock (&con_man->priv->pending_connections_lock);
-       if (cancellable) {
-               g_object_ref (cancellable);
+       if (!job_data || !other_job_data)
+               return FALSE;
+
+       return g_strcmp0 (job_data->message_uid, other_job_data->message_uid) == 0;
+}
+
+static void
+imapx_conn_manager_get_message_copy_result (CamelIMAPXJob *job,
+                                           gconstpointer set_result,
+                                           gpointer *out_result)
+{
+       if (!set_result || !*out_result)
+               return;
+
+       *out_result = g_object_ref ((gpointer) set_result);
+}
+
+CamelStream *
+camel_imapx_conn_manager_get_message_sync (CamelIMAPXConnManager *conn_man,
+                                          CamelIMAPXMailbox *mailbox,
+                                          CamelFolderSummary *summary,
+                                          CamelDataCache *message_cache,
+                                          const gchar *message_uid,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+       CamelIMAPXJob *job;
+       struct GetMessageJobData *job_data;
+       CamelStream *result;
+       gpointer result_data = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_GET_MESSAGE, mailbox,
+               imapx_conn_manager_get_message_run_sync,
+               imapx_conn_manager_get_message_matches,
+               imapx_conn_manager_get_message_copy_result);
+
+       job_data = g_new0 (struct GetMessageJobData, 1);
+       job_data->summary = g_object_ref (summary);
+       job_data->message_cache = g_object_ref (message_cache);
+       job_data->message_uid = g_strdup (message_uid);
+
+       camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
+
+       if (camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error) &&
+           camel_imapx_job_take_result_data (job, &result_data)) {
+               result = result_data;
        } else {
-               cancellable = g_cancellable_new ();
+               result = NULL;
        }
-       con_man->priv->pending_connections = g_slist_prepend (con_man->priv->pending_connections, 
cancellable);
-       g_mutex_unlock (&con_man->priv->pending_connections_lock);
-
-       /* 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've 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) {
-                       GError *local_error = NULL;
-
-                       is = imapx_create_new_connection_unlocked (con_man, folder_name, cancellable, 
&local_error);
-
-                       if (!is) {
-                               gboolean limit_connections =
-                                       g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
-                                       CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
-                                       con_man->priv->connections;
-
-                               c ('*', "Failed to open a new connection, while having %d opened, with error: 
%s; will limit connections: %s\n",
-                                       g_list_length (con_man->priv->connections),
-                                       local_error ? local_error->message : "Unknown error",
-                                       limit_connections ? "yes" : "no");
-
-                               if (limit_connections) {
-                                       /* limit to one-less than current connection count - be nice to the 
server */
-                                       con_man->priv->limit_max_connections = g_list_length 
(con_man->priv->connections) - 1;
-                                       if (!con_man->priv->limit_max_connections)
-                                               con_man->priv->limit_max_connections = 1;
-
-                                       g_clear_error (&local_error);
-                                       is = imapx_find_connection_unlocked (con_man, folder_name, 
for_expensive_job);
-                               } else if (local_error) {
-                                       g_propagate_error (error, local_error);
-                               }
-                       }
-               }
+
+       camel_imapx_job_unref (job);
+
+       return result;
+}
+
+struct CopyMessageJobData {
+       CamelIMAPXMailbox *destination;
+       GPtrArray *uids;
+       gboolean delete_originals;
+       gboolean remove_deleted_flags;
+};
+
+static void
+copy_message_job_data_free (gpointer ptr)
+{
+       struct CopyMessageJobData *job_data = ptr;
+
+       if (job_data) {
+               g_clear_object (&job_data->destination);
+               g_ptr_array_free (job_data->uids, TRUE);
+               g_free (job_data);
        }
+}
+
+static gboolean
+imapx_conn_manager_copy_message_run_sync (CamelIMAPXJob *job,
+                                         CamelIMAPXServer *server,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       struct CopyMessageJobData *job_data;
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       CON_WRITE_UNLOCK (con_man);
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (job_data->destination), FALSE);
+       g_return_val_if_fail (job_data->uids != NULL, FALSE);
 
-       g_mutex_lock (&con_man->priv->pending_connections_lock);
-       con_man->priv->pending_connections = g_slist_remove (con_man->priv->pending_connections, cancellable);
-       g_object_unref (cancellable);
-       g_mutex_unlock (&con_man->priv->pending_connections_lock);
+       success = camel_imapx_server_copy_message_sync (
+               server, mailbox, job_data->destination, job_data->uids, job_data->delete_originals,
+               job_data->remove_deleted_flags, cancellable, &local_error);
 
-       return is;
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
 }
 
-GList *
-camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
+gboolean
+camel_imapx_conn_manager_copy_message_sync (CamelIMAPXConnManager *conn_man,
+                                           CamelIMAPXMailbox *mailbox,
+                                           CamelIMAPXMailbox *destination,
+                                           GPtrArray *uids,
+                                           gboolean delete_originals,
+                                           gboolean remove_deleted_flags,
+                                           GCancellable *cancellable,
+                                           GError **error)
 {
-       GList *list, *link;
+       CamelIMAPXJob *job;
+       struct CopyMessageJobData *job_data;
+       gboolean success;
+       gint ii;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
 
-       list = imapx_conn_manager_list_info (con_man);
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_COPY_MESSAGE, mailbox,
+               imapx_conn_manager_copy_message_run_sync,
+               imapx_conn_manager_nothing_matches,
+               NULL);
 
-       /* 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);
+       job_data = g_new0 (struct CopyMessageJobData, 1);
+       job_data->destination = g_object_ref (destination);
+       job_data->uids = g_ptr_array_new_full (uids->len, (GDestroyNotify) camel_pstring_free);
+       job_data->delete_originals = delete_originals;
+       job_data->remove_deleted_flags = remove_deleted_flags;
+
+       for (ii = 0; ii < uids->len; ii++) {
+               g_ptr_array_add (job_data->uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
        }
 
-       return list;
+       camel_imapx_job_set_user_data (job, job_data, copy_message_job_data_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
 }
 
-/* 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)
+struct AppendMessageJobData {
+       CamelFolderSummary *summary;
+       CamelDataCache *message_cache;
+       CamelMimeMessage *message;
+       const CamelMessageInfo *mi;
+};
+
+static void
+append_message_job_data_free (gpointer ptr)
 {
-       ConnectionInfo *cinfo;
+       struct AppendMessageJobData *job_data = ptr;
+
+       if (job_data) {
+               g_clear_object (&job_data->summary);
+               g_clear_object (&job_data->message_cache);
+               g_clear_object (&job_data->message);
+               g_free (job_data);
+       }
+}
 
-       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+static gboolean
+imapx_conn_manager_append_message_run_sync (CamelIMAPXJob *job,
+                                           CamelIMAPXServer *server,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       struct AppendMessageJobData *job_data;
+       CamelIMAPXMailbox *mailbox;
+       gchar *appended_uid = NULL;
+       GError *local_error = NULL;
+       gboolean success;
 
-       /* Returns a new ConnectionInfo reference. */
-       cinfo = imapx_conn_manager_lookup_info (con_man, is);
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
 
-       if (cinfo == NULL)
-               return;
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+       g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+       g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (job_data->message), FALSE);
+
+       success = camel_imapx_server_append_message_sync (server, mailbox, job_data->summary, 
job_data->message_cache,
+               job_data->message, job_data->mi, &appended_uid, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, appended_uid, local_error, appended_uid ? g_free : NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_append_message_sync (CamelIMAPXConnManager *conn_man,
+                                             CamelIMAPXMailbox *mailbox,
+                                             CamelFolderSummary *summary,
+                                             CamelDataCache *message_cache,
+                                             CamelMimeMessage *message,
+                                             const CamelMessageInfo *mi,
+                                             gchar **append_uid,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       CamelIMAPXJob *job;
+       struct AppendMessageJobData *job_data;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_APPEND_MESSAGE, mailbox,
+               imapx_conn_manager_append_message_run_sync,
+               imapx_conn_manager_nothing_matches,
+               NULL);
 
-       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);
+       job_data = g_new0 (struct AppendMessageJobData, 1);
+       job_data->summary = g_object_ref (summary);
+       job_data->message_cache = g_object_ref (message_cache);
+       job_data->message = g_object_ref (message);
+       job_data->mi = mi;
+
+       camel_imapx_job_set_user_data (job, job_data, append_message_job_data_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+       if (success) {
+               gpointer result_data = NULL;
+
+               success = camel_imapx_job_take_result_data (job, &result_data);
+               if (success && append_uid)
+                       *append_uid = result_data;
+               else
+                       g_free (result_data);
        }
 
-       connection_info_unref (cinfo);
+       camel_imapx_job_unref (job);
+
+       return success;
 }
 
-void
-camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man,
-                                           const GError *error)
+static gboolean
+imapx_conn_manager_sync_message_run_sync (CamelIMAPXJob *job,
+                                         CamelIMAPXServer *server,
+                                         GCancellable *cancellable,
+                                         GError **error)
 {
-       GList *iter, *connections;
+       struct GetMessageJobData *job_data;
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
 
-       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
 
-       /* Do this before acquiring the write lock, because any pending
-          connection holds the write lock, thus makes this request starve. */
-       imax_conn_manager_cancel_pending_connections (con_man);
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       job_data = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (job_data != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (job_data->summary), FALSE);
+       g_return_val_if_fail (CAMEL_IS_DATA_CACHE (job_data->message_cache), FALSE);
+       g_return_val_if_fail (job_data->message_uid != NULL, FALSE);
+
+       success = camel_imapx_server_sync_message_sync (
+               server, mailbox, job_data->summary, job_data->message_cache, job_data->message_uid,
+               cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_sync_message_sync (CamelIMAPXConnManager *conn_man,
+                                           CamelIMAPXMailbox *mailbox,
+                                           CamelFolderSummary *summary,
+                                           CamelDataCache *message_cache,
+                                           const gchar *message_uid,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       CamelIMAPXJob *job;
+       struct GetMessageJobData *job_data;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SYNC_MESSAGE, mailbox,
+               imapx_conn_manager_sync_message_run_sync,
+               imapx_conn_manager_get_message_matches,
+               NULL);
+
+       job_data = g_new0 (struct GetMessageJobData, 1);
+       job_data->summary = g_object_ref (summary);
+       job_data->message_cache = g_object_ref (message_cache);
+       job_data->message_uid = g_strdup (message_uid);
+
+       camel_imapx_job_set_user_data (job, job_data, get_message_job_data_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_create_mailbox_run_sync (CamelIMAPXJob *job,
+                                           CamelIMAPXServer *server,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       const gchar *mailbox_name;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox_name = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (mailbox_name != NULL, FALSE);
+
+       success = camel_imapx_server_create_mailbox_sync (server, mailbox_name, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_create_mailbox_sync (CamelIMAPXConnManager *conn_man,
+                                             const gchar *mailbox_name,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_CREATE_MAILBOX, NULL,
+               imapx_conn_manager_create_mailbox_run_sync,
+               imapx_conn_manager_nothing_matches,
+               NULL);
+
+       camel_imapx_job_set_user_data (job, g_strdup (mailbox_name), g_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_delete_mailbox_run_sync (CamelIMAPXJob *job,
+                                           CamelIMAPXServer *server,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       success = camel_imapx_server_delete_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_delete_mailbox_sync (CamelIMAPXConnManager *conn_man,
+                                             CamelIMAPXMailbox *mailbox,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_DELETE_MAILBOX, mailbox,
+               imapx_conn_manager_delete_mailbox_run_sync,
+               imapx_conn_manager_nothing_matches,
+               NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_rename_mailbox_run_sync (CamelIMAPXJob *job,
+                                           CamelIMAPXServer *server,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       const gchar *new_mailbox_name;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       new_mailbox_name = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
+
+       success = camel_imapx_server_rename_mailbox_sync (server, mailbox, new_mailbox_name, cancellable, 
&local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_rename_mailbox_sync (CamelIMAPXConnManager *conn_man,
+                                             CamelIMAPXMailbox *mailbox,
+                                             const gchar *new_mailbox_name,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_RENAME_MAILBOX, mailbox,
+               imapx_conn_manager_rename_mailbox_run_sync,
+               imapx_conn_manager_nothing_matches,
+               NULL);
+
+       camel_imapx_job_set_user_data (job, g_strdup (new_mailbox_name), g_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_subscribe_mailbox_run_sync (CamelIMAPXJob *job,
+                                              CamelIMAPXServer *server,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
 
-       CON_WRITE_LOCK (con_man);
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
 
-       c('*', "Closing all %d connections, with propagated error: %s\n", g_list_length 
(con_man->priv->connections), error ? error->message : "none");
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       connections = con_man->priv->connections;
-       con_man->priv->connections = NULL;
+       success = camel_imapx_server_subscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
 
-       CON_WRITE_UNLOCK (con_man);
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
 
-       for (iter = connections; iter; iter = g_list_next (iter)) {
-               connection_info_set_shutdown_error (iter->data, error);
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_subscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, mailbox,
+               imapx_conn_manager_subscribe_mailbox_run_sync, NULL, NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_unsubscribe_mailbox_run_sync (CamelIMAPXJob *job,
+                                                CamelIMAPXServer *server,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       success = camel_imapx_server_unsubscribe_mailbox_sync (server, mailbox, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_unsubscribe_mailbox_sync (CamelIMAPXConnManager *conn_man,
+                                                  CamelIMAPXMailbox *mailbox,
+                                                  GCancellable *cancellable,
+                                                  GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, mailbox,
+               imapx_conn_manager_unsubscribe_mailbox_run_sync, NULL, NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_update_quota_info_run_sync (CamelIMAPXJob *job,
+                                              CamelIMAPXServer *server,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       GError *local_error = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       success = camel_imapx_server_update_quota_info_sync (server, mailbox, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, success, NULL, local_error, NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return success;
+}
+
+gboolean
+camel_imapx_conn_manager_update_quota_info_sync (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), FALSE);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, mailbox,
+               imapx_conn_manager_update_quota_info_run_sync, NULL, NULL);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+
+       camel_imapx_job_unref (job);
+
+       return success;
+}
+
+static gboolean
+imapx_conn_manager_uid_search_run_sync (CamelIMAPXJob *job,
+                                       CamelIMAPXServer *server,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+       CamelIMAPXMailbox *mailbox;
+       const gchar *criteria;
+       GPtrArray *uids = NULL;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+
+       mailbox = camel_imapx_job_get_mailbox (job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       criteria = camel_imapx_job_get_user_data (job);
+       g_return_val_if_fail (criteria != NULL, FALSE);
+
+       uids = camel_imapx_server_uid_search_sync (server, mailbox, criteria, cancellable, &local_error);
+
+       camel_imapx_job_set_result (job, uids != NULL, uids, local_error, uids ? (GDestroyNotify) 
g_ptr_array_free : NULL);
+
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       return uids != NULL;
+}
+
+static gboolean
+imapx_conn_manager_uid_search_matches (CamelIMAPXJob *job,
+                                      CamelIMAPXJob *other_job)
+{
+       const gchar *job_criteria, *other_job_criteria;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (other_job != NULL, FALSE);
+
+       if (camel_imapx_job_get_kind (job) != CAMEL_IMAPX_JOB_UID_SEARCH ||
+           camel_imapx_job_get_kind (job) != camel_imapx_job_get_kind (other_job))
+               return FALSE;
+
+       job_criteria = camel_imapx_job_get_user_data (job);
+       other_job_criteria = camel_imapx_job_get_user_data (other_job);
+
+       return g_strcmp0 (job_criteria, other_job_criteria) == 0;
+}
+
+GPtrArray *
+camel_imapx_conn_manager_uid_search_sync (CamelIMAPXConnManager *conn_man,
+                                         CamelIMAPXMailbox *mailbox,
+                                         const gchar *criteria,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       GPtrArray *uids = NULL;
+       CamelIMAPXJob *job;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man), NULL);
+
+       job = camel_imapx_job_new (CAMEL_IMAPX_JOB_UID_SEARCH, mailbox,
+               imapx_conn_manager_uid_search_run_sync,
+               imapx_conn_manager_uid_search_matches,
+               NULL);
+
+       camel_imapx_job_set_user_data (job, g_strdup (criteria), g_free);
+
+       success = camel_imapx_conn_manager_run_job_sync (conn_man, job, NULL, cancellable, error);
+       if (success) {
+               gpointer result_data = NULL;
+
+               success = camel_imapx_job_take_result_data (job, &result_data);
+               if (success)
+                       uids = result_data;
        }
 
-       g_list_free_full (connections, (GDestroyNotify) connection_info_cancel_and_unref);
+       camel_imapx_job_unref (job);
+
+       return uids;
 }
 
 /* for debugging purposes only */
 void
-camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_dump_queue_status (CamelIMAPXConnManager *conn_man)
 {
-       GList *list, *link;
+       GList *llink;
+       GSList *slink;
 
-       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
+       g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
 
-       list = imapx_conn_manager_list_info (con_man);
+       CON_READ_LOCK (conn_man);
 
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               ConnectionInfo *cinfo = link->data;
-               camel_imapx_server_dump_queue_status (cinfo->is);
-               connection_info_unref (cinfo);
+       printf ("%s: opened connections:%d\n", G_STRFUNC, g_list_length (conn_man->priv->connections));
+
+       for (llink = conn_man->priv->connections; llink != NULL; llink = g_list_next (llink)) {
+               ConnectionInfo *cinfo = llink->data;
+               CamelIMAPXCommand *cmd = NULL;
+
+               if (cinfo)
+                       cmd = cinfo->is ? camel_imapx_server_ref_current_command (cinfo->is) : NULL;
+
+               printf ("   connection:%p server:%p busy:%d command:%s\n", cinfo, cinfo ? cinfo->is : NULL, 
cinfo ? cinfo->busy : FALSE,
+                       cmd ? camel_imapx_job_get_kind_name (cmd->job_kind) : "[null]");
+
+               if (cmd)
+                       camel_imapx_command_unref (cmd);
+       }
+
+       CON_READ_UNLOCK (conn_man);
+
+       g_rec_mutex_lock (&conn_man->priv->job_queue_lock);
+
+       printf ("Queued jobs:%d\n", g_slist_length (conn_man->priv->job_queue));
+       for (slink = conn_man->priv->job_queue; slink; slink = g_slist_next (slink)) {
+               CamelIMAPXJob *job = slink->data;
+
+               printf ("   job:%p kind:%s mailbox:%s\n", job,
+                       job ? camel_imapx_job_get_kind_name (camel_imapx_job_get_kind (job)) : "[null]",
+                       job && camel_imapx_job_get_mailbox (job) ? camel_imapx_mailbox_get_name 
(camel_imapx_job_get_mailbox (job)) : "[null]");
        }
 
-       g_list_free (list);
+       g_rec_mutex_unlock (&conn_man->priv->job_queue_lock);
 }
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.h 
b/camel/providers/imapx/camel-imapx-conn-manager.h
index 60cc789..3fc5beb 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.h
+++ b/camel/providers/imapx/camel-imapx-conn-manager.h
@@ -21,6 +21,8 @@
 #ifndef _CAMEL_IMAPX_CONN_MANAGER_H
 #define _CAMEL_IMAPX_CONN_MANAGER_H
 
+#include "camel-imapx-job.h"
+#include "camel-imapx-mailbox.h"
 #include "camel-imapx-server.h"
 
 G_BEGIN_DECLS
@@ -44,6 +46,8 @@ G_BEGIN_DECLS
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerClass))
 
+struct _CamelIMAPXStore;
+
 typedef struct _CamelIMAPXConnManager CamelIMAPXConnManager;
 typedef struct _CamelIMAPXConnManagerClass CamelIMAPXConnManagerClass;
 typedef struct _CamelIMAPXConnManagerPrivate CamelIMAPXConnManagerPrivate;
@@ -56,33 +60,129 @@ struct _CamelIMAPXConnManager {
 
 struct _CamelIMAPXConnManagerClass {
        GObjectClass parent_class;
+
+       /* Signals */
+       void    (* connection_created) (CamelIMAPXConnManager *conn_man,
+                                       CamelIMAPXServer *server);
 };
 
 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,
-                                                const GError *error);
-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);
+struct _CamelIMAPXStore *
+               camel_imapx_conn_manager_ref_store
+                                               (CamelIMAPXConnManager *conn_man);
+gboolean       camel_imapx_conn_manager_connect_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_disconnect_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_run_job_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXJob *job,
+                                                CamelIMAPXJobMatchesFunc finish_before_job,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_list_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                const gchar *pattern,
+                                                CamelStoreGetFolderInfoFlags flags,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_refresh_info_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_sync_changes_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_expunge_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+CamelStream *  camel_imapx_conn_manager_get_message_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                CamelFolderSummary *summary,
+                                                CamelDataCache *message_cache,
+                                                const gchar *message_uid,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_copy_message_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                CamelIMAPXMailbox *destination,
+                                                GPtrArray *uids,
+                                                gboolean delete_originals,
+                                                gboolean remove_deleted_flags,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_append_message_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                CamelFolderSummary *summary,
+                                                CamelDataCache *message_cache,
+                                                CamelMimeMessage *message,
+                                                const CamelMessageInfo *mi,
+                                                gchar **append_uid,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_sync_message_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                CamelFolderSummary *summary,
+                                                CamelDataCache *message_cache,
+                                                const gchar *message_uid,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_create_mailbox_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                const gchar *mailbox_name,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_delete_mailbox_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_rename_mailbox_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                const gchar *new_mailbox_name,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_subscribe_mailbox_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_unsubscribe_mailbox_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_conn_manager_update_quota_info_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+GPtrArray *    camel_imapx_conn_manager_uid_search_sync
+                                               (CamelIMAPXConnManager *conn_man,
+                                                CamelIMAPXMailbox *mailbox,
+                                                const gchar *criteria,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 /* for debugging purposes only */
 void           camel_imapx_conn_manager_dump_queue_status
-                                               (CamelIMAPXConnManager *con_man);
+                                               (CamelIMAPXConnManager *conn_man);
 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 1d0db10..729d22e 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -425,60 +425,31 @@ imapx_append_message_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
-       const gchar *folder_name;
-       GError *local_error = NULL;
        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, folder_name, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (mailbox == NULL)
                goto exit;
-       }
 
-       success = camel_imapx_server_append_message (
-               imapx_server, mailbox, folder->summary,
+       success = camel_imapx_conn_manager_append_message_sync (
+               conn_man, mailbox, folder->summary,
                CAMEL_IMAPX_FOLDER (folder)->cache, message,
-               info, appended_uid, cancellable, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_append_message (
-                               imapx_server, mailbox, folder->summary,
-                               CAMEL_IMAPX_FOLDER (folder)->cache, message,
-                               info, appended_uid, cancellable, &local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+               info, appended_uid, cancellable, error);
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -490,28 +461,21 @@ imapx_expunge_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        GError *local_error = 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, folder_name, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (mailbox == NULL)
                goto exit;
-       }
 
        if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
                CamelFolder *trash;
@@ -549,28 +513,10 @@ imapx_expunge_sync (CamelFolder *folder,
                g_clear_error (&local_error);
        }
 
-       success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, 
&local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -628,7 +574,6 @@ imapx_get_message_sync (CamelFolder *folder,
        GIOStream *base_stream;
        const gchar *path = NULL;
        gboolean offline_message = FALSE;
-       GError *local_error = NULL;
 
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        store = camel_folder_get_parent_store (folder);
@@ -646,9 +591,8 @@ imapx_get_message_sync (CamelFolder *folder,
                stream = camel_stream_new (base_stream);
                g_object_unref (base_stream);
        } else {
-               CamelIMAPXServer *imapx_server;
+               CamelIMAPXConnManager *conn_man;
                CamelIMAPXMailbox *mailbox;
-               const gchar *folder_name;
 
                if (offline_message) {
                        g_set_error (
@@ -658,49 +602,20 @@ 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), folder_name, FALSE, cancellable, error);
-
-               if (imapx_server == NULL)
-                       return NULL;
+               conn_man = camel_imapx_store_get_conn_manager (CAMEL_IMAPX_STORE (store));
 
                mailbox = camel_imapx_folder_list_mailbox (
                        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);
+               if (mailbox == NULL)
                        return NULL;
-               }
 
-               stream = camel_imapx_server_get_message (
-                       imapx_server, mailbox, folder->summary,
+               stream = camel_imapx_conn_manager_get_message_sync (
+                       conn_man, mailbox, folder->summary,
                        CAMEL_IMAPX_FOLDER (folder)->cache, uid,
-                       cancellable, &local_error);
-
-               camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, folder_name);
-
-               while (!stream && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                       g_clear_error (&local_error);
-                       g_clear_object (&imapx_server);
-
-                       imapx_server = camel_imapx_store_ref_server (CAMEL_IMAPX_STORE (store), folder_name, 
FALSE, cancellable, &local_error);
-                       if (imapx_server) {
-                               stream = camel_imapx_server_get_message (
-                                       imapx_server, mailbox, folder->summary,
-                                       CAMEL_IMAPX_FOLDER (folder)->cache, uid,
-                                       cancellable, &local_error);
-
-                               camel_imapx_store_folder_op_done (CAMEL_IMAPX_STORE (store), imapx_server, 
folder_name);
-                       }
-               }
-
-               if (local_error)
-                       g_propagate_error (error, local_error);
+                       cancellable, error);
 
                g_clear_object (&mailbox);
-               g_clear_object (&imapx_server);
        }
 
        if (stream != NULL) {
@@ -750,48 +665,23 @@ imapx_get_quota_info_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        CamelFolderQuotaInfo *quota_info = NULL;
-       const gchar *folder_name;
        gchar **quota_roots;
        gboolean success = FALSE;
-       GError *local_error = 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, folder_name, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-       if (mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (mailbox == NULL)
                goto exit;
-       }
-
-       success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_update_quota_info (imapx_server, mailbox, cancellable, 
&local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
 
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_update_quota_info_sync (conn_man, mailbox, cancellable, error);
 
        if (!success)
                goto exit;
@@ -814,7 +704,6 @@ imapx_get_quota_info_sync (CamelFolder *folder,
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return quota_info;
 }
@@ -837,12 +726,9 @@ imapx_refresh_info_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
-       CamelFolderChangeInfo *changes;
-       gchar *folder_name;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        store = camel_folder_get_parent_store (folder);
 
@@ -850,58 +736,23 @@ imapx_refresh_info_sync (CamelFolder *folder,
        if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
                return TRUE;
 
-       folder_name = g_strdup (camel_folder_get_full_name (folder));
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
-       mailbox = camel_imapx_folder_list_mailbox (
-               CAMEL_IMAPX_FOLDER (folder), cancellable, error);
-
-       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, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       changes = camel_imapx_server_refresh_info (imapx_server, mailbox, cancellable, 
&local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (changes != NULL) {
-               if (camel_folder_change_info_changed (changes))
-                       camel_folder_changed (folder, changes);
-               camel_folder_change_info_free (changes);
-               success = TRUE;
+       if (mailbox) {
+               success = camel_imapx_conn_manager_refresh_info_sync (conn_man, mailbox, cancellable, error);
        }
 
-exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
-       g_free (folder_name);
 
        return success;
 }
 
 /* Helper for imapx_synchronize_sync() */
 static gboolean
-imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
+imapx_move_to_real_junk (CamelIMAPXConnManager *conn_man,
                          CamelFolder *folder,
                          GCancellable *cancellable,
                          gboolean *out_need_to_expunge,
@@ -925,7 +776,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
        uids_to_copy = g_ptr_array_new_with_free_func (
                (GDestroyNotify) camel_pstring_free);
 
-       settings = camel_imapx_server_ref_settings (imapx_server);
+       settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE 
(camel_folder_get_parent_store (folder))));
        if (camel_imapx_settings_get_use_real_junk_path (settings)) {
                real_junk_path =
                        camel_imapx_settings_dup_real_junk_path (settings);
@@ -938,7 +789,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
                CamelIMAPXStore *imapx_store;
                CamelIMAPXMailbox *destination = NULL;
 
-               imapx_store = camel_imapx_server_ref_store (imapx_server);
+               imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
 
                if (real_junk_path != NULL) {
                        folder = camel_store_get_folder_sync (
@@ -964,9 +815,8 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
                if (destination == mailbox) {
                        success = TRUE;
                } else if (destination != NULL) {
-                       success = camel_imapx_server_copy_message (
-                               imapx_server,
-                               mailbox, destination,
+                       success = camel_imapx_conn_manager_copy_message_sync (
+                               conn_man, mailbox, destination,
                                uids_to_copy, TRUE, FALSE,
                                cancellable, error);
                        *out_need_to_expunge = success;
@@ -994,7 +844,7 @@ imapx_move_to_real_junk (CamelIMAPXServer *imapx_server,
 
 /* Helper for imapx_synchronize_sync() */
 static gboolean
-imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
+imapx_move_to_real_trash (CamelIMAPXConnManager *conn_man,
                           CamelFolder *folder,
                           GCancellable *cancellable,
                           gboolean *out_need_to_expunge,
@@ -1018,7 +868,7 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
        uids_to_copy = g_ptr_array_new_with_free_func (
                (GDestroyNotify) camel_pstring_free);
 
-       settings = camel_imapx_server_ref_settings (imapx_server);
+       settings = CAMEL_IMAPX_SETTINGS (camel_service_ref_settings (CAMEL_SERVICE 
(camel_folder_get_parent_store (folder))));
        if (camel_imapx_settings_get_use_real_trash_path (settings)) {
                real_trash_path =
                        camel_imapx_settings_dup_real_trash_path (settings);
@@ -1031,7 +881,7 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
                CamelIMAPXStore *imapx_store;
                CamelIMAPXMailbox *destination = NULL;
 
-               imapx_store = camel_imapx_server_ref_store (imapx_server);
+               imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
 
                if (real_trash_path != NULL) {
                        folder = camel_store_get_folder_sync (
@@ -1059,9 +909,8 @@ imapx_move_to_real_trash (CamelIMAPXServer *imapx_server,
                        /* Deleted messages in the real Trash folder will be permanently deleted immediately. 
*/
                        *out_need_to_expunge = TRUE;
                } else if (destination != NULL) {
-                       success = camel_imapx_server_copy_message (
-                               imapx_server,
-                               mailbox, destination,
+                       success = camel_imapx_conn_manager_copy_message_sync (
+                               conn_man, mailbox, destination,
                                uids_to_copy, TRUE, TRUE,
                                cancellable, error);
                        *out_need_to_expunge = success;
@@ -1095,27 +944,19 @@ imapx_synchronize_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
-       const gchar *folder_name;
        gboolean need_to_expunge;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        store = camel_folder_get_parent_store (folder);
-       folder_name = camel_folder_get_full_name (folder);
 
        /* Not connected, thus skip the operation */
        if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
                return TRUE;
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       /* 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;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
@@ -1123,34 +964,21 @@ imapx_synchronize_sync (CamelFolder *folder,
        if (mailbox == NULL || (camel_application_is_exiting &&
            camel_imapx_mailbox_get_permanentflags (mailbox) == ~0)) {
                success = 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, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_sync_changes (imapx_server, mailbox, cancellable, 
&local_error);
-               }
-       }
+       success = camel_imapx_conn_manager_sync_changes_sync (conn_man, mailbox, cancellable, error);
 
        if (success) {
                success = imapx_move_to_real_junk (
-                       imapx_server, folder, cancellable,
+                       conn_man, folder, cancellable,
                        &need_to_expunge, error);
                expunge |= need_to_expunge;
        }
 
        if (success) {
                success = imapx_move_to_real_trash (
-                       imapx_server, folder, cancellable,
+                       conn_man, folder, cancellable,
                        &need_to_expunge, error);
                expunge |= need_to_expunge;
        }
@@ -1158,31 +986,11 @@ imapx_synchronize_sync (CamelFolder *folder,
        /* Sync twice - make sure deleted flags are written out,
         * then sync again incase expunge changed anything */
 
-       if (success && expunge) {
-               success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, &local_error);
-
-               while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-                       g_clear_error (&local_error);
-                       g_clear_object (&imapx_server);
-
-                       imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, 
cancellable, &local_error);
-                       if (imapx_server) {
-                               success = camel_imapx_server_expunge (imapx_server, mailbox, cancellable, 
&local_error);
-                       }
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
-
-       if (imapx_server)
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (success && expunge)
+               success = camel_imapx_conn_manager_expunge_sync (conn_man, mailbox, cancellable, error);
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -1195,57 +1003,28 @@ imapx_synchronize_message_sync (CamelFolder *folder,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
-       const gchar *folder_name;
        gboolean success = FALSE;
-       GError *local_error = 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, folder_name, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
 
-       if (mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (mailbox == NULL)
                goto exit;
-       }
 
-       success = camel_imapx_server_sync_message (
-               imapx_server, mailbox, folder->summary,
+       success = camel_imapx_conn_manager_sync_message_sync (
+               conn_man, mailbox, folder->summary,
                CAMEL_IMAPX_FOLDER (folder)->cache, uid,
-               cancellable, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_sync_message (
-                               imapx_server, mailbox, folder->summary,
-                               CAMEL_IMAPX_FOLDER (folder)->cache, uid,
-                               cancellable, &local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+               cancellable, error);
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -1261,60 +1040,31 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
 {
        CamelStore *store;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *src_mailbox = NULL;
        CamelIMAPXMailbox *dst_mailbox = NULL;
-       const gchar *folder_name;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        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, folder_name, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        src_mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (source), cancellable, error);
 
-       if (src_mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (src_mailbox == NULL)
                goto exit;
-       }
 
        dst_mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (dest), cancellable, error);
 
-       if (dst_mailbox == NULL) {
-               camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
+       if (dst_mailbox == NULL)
                goto exit;
-       }
-
-       success = camel_imapx_server_copy_message (
-               imapx_server, src_mailbox, dst_mailbox, uids,
-               delete_originals, FALSE, cancellable, &local_error);
-
-       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, FALSE, cancellable, 
&local_error);
-               if (imapx_server) {
-                       success = camel_imapx_server_copy_message (
-                               imapx_server, src_mailbox, dst_mailbox, uids,
-                               delete_originals, FALSE, cancellable, &local_error);
-
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-               }
-       }
 
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_copy_message_sync (
+               conn_man, src_mailbox, dst_mailbox, uids,
+               delete_originals, FALSE, cancellable, error);
 
        /* Update destination folder only if it's not frozen,
         * to avoid updating for each "move" action on a single
@@ -1325,7 +1075,6 @@ imapx_transfer_messages_to_sync (CamelFolder *source,
 exit:
        g_clear_object (&src_mailbox);
        g_clear_object (&dst_mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -1687,7 +1436,7 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
                                  GError **error)
 {
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *server = NULL;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox;
        CamelStore *parent_store;
        CamelStoreInfo *store_info;
@@ -1696,7 +1445,6 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
        gchar *mailbox_name = NULL;
        gchar *pattern;
        gboolean success;
-       GError *local_error = NULL;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
 
@@ -1733,36 +1481,14 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
                goto exit;
        }
 
-       server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-       if (server == NULL)
-               goto exit;
-
-       mailbox = camel_imapx_store_ref_mailbox (imapx_store, mailbox_name);
-       if (mailbox != NULL) {
-               camel_imapx_folder_set_mailbox (folder, mailbox);
-               goto exit;
-       }
-
        /* Last resort is to issue a LIST command.  Maintainer should
         * monitor IMAP logs to make sure this is rarely if ever used. */
 
        pattern = camel_utf8_utf7 (mailbox_name);
 
        /* This creates a mailbox instance from the LIST response. */
-       success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&server);
-
-               server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
-               if (server) {
-                       success = camel_imapx_server_list (server, pattern, 0, cancellable, &local_error);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+       success = camel_imapx_conn_manager_list_sync (conn_man, pattern, 0, cancellable, error);
 
        g_free (pattern);
 
@@ -1783,8 +1509,6 @@ camel_imapx_folder_list_mailbox (CamelIMAPXFolder *folder,
        }
 
 exit:
-       g_clear_object (&server);
-
        g_free (folder_path);
        g_free (mailbox_name);
 
diff --git a/camel/providers/imapx/camel-imapx-input-stream.c 
b/camel/providers/imapx/camel-imapx-input-stream.c
index 6a0af1e..706fafe 100644
--- a/camel/providers/imapx/camel-imapx-input-stream.c
+++ b/camel/providers/imapx/camel-imapx-input-stream.c
@@ -67,6 +67,9 @@ imapx_input_stream_fill (CamelIMAPXInputStream *is,
        GInputStream *base_stream;
        gint left = 0;
 
+       if (g_cancellable_is_cancelled (cancellable))
+               return -1;
+
        base_stream = g_filter_input_stream_get_base_stream (
                G_FILTER_INPUT_STREAM (is));
 
@@ -707,7 +710,7 @@ camel_imapx_input_stream_token (CamelIMAPXInputStream *is,
                return is->priv->unget_tok;
        }
 
-       if (is->priv->literal > 0)
+       if (is->priv->literal > 0 && !g_cancellable_is_cancelled (cancellable))
                g_warning (
                        "stream_token called with literal %d",
                        is->priv->literal);
diff --git a/camel/providers/imapx/camel-imapx-job.c b/camel/providers/imapx/camel-imapx-job.c
index 085cc96..1912063 100644
--- a/camel/providers/imapx/camel-imapx-job.c
+++ b/camel/providers/imapx/camel-imapx-job.c
@@ -14,475 +14,524 @@
  * along with this library. If not, see <http://www.gnu.org/licenses/>.
  *
  */
-
-#include "camel-imapx-job.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <string.h>
 
-#include "camel-imapx-folder.h"
-
-typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
-
-/* CamelIMAPXJob + some private bits */
-struct _CamelIMAPXRealJob {
-       CamelIMAPXJob public;
-
-       volatile gint ref_count;
-
-       GCancellable *cancellable;
-
-       /* This is set by camel_imapx_job_take_error(),
-        * and propagated through camel_imapx_job_wait(). */
-       GError *error;
-
-       /* Used for running some jobs synchronously. */
-       GCond done_cond;
-       GMutex done_mutex;
-       gboolean done_flag;
-
-       /* Extra job-specific data. */
-       gpointer data;
-       GDestroyNotify destroy_data;
-
-       CamelIMAPXMailbox *mailbox;
-       GMutex mailbox_lock;
+#include "camel-imapx-job.h"
 
-       CamelIMAPXMailbox *guard_mailbox_update; /* uses the mailbox_lock */
-       gint has_update_locked;
-};
+G_LOCK_DEFINE_STATIC (get_kind_name_funcs);
+static GSList *get_kind_name_funcs = NULL;
 
-static void
-imapx_job_cancelled_cb (GCancellable *cancellable,
-                        CamelIMAPXJob *job)
+const gchar *
+camel_imapx_job_get_kind_name (guint32 job_kind)
 {
-       /* Unblock camel_imapx_run_job() immediately.
-        *
-        * If camel_imapx_job_done() is called sometime later,
-        * the GCond will broadcast but no one will be listening. */
+       GSList *link;
+
+       switch ((CamelIMAPXJobKind) job_kind) {
+       case CAMEL_IMAPX_JOB_UNKNOWN:
+               return "UNKNOWN";
+       case CAMEL_IMAPX_JOB_CAPABILITY:
+               return "CAPABILITY";
+       case CAMEL_IMAPX_JOB_STARTTLS:
+               return "STARTTLS";
+       case CAMEL_IMAPX_JOB_AUTHENTICATE:
+               return "AUTHENTICATE";
+       case CAMEL_IMAPX_JOB_LOGIN:
+               return "LOGIN";
+       case CAMEL_IMAPX_JOB_NAMESPACE:
+               return "NAMESPACE";
+       case CAMEL_IMAPX_JOB_SELECT:
+               return "SELECT";
+       case CAMEL_IMAPX_JOB_STATUS:
+               return "STATUS";
+       case CAMEL_IMAPX_JOB_ENABLE:
+               return "ENABLE";
+       case CAMEL_IMAPX_JOB_NOTIFY:
+               return "NOTIFY";
+       case CAMEL_IMAPX_JOB_GET_MESSAGE:
+               return "GET_MESSAGE";
+       case CAMEL_IMAPX_JOB_SYNC_MESSAGE:
+               return "SYNC_MESSAGE";
+       case CAMEL_IMAPX_JOB_APPEND_MESSAGE:
+               return "APPEND_MESSAGE";
+       case CAMEL_IMAPX_JOB_COPY_MESSAGE:
+               return "COPY_MESSAGE";
+       case CAMEL_IMAPX_JOB_MOVE_MESSAGE:
+               return "MOVE_MESSAGE";
+       case CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES:
+               return "FETCH_NEW_MESSAGES";
+       case CAMEL_IMAPX_JOB_REFRESH_INFO:
+               return "REFRESH_INFO";
+       case CAMEL_IMAPX_JOB_SYNC_CHANGES:
+               return "SYNC_CHANGES";
+       case CAMEL_IMAPX_JOB_EXPUNGE:
+               return "EXPUNGE";
+       case CAMEL_IMAPX_JOB_NOOP:
+               return "NOOP";
+       case CAMEL_IMAPX_JOB_IDLE:
+               return "IDLE";
+       case CAMEL_IMAPX_JOB_DONE:
+               return "DONE";
+       case CAMEL_IMAPX_JOB_LIST:
+               return "LIST";
+       case CAMEL_IMAPX_JOB_LSUB:
+               return "LSUB";
+       case CAMEL_IMAPX_JOB_CREATE_MAILBOX:
+               return "CREATE_MAILBOX";
+       case CAMEL_IMAPX_JOB_DELETE_MAILBOX:
+               return "DELETE_MAILBOX";
+       case CAMEL_IMAPX_JOB_RENAME_MAILBOX:
+               return "RENAME_MAILBOX";
+       case CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX:
+               return "SUBSCRIBE_MAILBOX";
+       case CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
+               return "UNSUBSCRIBE_MAILBOX";
+       case CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO:
+               return "UPDATE_QUOTA_INFO";
+       case CAMEL_IMAPX_JOB_UID_SEARCH:
+               return "UID_SEARCH";
+       case CAMEL_IMAPX_JOB_LAST:
+               break;
+       }
 
-       camel_imapx_job_done (job);
-}
+       G_LOCK (get_kind_name_funcs);
 
-CamelIMAPXJob *
-camel_imapx_job_new (GCancellable *cancellable)
-{
-       CamelIMAPXRealJob *real_job;
+       for (link = get_kind_name_funcs; link; link = g_slist_next (link)) {
+               CamelIMAPXJobGetKindNameFunc get_kind_name = link->data;
 
-       real_job = g_slice_new0 (CamelIMAPXRealJob);
+               if (get_kind_name) {
+                       const gchar *name = get_kind_name (job_kind);
 
-       /* Initialize private bits. */
-       real_job->ref_count = 1;
-       g_cond_init (&real_job->done_cond);
-       g_mutex_init (&real_job->done_mutex);
+                       if (name) {
+                               G_UNLOCK (get_kind_name_funcs);
+                               return name;
+                       }
+               }
+       }
 
-       if (cancellable != NULL)
-               g_object_ref (cancellable);
-       real_job->cancellable = cancellable;
+       G_UNLOCK (get_kind_name_funcs);
 
-       g_mutex_init (&real_job->mailbox_lock);
+       if (job_kind == CAMEL_IMAPX_JOB_LAST)
+               return "LAST";
 
-       return (CamelIMAPXJob *) real_job;
+       return "???";
 }
 
-CamelIMAPXJob *
-camel_imapx_job_ref (CamelIMAPXJob *job)
+void
+camel_imapx_job_register_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+       g_return_if_fail (get_kind_name != NULL);
 
-       real_job = (CamelIMAPXRealJob *) job;
+       G_LOCK (get_kind_name_funcs);
 
-       g_atomic_int_inc (&real_job->ref_count);
+       if (!g_slist_find (get_kind_name_funcs, get_kind_name))
+               get_kind_name_funcs = g_slist_prepend (get_kind_name_funcs, get_kind_name);
 
-       return job;
+       G_UNLOCK (get_kind_name_funcs);
 }
 
 void
-camel_imapx_job_unref (CamelIMAPXJob *job)
+camel_imapx_job_unregister_get_kind_name_func (CamelIMAPXJobGetKindNameFunc get_kind_name)
 {
-       CamelIMAPXRealJob *real_job;
+       g_return_if_fail (get_kind_name != NULL);
 
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       G_LOCK (get_kind_name_funcs);
 
-       real_job = (CamelIMAPXRealJob *) job;
+       g_warn_if_fail (g_slist_find (get_kind_name_funcs, get_kind_name));
+       get_kind_name_funcs = g_slist_remove (get_kind_name_funcs, get_kind_name);
 
-       if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
+       G_UNLOCK (get_kind_name_funcs);
+}
 
-               /* Free the public stuff. */
+struct _CamelIMAPXJob {
+       volatile gint ref_count;
 
-               if (real_job->public.pop_operation_msg)
-                       camel_operation_pop_message (real_job->cancellable);
+       guint32 job_kind;
+       CamelIMAPXMailbox *mailbox;
 
-               /* Free the private stuff. */
+       CamelIMAPXJobRunSyncFunc run_sync;
+       CamelIMAPXJobMatchesFunc matches;
+       CamelIMAPXJobCopyResultFunc copy_result;
 
-               if (real_job->cancellable != NULL)
-                       g_object_unref (real_job->cancellable);
+       /* Extra job-specific data. */
+       gpointer user_data;
+       GDestroyNotify destroy_user_data;
 
-               g_clear_error (&real_job->error);
+       gboolean result_is_set;
+       gboolean result_success;
+       gpointer result_data;
+       GError *result_error;
+       GDestroyNotify destroy_result_data;
 
-               g_cond_clear (&real_job->done_cond);
-               g_mutex_clear (&real_job->done_mutex);
+       GCond done_cond;
+       GMutex done_mutex;
+       gboolean is_done;
 
-               if (real_job->destroy_data != NULL)
-                       real_job->destroy_data (real_job->data);
+       GCancellable *abort_cancellable;
+};
 
-               g_mutex_lock (&real_job->mailbox_lock);
-               while (real_job->has_update_locked > 0) {
-                       camel_imapx_mailbox_inc_update_count (real_job->guard_mailbox_update, -1);
-                       real_job->has_update_locked--;
-               }
-               g_clear_object (&real_job->guard_mailbox_update);
-               g_mutex_unlock (&real_job->mailbox_lock);
+CamelIMAPXJob *
+camel_imapx_job_new (guint32 job_kind,
+                    CamelIMAPXMailbox *mailbox,
+                    CamelIMAPXJobRunSyncFunc run_sync,
+                    CamelIMAPXJobMatchesFunc matches,
+                    CamelIMAPXJobCopyResultFunc copy_result)
+{
+       CamelIMAPXJob *job;
 
-               g_clear_object (&real_job->mailbox);
-               g_mutex_clear (&real_job->mailbox_lock);
+       g_return_val_if_fail (run_sync != NULL, NULL);
 
-               /* Fill the memory with a bit pattern before releasing
-                * it back to the slab allocator, so we can more easily
-                * identify dangling CamelIMAPXJob pointers. */
-               memset (real_job, 0xaa, sizeof (CamelIMAPXRealJob));
+       job = g_new0 (CamelIMAPXJob, 1);
+       job->ref_count = 1;
+       job->job_kind = job_kind;
+       job->mailbox = mailbox ? g_object_ref (mailbox) : NULL;
+       job->run_sync = run_sync;
+       job->matches = matches;
+       job->copy_result = copy_result;
+       job->abort_cancellable = camel_operation_new ();
+       job->is_done = FALSE;
 
-               /* But leave the reference count set to zero, so
-                * CAMEL_IS_IMAPX_JOB can identify it as bad. */
-               real_job->ref_count = 0;
+       g_cond_init (&job->done_cond);
+       g_mutex_init (&job->done_mutex);
 
-               g_slice_free (CamelIMAPXRealJob, real_job);
-       }
+       return job;
 }
 
-gboolean
-camel_imapx_job_check (CamelIMAPXJob *job)
+CamelIMAPXJob *
+camel_imapx_job_ref (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
+       g_return_val_if_fail (job != NULL, NULL);
 
-       real_job = (CamelIMAPXRealJob *) job;
+       g_atomic_int_inc (&job->ref_count);
 
-       return (real_job != NULL && real_job->ref_count > 0);
+       return job;
 }
 
 void
-camel_imapx_job_cancel (CamelIMAPXJob *job)
+camel_imapx_job_unref (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
+       g_return_if_fail (job != NULL);
+
+       if (g_atomic_int_dec_and_test (&job->ref_count)) {
+               if (job->destroy_user_data)
+                       job->destroy_user_data (job->user_data);
 
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+               if (job->result_is_set && job->destroy_result_data)
+                       job->destroy_result_data (job->result_data);
 
-       real_job = (CamelIMAPXRealJob *) job;
+               g_clear_object (&job->mailbox);
+               g_clear_object (&job->abort_cancellable);
+               g_clear_error (&job->result_error);
 
-       g_cancellable_cancel (real_job->cancellable);
+               g_cond_clear (&job->done_cond);
+               g_mutex_clear (&job->done_mutex);
+
+               job->ref_count = 0xdeadbeef;
+
+               g_free (job);
+       }
 }
 
-/**
- * camel_imapx_job_wait:
- * @job: a #CamelIMAPXJob
- * @error: return location for a #GError, or %NULL
- *
- * Blocks until @job completes by way of camel_imapx_job_done().  If @job
- * completed successfully, the function returns %TRUE.  If @job was given
- * a #GError by way of camel_imapx_job_take_error(), or its #GCancellable
- * was cancelled, the function sets @error and returns %FALSE.
- *
- * Returns: whether @job completed successfully
- *
- * Since: 3.10
- **/
-gboolean
-camel_imapx_job_wait (CamelIMAPXJob *job,
-                      GError **error)
+guint32
+camel_imapx_job_get_kind (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
-       GCancellable *cancellable;
-       gulong cancel_id = 0;
-       gboolean success = TRUE;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
-       real_job = (CamelIMAPXRealJob *) job;
-       cancellable = camel_imapx_job_get_cancellable (job);
-
-       if (G_IS_CANCELLABLE (cancellable))
-               cancel_id = g_cancellable_connect (
-                       cancellable,
-                       G_CALLBACK (imapx_job_cancelled_cb),
-                       camel_imapx_job_ref (job),
-                       (GDestroyNotify) camel_imapx_job_unref);
-
-       g_mutex_lock (&real_job->done_mutex);
-       while (!real_job->done_flag && !g_cancellable_is_cancelled (cancellable))
-               g_cond_wait (
-                       &real_job->done_cond,
-                       &real_job->done_mutex);
-       g_mutex_unlock (&real_job->done_mutex);
-
-       if (cancel_id > 0)
-               g_cancellable_disconnect (cancellable, cancel_id);
-
-       /* Cancellation takes priority over other errors. */
-       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
-               success = FALSE;
-       } else if (real_job->error != NULL) {
-               /* Copy the error, don't propagate it.
-                * We want our GError to remain intact. */
-               if (error != NULL) {
-                       g_warn_if_fail (*error == NULL);
-                       *error = g_error_copy (real_job->error);
-               }
-               success = FALSE;
-       }
+       g_return_val_if_fail (job != NULL, CAMEL_IMAPX_JOB_UNKNOWN);
 
-       return success;
+       return job->job_kind;
 }
 
-void
-camel_imapx_job_done (CamelIMAPXJob *job)
+CamelIMAPXMailbox *
+camel_imapx_job_get_mailbox (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       g_return_val_if_fail (job != NULL, NULL);
 
-       real_job = (CamelIMAPXRealJob *) job;
+       return job->mailbox;
+}
 
-       g_mutex_lock (&real_job->mailbox_lock);
-       while (real_job->has_update_locked > 0) {
-               camel_imapx_mailbox_inc_update_count (real_job->guard_mailbox_update, -1);
-               real_job->has_update_locked--;
-       }
-       g_clear_object (&real_job->guard_mailbox_update);
-       g_mutex_unlock (&real_job->mailbox_lock);
+gpointer
+camel_imapx_job_get_user_data (CamelIMAPXJob *job)
+{
+       g_return_val_if_fail (job != NULL, NULL);
 
-       g_mutex_lock (&real_job->done_mutex);
-       real_job->done_flag = TRUE;
-       g_cond_broadcast (&real_job->done_cond);
-       g_mutex_unlock (&real_job->done_mutex);
+       return job->user_data;
 }
 
-gboolean
-camel_imapx_job_run (CamelIMAPXJob *job,
-                     CamelIMAPXServer *is,
-                     GError **error)
+void
+camel_imapx_job_set_user_data (CamelIMAPXJob *job,
+                              gpointer user_data,
+                              GDestroyNotify destroy_user_data)
 {
-       GCancellable *cancellable;
-       gboolean success;
+       g_return_if_fail (job != NULL);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-       g_return_val_if_fail (job->start != NULL, FALSE);
+       if (job->destroy_user_data)
+               job->destroy_user_data (job->user_data);
 
-       cancellable = ((CamelIMAPXRealJob *) job)->cancellable;
+       job->user_data = user_data;
+       job->destroy_user_data = destroy_user_data;
+}
 
-       if (g_cancellable_set_error_if_cancelled (cancellable, error))
-               return FALSE;
+void
+camel_imapx_job_set_result (CamelIMAPXJob *job,
+                           gboolean success,
+                           gpointer result,
+                           const GError *error,
+                           GDestroyNotify destroy_result)
+{
+       g_return_if_fail (job != NULL);
 
-       success = job->start (job, is, cancellable, error);
+       if (job->result_is_set) {
+               if (job->destroy_result_data)
+                       job->destroy_result_data (job->result_data);
+               g_clear_error (&job->result_error);
+       }
 
-       if (success && !job->noreply)
-               success = camel_imapx_job_wait (job, error);
+       job->result_is_set = TRUE;
+       job->result_success = success;
+       job->result_data = result;
+       job->destroy_result_data = destroy_result;
 
-       return success;
+       if (error)
+               job->result_error = g_error_copy (error);
 }
 
+/* This doesn't return whether the job succeeded, but whether the result
+   was set for the job, thus some result copied. All out-arguments are optional. */
 gboolean
-camel_imapx_job_matches (CamelIMAPXJob *job,
-                         CamelIMAPXMailbox *mailbox,
-                         const gchar *uid)
+camel_imapx_job_copy_result (CamelIMAPXJob *job,
+                            gboolean *out_success,
+                            gpointer *out_result,
+                            GError **out_error,
+                            GDestroyNotify *out_destroy_result)
 {
-       /* XXX CamelIMAPXMailbox can be NULL.  I'm less sure about
-        *     the message UID but let's assume that can be NULL too. */
+       g_return_val_if_fail (job != NULL, FALSE);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
+       if (!job->result_is_set)
+               return FALSE;
 
-       if (mailbox != NULL)
-               g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+       if (out_success)
+               *out_success = job->result_success;
 
-       if (job->matches == NULL)
-               return FALSE;
+       if (out_result) {
+               *out_result = NULL;
 
-       return job->matches (job, mailbox, uid);
-}
+               if (job->copy_result) {
+                       job->copy_result (job, job->result_data, out_result);
+               } else if (job->result_data) {
+                       g_warn_if_reached ();
+               }
+       }
 
-gpointer
-camel_imapx_job_get_data (CamelIMAPXJob *job)
-{
-       CamelIMAPXRealJob *real_job;
+       if (out_error) {
+               g_warn_if_fail (*out_error == NULL);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+               if (job->result_error)
+                       *out_error = g_error_copy (job->result_error);
+       }
 
-       real_job = (CamelIMAPXRealJob *) job;
+       if (out_destroy_result)
+               *out_destroy_result = job->destroy_result_data;
 
-       return real_job->data;
+       return TRUE;
 }
 
-void
-camel_imapx_job_set_data (CamelIMAPXJob *job,
-                          gpointer data,
-                          GDestroyNotify destroy_data)
+/* Similar to camel_imapx_job_copy_result() except it gives result data
+   to the caller and unsets (not frees) the data in the job. */
+gboolean
+camel_imapx_job_take_result_data (CamelIMAPXJob *job,
+                                 gpointer *out_result)
 {
-       CamelIMAPXRealJob *real_job;
+       g_return_val_if_fail (job != NULL, FALSE);
 
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       if (!job->result_is_set)
+               return FALSE;
+
+       if (out_result) {
+               *out_result = job->result_data;
+       } else if (job->destroy_result_data) {
+               job->destroy_result_data (job->result_data);
+       }
 
-       real_job = (CamelIMAPXRealJob *) job;
+       job->result_data = NULL;
+       g_clear_error (&job->result_error);
 
-       if (real_job->destroy_data != NULL)
-               real_job->destroy_data (real_job->data);
+       job->result_is_set = FALSE;
 
-       real_job->data = data;
-       real_job->destroy_data = destroy_data;
+       return TRUE;
 }
 
 gboolean
-camel_imapx_job_has_mailbox (CamelIMAPXJob *job,
-                             CamelIMAPXMailbox *mailbox)
+camel_imapx_job_matches (CamelIMAPXJob *job,
+                        CamelIMAPXJob *other_job)
 {
-       CamelIMAPXRealJob *real_job;
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (other_job != NULL, FALSE);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
-
-       if (mailbox != NULL)
-               g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+       if (job->job_kind != other_job->job_kind)
+               return FALSE;
 
-       real_job = (CamelIMAPXRealJob *) job;
+       if (job->mailbox != other_job->mailbox)
+               return FALSE;
 
-       /* Not necessary to lock the mutex since
-        * we're just comparing memory addresses. */
+       if (job->matches)
+               return job->matches (job, other_job);
 
-       return (mailbox == real_job->mailbox);
+       return TRUE;
 }
 
-CamelIMAPXMailbox *
-camel_imapx_job_ref_mailbox (CamelIMAPXJob *job)
+static void
+imapx_job_cancelled_cb (GCancellable *cancellable,
+                       CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
-       CamelIMAPXMailbox *mailbox = NULL;
+       camel_imapx_job_abort (job);
+}
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
+static void
+imapx_job_push_message_cb (CamelOperation *operation,
+                          const gchar *message,
+                          GCancellable *job_cancellable)
+{
+       g_return_if_fail (CAMEL_IS_OPERATION (operation));
+       g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
 
-       real_job = (CamelIMAPXRealJob *) job;
+       camel_operation_push_message (job_cancellable, "%s", message);
+}
 
-       g_mutex_lock (&real_job->mailbox_lock);
+static void
+imapx_job_pop_message_cb (CamelOperation *operation,
+                         GCancellable *job_cancellable)
+{
+       g_return_if_fail (CAMEL_IS_OPERATION (operation));
+       g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
 
-       if (real_job->mailbox != NULL)
-               mailbox = g_object_ref (real_job->mailbox);
+       camel_operation_pop_message (job_cancellable);
+}
 
-       g_mutex_unlock (&real_job->mailbox_lock);
+static void
+imapx_job_progress_cb (CamelOperation *operation,
+                      gint percent,
+                      GCancellable *job_cancellable)
+{
+       g_return_if_fail (CAMEL_IS_OPERATION (operation));
+       g_return_if_fail (CAMEL_IS_OPERATION (job_cancellable));
 
-       return mailbox;
+       camel_operation_progress (job_cancellable, percent);
 }
 
-void
-camel_imapx_job_set_mailbox (CamelIMAPXJob *job,
-                             CamelIMAPXMailbox *mailbox)
+gboolean
+camel_imapx_job_run_sync (CamelIMAPXJob *job,
+                         CamelIMAPXServer *server,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       GError *local_error = NULL;
+       gboolean success = FALSE;
+
+       g_return_val_if_fail (job != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), FALSE);
+       g_return_val_if_fail (job->run_sync != NULL, FALSE);
+
+       g_mutex_lock (&job->done_mutex);
+       job->is_done = FALSE;
+       g_mutex_unlock (&job->done_mutex);
+
+       g_cancellable_reset (job->abort_cancellable);
+
+       if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               gulong cancelled_handler_id = 0;
+               gulong push_message_handler_id = 0;
+               gulong pop_message_handler_id = 0;
+               gulong progress_handler_id = 0;
+
+               /* Proxy signals between job's cancellable and the abort_cancellable */
+               if (cancellable)
+                       cancelled_handler_id = g_cancellable_connect (cancellable,
+                               G_CALLBACK (imapx_job_cancelled_cb), job, NULL);
+
+               if (CAMEL_IS_OPERATION (cancellable)) {
+                       push_message_handler_id = g_signal_connect (job->abort_cancellable, "push-message",
+                               G_CALLBACK (imapx_job_push_message_cb), cancellable);
+                       pop_message_handler_id = g_signal_connect (job->abort_cancellable, "pop-message",
+                               G_CALLBACK (imapx_job_pop_message_cb), cancellable);
+                       progress_handler_id = g_signal_connect (job->abort_cancellable, "progress",
+                               G_CALLBACK (imapx_job_progress_cb), cancellable);
+               }
 
-       real_job = (CamelIMAPXRealJob *) job;
+               success = job->run_sync (job, server, job->abort_cancellable, &local_error);
 
-       if (mailbox != NULL) {
-               g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
-               g_object_ref (mailbox);
+               if (push_message_handler_id)
+                       g_signal_handler_disconnect (job->abort_cancellable, push_message_handler_id);
+               if (pop_message_handler_id)
+                       g_signal_handler_disconnect (job->abort_cancellable, pop_message_handler_id);
+               if (progress_handler_id)
+                       g_signal_handler_disconnect (job->abort_cancellable, progress_handler_id);
+               if (cancelled_handler_id)
+                       g_cancellable_disconnect (cancellable, cancelled_handler_id);
        }
 
-       g_mutex_lock (&real_job->mailbox_lock);
+       if (!g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT))
+               camel_imapx_job_done (job);
 
-       g_clear_object (&real_job->mailbox);
-       real_job->mailbox = mailbox;
+       if (local_error)
+               g_propagate_error (error, local_error);
 
-       g_mutex_unlock (&real_job->mailbox_lock);
+       return success;
 }
 
-GCancellable *
-camel_imapx_job_get_cancellable (CamelIMAPXJob *job)
+void
+camel_imapx_job_done (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
-
-       real_job = (CamelIMAPXRealJob *) job;
+       g_return_if_fail (job != NULL);
 
-       return real_job->cancellable;
+       g_mutex_lock (&job->done_mutex);
+       job->is_done = TRUE;
+       g_cond_broadcast (&job->done_cond);
+       g_mutex_unlock (&job->done_mutex);
 }
 
-/**
- * camel_imapx_job_take_error:
- * @job: a #CamelIMAPXJob
- * @error: a #GError
- *
- * Takes over the caller's ownership of @error, so the caller does not
- * need to free it any more.  Call this when a #CamelIMAPXCommand fails
- * and the @job is to be aborted.
- *
- * The @error will be returned to callers of camel_imapx_job_wait() or
- * camel_imapx_job_run().
- *
- * Since: 3.10
- **/
 void
-camel_imapx_job_take_error (CamelIMAPXJob *job,
-                            GError *error)
+camel_imapx_job_abort (CamelIMAPXJob *job)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-       g_return_if_fail (error != NULL);
+       g_return_if_fail (job != NULL);
 
-       real_job = (CamelIMAPXRealJob *) job;
-       g_return_if_fail (real_job->error != error);
-
-       g_clear_error (&real_job->error);
-
-       real_job->error = error;  /* takes ownership */
+       g_cancellable_cancel (job->abort_cancellable);
 }
 
-/**
- * camel_imapx_job_set_error_if_failed:
- * @job: a #CamelIMAPXJob
- * @error: a location for a #GError
- *
- * Sets @error to a new GError instance and returns TRUE, if the job has set
- * an error or when it was cancelled.
- *
- * Returns: Whether the job failed.
- *
- * Since: 3.16
- **/
-gboolean
-camel_imapx_job_set_error_if_failed (CamelIMAPXJob *job,
-                                    GError **error)
+static void
+camel_imapx_job_wait_cancelled_cb (GCancellable *cancellable,
+                                  gpointer user_data)
 {
-       CamelIMAPXRealJob *real_job;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), TRUE);
-       g_return_val_if_fail (error != NULL, TRUE);
+       CamelIMAPXJob *job = user_data;
 
-       real_job = (CamelIMAPXRealJob *) job;
+       g_return_if_fail (job != NULL);
 
-       if (real_job->error) {
-               g_propagate_error (error, g_error_copy (real_job->error));
-               return TRUE;
-       }
-
-       return g_cancellable_set_error_if_cancelled (real_job->cancellable, error);
+       g_mutex_lock (&job->done_mutex);
+       g_cond_broadcast (&job->done_cond);
+       g_mutex_unlock (&job->done_mutex);
 }
 
 void
-camel_imapx_job_inc_update_locked (CamelIMAPXJob *job,
-                                  CamelIMAPXMailbox *mailbox)
+camel_imapx_job_wait_sync (CamelIMAPXJob *job,
+                          GCancellable *cancellable)
 {
-       CamelIMAPXRealJob *real_job;
+       gulong handler_id = 0;
 
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
+       g_return_if_fail (job != NULL);
 
-       real_job = (CamelIMAPXRealJob *) job;
+       if (g_cancellable_is_cancelled (cancellable))
+               return;
 
-       g_mutex_lock (&real_job->mailbox_lock);
-       if (real_job->guard_mailbox_update) {
-               g_warn_if_fail (real_job->guard_mailbox_update == mailbox);
-       } else {
-               real_job->guard_mailbox_update = g_object_ref (mailbox);
+       if (cancellable)
+               handler_id = g_cancellable_connect (cancellable, G_CALLBACK 
(camel_imapx_job_wait_cancelled_cb), job, NULL);
+
+       g_mutex_lock (&job->done_mutex);
+       while (!job->is_done && !g_cancellable_is_cancelled (cancellable)) {
+               g_cond_wait (&job->done_cond, &job->done_mutex);
        }
-       real_job->has_update_locked++;
-       g_mutex_unlock (&real_job->mailbox_lock);
+       g_mutex_unlock (&job->done_mutex);
+
+       if (handler_id)
+               g_cancellable_disconnect (cancellable, handler_id);
 }
diff --git a/camel/providers/imapx/camel-imapx-job.h b/camel/providers/imapx/camel-imapx-job.h
index b82e36a..ccad91b 100644
--- a/camel/providers/imapx/camel-imapx-job.h
+++ b/camel/providers/imapx/camel-imapx-job.h
@@ -20,72 +20,102 @@
 
 #include "camel-imapx-server.h"
 
-#define CAMEL_IS_IMAPX_JOB(job) \
-       (camel_imapx_job_check (job))
-
 G_BEGIN_DECLS
 
 typedef struct _CamelIMAPXJob CamelIMAPXJob;
 
-struct _uidset_state {
-       gint entries, uids;
-       gint total, limit;
-       guint32 start;
-       guint32 last;
-};
+struct _CamelIMAPXJob;
 
-struct _CamelIMAPXJob {
-       /* Whether to pop a status message off the
-        * GCancellable when the job is finalized. */
-       gboolean pop_operation_msg;
+typedef enum {
+       CAMEL_IMAPX_JOB_UNKNOWN = 0,
+       CAMEL_IMAPX_JOB_CAPABILITY,
+       CAMEL_IMAPX_JOB_STARTTLS,
+       CAMEL_IMAPX_JOB_AUTHENTICATE,
+       CAMEL_IMAPX_JOB_LOGIN,
+       CAMEL_IMAPX_JOB_NAMESPACE,
+       CAMEL_IMAPX_JOB_SELECT,
+       CAMEL_IMAPX_JOB_STATUS,
+       CAMEL_IMAPX_JOB_ENABLE,
+       CAMEL_IMAPX_JOB_NOTIFY,
+       CAMEL_IMAPX_JOB_GET_MESSAGE,
+       CAMEL_IMAPX_JOB_SYNC_MESSAGE,
+       CAMEL_IMAPX_JOB_APPEND_MESSAGE,
+       CAMEL_IMAPX_JOB_COPY_MESSAGE,
+       CAMEL_IMAPX_JOB_MOVE_MESSAGE,
+       CAMEL_IMAPX_JOB_FETCH_NEW_MESSAGES,
+       CAMEL_IMAPX_JOB_REFRESH_INFO,
+       CAMEL_IMAPX_JOB_SYNC_CHANGES,
+       CAMEL_IMAPX_JOB_EXPUNGE,
+       CAMEL_IMAPX_JOB_NOOP,
+       CAMEL_IMAPX_JOB_IDLE,
+       CAMEL_IMAPX_JOB_DONE,
+       CAMEL_IMAPX_JOB_LIST,
+       CAMEL_IMAPX_JOB_LSUB,
+       CAMEL_IMAPX_JOB_CREATE_MAILBOX,
+       CAMEL_IMAPX_JOB_DELETE_MAILBOX,
+       CAMEL_IMAPX_JOB_RENAME_MAILBOX,
+       CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX,
+       CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX,
+       CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO,
+       CAMEL_IMAPX_JOB_UID_SEARCH,
+       CAMEL_IMAPX_JOB_LAST
+} CamelIMAPXJobKind;
 
-       gboolean        (*start)                (CamelIMAPXJob *job,
-                                                CamelIMAPXServer *is,
-                                                GCancellable *cancellable,
-                                                GError **error);
-       gboolean        (*matches)              (CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox,
-                                                const gchar *uid);
+typedef const gchar *  (* CamelIMAPXJobGetKindNameFunc)(guint32 job_kind);
 
-       guint noreply:1;        /* dont wait for reply */
-       guint32 type;           /* operation type */
-       gint pri;               /* the command priority */
-       volatile gint commands; /* counts how many commands are outstanding */
-};
+const gchar *  camel_imapx_job_get_kind_name   (guint32 job_kind);
+void           camel_imapx_job_register_get_kind_name_func
+                                               (CamelIMAPXJobGetKindNameFunc get_kind_name);
+void           camel_imapx_job_unregister_get_kind_name_func
+                                               (CamelIMAPXJobGetKindNameFunc get_kind_name);
 
-CamelIMAPXJob *        camel_imapx_job_new             (GCancellable *cancellable);
+typedef gboolean       (* CamelIMAPXJobRunSyncFunc)    (CamelIMAPXJob *job,
+                                                        CamelIMAPXServer *server,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+typedef gboolean       (* CamelIMAPXJobMatchesFunc)    (CamelIMAPXJob *job,
+                                                        CamelIMAPXJob *other_job);
+typedef void           (* CamelIMAPXJobCopyResultFunc) (CamelIMAPXJob *job,
+                                                        gconstpointer set_result,
+                                                        gpointer *out_result);
+
+CamelIMAPXJob *        camel_imapx_job_new             (guint32 job_kind,
+                                                CamelIMAPXMailbox *mailbox,
+                                                CamelIMAPXJobRunSyncFunc run_sync,
+                                                CamelIMAPXJobMatchesFunc matches,
+                                                CamelIMAPXJobCopyResultFunc copy_result);
 CamelIMAPXJob *        camel_imapx_job_ref             (CamelIMAPXJob *job);
 void           camel_imapx_job_unref           (CamelIMAPXJob *job);
-gboolean       camel_imapx_job_check           (CamelIMAPXJob *job);
-void           camel_imapx_job_cancel          (CamelIMAPXJob *job);
-gboolean       camel_imapx_job_wait            (CamelIMAPXJob *job,
-                                                GError **error);
-void           camel_imapx_job_done            (CamelIMAPXJob *job);
-gboolean       camel_imapx_job_run             (CamelIMAPXJob *job,
-                                                CamelIMAPXServer *is,
-                                                GError **error);
-gboolean       camel_imapx_job_matches         (CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox,
-                                                const gchar *uid);
-gpointer       camel_imapx_job_get_data        (CamelIMAPXJob *job);
-void           camel_imapx_job_set_data        (CamelIMAPXJob *job,
-                                                gpointer data,
-                                                GDestroyNotify destroy_data);
-gboolean       camel_imapx_job_has_mailbox     (CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox);
+guint32                camel_imapx_job_get_kind        (CamelIMAPXJob *job);
 CamelIMAPXMailbox *
-               camel_imapx_job_ref_mailbox     (CamelIMAPXJob *job);
-void           camel_imapx_job_set_mailbox     (CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox);
-GCancellable * camel_imapx_job_get_cancellable (CamelIMAPXJob *job);
-void           camel_imapx_job_take_error      (CamelIMAPXJob *job,
-                                                GError *error);
-gboolean       camel_imapx_job_set_error_if_failed
+               camel_imapx_job_get_mailbox     (CamelIMAPXJob *job);
+gpointer       camel_imapx_job_get_user_data   (CamelIMAPXJob *job);
+void           camel_imapx_job_set_user_data   (CamelIMAPXJob *job,
+                                                gpointer user_data,
+                                                GDestroyNotify destroy_user_data);
+void           camel_imapx_job_set_result      (CamelIMAPXJob *job,
+                                                gboolean success,
+                                                gpointer result,
+                                                const GError *error,
+                                                GDestroyNotify destroy_result);
+gboolean       camel_imapx_job_copy_result     (CamelIMAPXJob *job,
+                                                gboolean *out_success,
+                                                gpointer *out_result,
+                                                GError **out_error,
+                                                GDestroyNotify *out_destroy_result);
+gboolean       camel_imapx_job_take_result_data
                                                (CamelIMAPXJob *job,
+                                                gpointer *out_result);
+gboolean       camel_imapx_job_matches         (CamelIMAPXJob *job,
+                                                CamelIMAPXJob *other_job);
+gboolean       camel_imapx_job_run_sync        (CamelIMAPXJob *job,
+                                                CamelIMAPXServer *server,
+                                                GCancellable *cancellable,
                                                 GError **error);
-void           camel_imapx_job_inc_update_locked
-                                               (CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox);
+void           camel_imapx_job_done            (CamelIMAPXJob *job);
+void           camel_imapx_job_abort           (CamelIMAPXJob *job);
+void           camel_imapx_job_wait_sync       (CamelIMAPXJob *job,
+                                                GCancellable *cancellable);
 
 G_END_DECLS
 
diff --git a/camel/providers/imapx/camel-imapx-search.c b/camel/providers/imapx/camel-imapx-search.c
index f2dd1c8..b1359f0 100644
--- a/camel/providers/imapx/camel-imapx-search.c
+++ b/camel/providers/imapx/camel-imapx-search.c
@@ -173,33 +173,16 @@ imapx_search_process_criteria (CamelSExp *sexp,
 
        if (mailbox != NULL) {
                CamelIMAPXStore *imapx_store;
-               CamelIMAPXServer *imapx_server;
-               const gchar *folder_name;
+               CamelIMAPXConnManager *conn_man;
 
                imapx_store = camel_imapx_search_ref_store (imapx_search);
 
                /* there should always be one, held by one of the callers of this function */
                g_warn_if_fail (imapx_store != NULL);
 
-               folder_name = camel_folder_get_full_name (search->folder);
-               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, 
imapx_search->priv->cancellable, &local_error);
-               if (imapx_server) {
-                       uids = camel_imapx_server_uid_search (imapx_server, mailbox, criteria->str, 
imapx_search->priv->cancellable, &local_error);
-                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, folder_name);
-
-                       while (!uids && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                               g_clear_error (&local_error);
-                               g_clear_object (&imapx_server);
-
-                               imapx_server = camel_imapx_store_ref_server (imapx_store, folder_name, TRUE, 
imapx_search->priv->cancellable, &local_error);
-                               if (imapx_server) {
-                                       uids = camel_imapx_server_uid_search (imapx_server, mailbox, 
criteria->str, imapx_search->priv->cancellable, &local_error);
-                                       camel_imapx_store_folder_op_done (imapx_store, imapx_server, 
folder_name);
-                               }
-                       }
-               }
+               conn_man = camel_imapx_store_get_conn_manager (imapx_store);
+               uids = camel_imapx_conn_manager_uid_search_sync (conn_man, mailbox, criteria->str, 
imapx_search->priv->cancellable, &local_error);
 
-               g_clear_object (&imapx_server);
                g_clear_object (&imapx_store);
                g_object_unref (mailbox);
        }
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 12c977c..d97b618 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -55,21 +55,22 @@
 #define c(...) camel_imapx_debug(command, __VA_ARGS__)
 #define e(...) camel_imapx_debug(extra, __VA_ARGS__)
 
-#define QUEUE_LOCK(x) g_rec_mutex_lock (&(x)->queue_lock)
-#define QUEUE_UNLOCK(x) g_rec_mutex_unlock (&(x)->queue_lock)
+#define COMMAND_LOCK(x) g_rec_mutex_lock (&(x)->priv->command_lock)
+#define COMMAND_UNLOCK(x) g_rec_mutex_unlock (&(x)->priv->command_lock)
 
 /* Try pipelining fetch requests, 'in bits' */
 #define MULTI_SIZE (32768 * 8)
 
-/* How many outstanding commands do we allow before we just queue them? */
-#define MAX_COMMANDS (10)
-
 #define MAX_COMMAND_LEN 1000
 
 /* Ping the server after a period of inactivity to avoid being logged off.
  * Using a 29 minute inactivity timeout as recommended in RFC 2177 (IDLE). */
 #define INACTIVITY_TIMEOUT_SECONDS (29 * 60)
 
+/* Number of seconds to remain in PENDING state waiting for other commands
+   to be queued, before actually sending IDLE */
+#define IMAPX_IDLE_WAIT_SECONDS 2
+
 #ifdef G_OS_WIN32
 #ifdef gmtime_r
 #undef gmtime_r
@@ -81,91 +82,6 @@
 
 G_DEFINE_QUARK (camel-imapx-server-error-quark, camel_imapx_server_error)
 
-/* Job-specific structs */
-typedef struct _GetMessageData GetMessageData;
-typedef struct _RefreshInfoData RefreshInfoData;
-typedef struct _SyncChangesData SyncChangesData;
-typedef struct _AppendMessageData AppendMessageData;
-typedef struct _CopyMessagesData CopyMessagesData;
-typedef struct _ListData ListData;
-typedef struct _MailboxData MailboxData;
-typedef struct _SearchData SearchData;
-
-struct _GetMessageData {
-       /* in: uid requested */
-       gchar *uid;
-       CamelDataCache *message_cache;
-       /* in/out: message content stream output */
-       GIOStream *stream;
-       /* working variables */
-       gsize body_offset;
-       gsize fetch_offset;
-       gsize size;
-       gboolean use_multi_fetch;
-};
-
-struct _RefreshInfoData {
-       /* array of refresh info's */
-       GArray *infos;
-       /* used for building uidset stuff */
-       gint index;
-       gint last_index;
-       CamelFetchType fetch_type;
-       gboolean update_unseen;
-       gboolean scan_changes;
-       struct _uidset_state uidset;
-       /* changes during refresh */
-       CamelFolderChangeInfo *changes;
-};
-
-struct _SyncChangesData {
-       CamelFolder *folder;
-       GPtrArray *changed_uids;
-       gboolean own_allocated_changed_uids;
-       guint32 on_set;
-       guint32 off_set;
-       GArray *on_user; /* imapx_flag_change */
-       GArray *off_user;
-       gint unread_change;
-
-       /* Remove recently set DELETED flags before synchronizing.
-        * This is only set when using a real Trash folder and NOT
-        * about to expunge the folder. */
-       gboolean remove_deleted_flags;
-};
-
-struct _AppendMessageData {
-       gchar *path;
-       CamelMessageInfo *info;
-       gchar *appended_uid;
-       time_t date_time; /* message's date/time, in UTC */
-};
-
-struct _CopyMessagesData {
-       CamelIMAPXMailbox *destination;
-       GPtrArray *uids;
-       gboolean delete_originals;
-       gboolean use_move_command;
-       gboolean remove_deleted_flags;
-       gint index;
-       gint last_index;
-       struct _uidset_state uidset;
-};
-
-struct _ListData {
-       gchar *pattern;
-};
-
-struct _MailboxData {
-       CamelIMAPXMailbox *mailbox;
-       gchar *mailbox_name;
-};
-
-struct _SearchData {
-       gchar *criteria;
-       GArray *results;
-};
-
 /* untagged response handling */
 
 /* May need to turn this into separate,
@@ -310,30 +226,9 @@ static const CamelIMAPXUntaggedRespHandlerDesc _untagged_descr[] = {
        {CAMEL_IMAPX_UNTAGGED_VANISHED, imapx_untagged_vanished, NULL, TRUE},
 };
 
-typedef enum {
-       IMAPX_IDLE_OFF,
-       IMAPX_IDLE_PENDING,     /* Queue is idle; waiting to send IDLE command
-                                  soon if nothing more interesting happens */
-       IMAPX_IDLE_ISSUED,      /* Sent IDLE command; waiting for response */
-       IMAPX_IDLE_STARTED,     /* IDLE continuation received; IDLE active */
-       IMAPX_IDLE_CANCEL,      /* Cancelled from ISSUED state; need to send
-                                  DONE as soon as we receive continuation */
-       IMAPX_IDLE_WAIT_DONE    /* DONE was issued, waiting for a confirmation response */
-} CamelIMAPXIdleState;
-
-#define IMAPX_IDLE_DWELL_TIME  2 /* Number of seconds to remain in PENDING
-                                    state waiting for other commands to be
-                                    queued, before actually sending IDLE */
-
-typedef enum {
-       IMAPX_IDLE_STOP_NOOP,
-       IMAPX_IDLE_STOP_WAIT_DONE,
-       IMAPX_IDLE_STOP_SUCCESS,
-       IMAPX_IDLE_STOP_ERROR
-} CamelIMAPXIdleStopResult;
-
 struct _CamelIMAPXServerPrivate {
        GWeakRef store;
+       GCancellable *cancellable; /* the main connection cancellable, it's cancelled on disconnect */
 
        CamelIMAPXServerUntaggedContext *context;
        GHashTable *untagged_handlers;
@@ -345,21 +240,12 @@ struct _CamelIMAPXServerPrivate {
        GSubprocess *subprocess;
        GMutex stream_lock;
 
-       GThread *parser_thread;
-       GMainLoop *parser_main_loop;
-       GMainContext *parser_main_context;
-       GWeakRef parser_cancellable;
-
-       GMutex shutdown_error_lock;
-       GError *shutdown_error;
-
        GSource *inactivity_timeout;
        GMutex inactivity_timeout_lock;
 
        /* Info on currently selected folder. */
        GMutex select_lock;
        GWeakRef select_mailbox;
-       GWeakRef select_closing;
        GWeakRef select_pending;
        CamelFolderChangeInfo *changes;
 
@@ -392,14 +278,32 @@ struct _CamelIMAPXServerPrivate {
        GMainLoop *idle_main_loop;
        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;
+       CamelIMAPXMailbox *idle_mailbox;
+       GCancellable *idle_cancellable;
+       gboolean idle_running;
 
        gboolean is_cyrus;
+
+       /* Info about the current connection */
+       struct _capability_info *cinfo;
+
+       GRecMutex command_lock;
+
+       gchar tagprefix;
+       guint32 state;
+
+       gboolean use_qresync;
+
+       CamelIMAPXCommand *current_command;
+       CamelIMAPXCommand *continuation_command;
+
+       /* operation data */
+       GIOStream *get_message_stream;
+
+       CamelIMAPXMailbox *fetch_changes_mailbox; /* not referenced */
+       CamelFolder *fetch_changes_folder; /* not referenced */
+       GHashTable *fetch_changes_infos; /* gchar *uid ~> FetchChangesInfo-s */
+       gint64 fetch_changes_last_progress; /* when was called last progress */
 };
 
 enum {
@@ -408,25 +312,12 @@ enum {
 };
 
 enum {
-       MAILBOX_SELECT,
-       MAILBOX_CLOSED,
-       SHUTDOWN,
+       REFRESH_MAILBOX,
        LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL];
 
-static void    imapx_uidset_init               (struct _uidset_state *ss,
-                                                gint total,
-                                                gint limit);
-static gint    imapx_uidset_done               (struct _uidset_state *ss,
-                                                CamelIMAPXCommand *ic);
-static gint    imapx_uidset_add                (struct _uidset_state *ss,
-                                                CamelIMAPXCommand *ic,
-                                                const gchar *uid);
-
-static gboolean        imapx_command_idle_stop         (CamelIMAPXServer *is,
-                                                GError **error);
 static gboolean        imapx_continuation              (CamelIMAPXServer *is,
                                                 GInputStream *input_stream,
                                                 GOutputStream *output_stream,
@@ -434,11 +325,6 @@ static gboolean    imapx_continuation              (CamelIMAPXServer *is,
                                                 GCancellable *cancellable,
                                                 GError **error);
 static void    imapx_disconnect                (CamelIMAPXServer *is);
-static gboolean        imapx_is_command_queue_empty    (CamelIMAPXServer *is);
-static gint    imapx_uid_cmp                   (gconstpointer ap,
-                                                gconstpointer bp,
-                                                gpointer data);
-static void    imapx_command_start_next        (CamelIMAPXServer *is);
 
 /* states for the connection? */
 enum {
@@ -450,33 +336,6 @@ enum {
        IMAPX_SELECTED
 };
 
-struct _refresh_info {
-       gchar *uid;
-       gboolean exists;
-       guint32 server_flags;
-       CamelFlag *server_user_flags;
-};
-
-enum {
-       IMAPX_JOB_GET_MESSAGE = 1 << 0,
-       IMAPX_JOB_APPEND_MESSAGE = 1 << 1,
-       IMAPX_JOB_COPY_MESSAGE = 1 << 2,
-       IMAPX_JOB_FETCH_NEW_MESSAGES = 1 << 3,
-       IMAPX_JOB_REFRESH_INFO = 1 << 4,
-       IMAPX_JOB_SYNC_CHANGES = 1 << 5,
-       IMAPX_JOB_EXPUNGE = 1 << 6,
-       IMAPX_JOB_NOOP = 1 << 7,
-       IMAPX_JOB_IDLE = 1 << 8,
-       IMAPX_JOB_LIST = 1 << 9,
-       IMAPX_JOB_CREATE_MAILBOX = 1 << 10,
-       IMAPX_JOB_DELETE_MAILBOX = 1 << 11,
-       IMAPX_JOB_RENAME_MAILBOX = 1 << 12,
-       IMAPX_JOB_SUBSCRIBE_MAILBOX = 1 << 13,
-       IMAPX_JOB_UNSUBSCRIBE_MAILBOX = 1 << 14,
-       IMAPX_JOB_UPDATE_QUOTA_INFO = 1 << 15,
-       IMAPX_JOB_UID_SEARCH = 1 << 16
-};
-
 /* Mailbox management operations have highest priority
  * since we know for sure that they are user triggered. */
 enum {
@@ -501,55 +360,34 @@ struct _imapx_flag_change {
        gchar *name;
 };
 
-static CamelIMAPXJob *
-               imapx_match_active_job          (CamelIMAPXServer *is,
-                                                guint32 type,
-                                                const gchar *uid);
-static gboolean        imapx_job_fetch_new_messages_start
-                                               (CamelIMAPXJob *job,
-                                                CamelIMAPXServer *is,
-                                                GCancellable *cancellable,
-                                                GError **error);
 static gint    imapx_refresh_info_uid_cmp      (gconstpointer ap,
                                                 gconstpointer bp,
                                                 gboolean ascending);
 static gint    imapx_uids_array_cmp            (gconstpointer ap,
                                                 gconstpointer bp);
-static gboolean        imapx_server_sync_changes       (CamelIMAPXServer *is,
-                                                CamelIMAPXMailbox *mailbox,
-                                                guint32 job_type,
-                                                gint pri,
-                                                GCancellable *cancellable,
-                                                GError **error);
 static void    imapx_sync_free_user            (GArray *user_set);
 
-static gboolean        imapx_command_copy_messages_step_start
-                                               (CamelIMAPXServer *is,
-                                                CamelIMAPXJob *job,
-                                                gint index,
-                                                GError **error);
-static gboolean        imapx_job_noop_start            (CamelIMAPXJob *job,
-                                                CamelIMAPXServer *is,
-                                                GCancellable *cancellable,
-                                                GError **error);
-
 static gboolean        imapx_in_idle                   (CamelIMAPXServer *is);
-static gboolean        imapx_use_idle          (CamelIMAPXServer *is);
-static void    imapx_start_idle                (CamelIMAPXServer *is);
-static CamelIMAPXIdleStopResult
-               imapx_stop_idle                 (CamelIMAPXServer *is,
-                                                GError **error);
-static gboolean        camel_imapx_server_idle         (CamelIMAPXServer *is,
-                                                CamelIMAPXMailbox *mailbox,
-                                                GCancellable *cancellable,
-                                                GError **error);
-
-static void    imapx_maybe_select              (CamelIMAPXServer *is,
-                                                CamelIMAPXJob *job,
-                                                CamelIMAPXMailbox *mailbox);
+static gboolean        imapx_use_idle                  (CamelIMAPXServer *is);
 
 G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, G_TYPE_OBJECT)
 
+typedef struct _FetchChangesInfo {
+       guint32 server_flags;
+       CamelFlag *server_user_flags;
+} FetchChangesInfo;
+
+static void
+fetch_changes_info_free (gpointer ptr)
+{
+       FetchChangesInfo *nfo = ptr;
+
+       if (nfo) {
+               camel_flag_list_free (&nfo->server_user_flags);
+               g_free (nfo);
+       }
+}
+
 static GWeakRef *
 imapx_weak_ref_new (gpointer object)
 {
@@ -576,169 +414,6 @@ imapx_weak_ref_free (GWeakRef *weak_ref)
        g_slice_free (GWeakRef, weak_ref);
 }
 
-static void
-imapx_server_set_shutdown_error (CamelIMAPXServer *imapx_server,
-                                const GError *error)
-{
-       g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
-       if (error != imapx_server->priv->shutdown_error) {
-               g_clear_error (&imapx_server->priv->shutdown_error);
-               if (error)
-                       imapx_server->priv->shutdown_error = g_error_copy (error);
-       }
-
-       g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-}
-
-static GError *
-imapx_server_dup_shutdown_error (CamelIMAPXServer *imapx_server)
-{
-       GError *error = NULL;
-
-       g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
-
-       if (imapx_server->priv->shutdown_error)
-               error = g_error_copy (imapx_server->priv->shutdown_error);
-
-       g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
-
-       return error;
-}
-
-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));
-       if (!camel_imapx_mailbox_is_inbox (camel_imapx_mailbox_get_name (mailbox)))
-               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,
@@ -796,125 +471,19 @@ create_initial_untagged_handler_table (void)
        return uh;
 }
 
-static void
-get_message_data_free (GetMessageData *data)
-{
-       g_free (data->uid);
-
-       g_clear_object (&data->message_cache);
-       g_clear_object (&data->stream);
-
-       g_slice_free (GetMessageData, data);
-}
-
-static void
-refresh_info_data_infos_free (RefreshInfoData *data)
-{
-       gint ii;
-
-       if (!data || !data->infos)
-               return;
-
-       for (ii = 0; ii < data->infos->len; ii++) {
-               struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, ii);
-
-               camel_flag_list_free (&r->server_user_flags);
-               g_free (r->uid);
-       }
-
-       g_array_free (data->infos, TRUE);
-       data->infos = NULL;
-}
-
-static void
-refresh_info_data_free (RefreshInfoData *data)
-{
-       if (data->changes != NULL)
-               camel_folder_change_info_free (data->changes);
-
-       refresh_info_data_infos_free (data);
-
-       g_slice_free (RefreshInfoData, data);
-}
-
-static void
-sync_changes_data_free (SyncChangesData *data)
-{
-       if (data->folder != NULL) {
-               if (!data->own_allocated_changed_uids)
-                       camel_folder_free_uids (data->folder, data->changed_uids);
-               g_object_unref (data->folder);
-       }
-
-       if (data->own_allocated_changed_uids && data->changed_uids) {
-               g_ptr_array_foreach (data->changed_uids, (GFunc) camel_pstring_free, NULL);
-               g_ptr_array_free (data->changed_uids, TRUE);
-       }
-
-       imapx_sync_free_user (data->on_user);
-       imapx_sync_free_user (data->off_user);
-
-       g_slice_free (SyncChangesData, data);
-}
-
-static void
-append_message_data_free (AppendMessageData *data)
-{
-       g_free (data->path);
-       g_free (data->appended_uid);
-
-       camel_message_info_unref (data->info);
-
-       g_slice_free (AppendMessageData, data);
-}
-
-static void
-copy_messages_data_free (CopyMessagesData *data)
-{
-       g_clear_object (&data->destination);
-
-       if (data->uids != NULL) {
-               g_ptr_array_foreach (data->uids, (GFunc) g_free, NULL);
-               g_ptr_array_free (data->uids, TRUE);
-       }
-
-       g_slice_free (CopyMessagesData, data);
-}
-
-static void
-list_data_free (ListData *data)
-{
-       g_free (data->pattern);
-
-       g_slice_free (ListData, data);
-}
-
-static void
-mailbox_data_free (MailboxData *data)
-{
-       g_clear_object (&data->mailbox);
-       g_free (data->mailbox_name);
-
-       g_slice_free (MailboxData, data);
-}
-
-static void
-search_data_free (SearchData *data)
-{
-       g_free (data->criteria);
-
-       if (data->results != NULL)
-               g_array_unref (data->results);
-
-       g_slice_free (SearchData, data);
-}
+struct _uidset_state {
+       gint entries, uids;
+       gint total, limit;
+       guint32 start;
+       guint32 last;
+};
 
 /*
   this creates a uid (or sequence number) set directly into a command,
   if total is set, then we break it up into total uids. (i.e. command time)
   if limit is set, then we break it up into limit entries (i.e. command length)
 */
-void
+static void
 imapx_uidset_init (struct _uidset_state *ss,
                    gint total,
                    gint limit)
@@ -927,14 +496,19 @@ imapx_uidset_init (struct _uidset_state *ss,
        ss->limit = limit;
 }
 
-gboolean
+static gboolean
 imapx_uidset_done (struct _uidset_state *ss,
                    CamelIMAPXCommand *ic)
 {
        gint ret = FALSE;
 
-       if (ss->last != 0 && ss->last != ss->start) {
-               camel_imapx_command_add (ic, ":%d", ss->last);
+       if (ss->last != 0) {
+               if (ss->entries > 0)
+                       camel_imapx_command_add (ic, ",");
+               if (ss->last == ss->start)
+                       camel_imapx_command_add (ic, "%d", ss->last);
+               else
+                       camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
        }
 
        ret = ss->last != 0;
@@ -947,7 +521,7 @@ imapx_uidset_done (struct _uidset_state *ss,
        return ret;
 }
 
-gint
+static gint
 imapx_uidset_add (struct _uidset_state *ss,
                   CamelIMAPXCommand *ic,
                   const gchar *uid)
@@ -960,33 +534,41 @@ imapx_uidset_add (struct _uidset_state *ss,
 
        ss->uids++;
 
-       e (ic->is->tagprefix, "uidset add '%s'\n", uid);
+       e (ic->is->priv->tagprefix, "uidset add '%s'\n", uid);
 
        if (ss->last == 0) {
-               e (ic->is->tagprefix, " start\n");
-               camel_imapx_command_add (ic, "%d", uidn);
-               ss->entries++;
+               e (ic->is->priv->tagprefix, " start\n");
                ss->start = uidn;
+               ss->last = uidn;
        } else {
-               if (ss->last != uidn - 1) {
-                       if (ss->last == ss->start) {
-                               e (ic->is->tagprefix, " ,next\n");
-                               camel_imapx_command_add (ic, ",%d", uidn);
-                               ss->entries++;
-                       } else {
-                               e (ic->is->tagprefix, " :range\n");
-                               camel_imapx_command_add (ic, ":%d,%d", ss->last, uidn);
-                               ss->entries+=2;
-                       }
+               if (ss->start - 1 == uidn) {
                        ss->start = uidn;
+               } else {
+                       if (ss->last != uidn - 1) {
+                               if (ss->last == ss->start) {
+                                       e (ic->is->priv->tagprefix, " ,next\n");
+                                       if (ss->entries > 0)
+                                               camel_imapx_command_add (ic, ",");
+                                       camel_imapx_command_add (ic, "%d", ss->start);
+                                       ss->entries++;
+                               } else {
+                                       e (ic->is->priv->tagprefix, " :range\n");
+                                       if (ss->entries > 0)
+                                               camel_imapx_command_add (ic, ",");
+                                       camel_imapx_command_add (ic, "%d:%d", ss->start, ss->last);
+                                       ss->entries += 2;
+                               }
+                               ss->start = uidn;
+                       }
+
+                       ss->last = uidn;
                }
        }
 
-       ss->last = uidn;
-
        if ((ss->limit && ss->entries >= ss->limit)
+           || (ss->limit && ss->uids >= ss->limit)
            || (ss->total && ss->uids >= ss->total)) {
-               e (ic->is->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
+               e (ic->is->priv->tagprefix, " done, %d entries, %d uids\n", ss->entries, ss->uids);
                if (!imapx_uidset_done (ss, ic))
                        return -1;
                return 1;
@@ -995,71 +577,6 @@ imapx_uidset_add (struct _uidset_state *ss,
        return 0;
 }
 
-static gboolean
-imapx_register_job (CamelIMAPXServer *is,
-                    CamelIMAPXJob *job,
-                    GError **error)
-{
-       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 if (is->state <= IMAPX_SHUTDOWN) {
-               e (is->tagprefix, "Server is shutdown/disconnected, try reconnect.");
-               g_set_error (error,
-                       CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
-                       _("Not authenticated"));
-               return FALSE;
-       } else {
-               e (is->tagprefix, "Not connected yet, maybe user cancelled jobs earlier?");
-               g_set_error (
-                       error, CAMEL_SERVICE_ERROR,
-                       CAMEL_SERVICE_ERROR_NOT_CONNECTED,
-                       _("Not authenticated"));
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static void
-imapx_unregister_job (CamelIMAPXServer *is,
-                      CamelIMAPXJob *job)
-{
-       camel_imapx_job_done (job);
-
-       QUEUE_LOCK (is);
-
-       if (g_queue_remove (&is->jobs, job)) {
-               imapx_server_job_removed (is, job);
-               camel_imapx_job_unref (job);
-       }
-
-       imapx_command_start_next (is);
-
-       QUEUE_UNLOCK (is);
-}
-
-static gboolean
-imapx_submit_job (CamelIMAPXServer *is,
-                  CamelIMAPXJob *job,
-                  GError **error)
-{
-       gboolean success;
-
-       if (!imapx_register_job (is, job, error))
-               return FALSE;
-
-       success = camel_imapx_job_run (job, is, error);
-
-       if (!success)
-               imapx_unregister_job (is, job);
-
-       return success;
-}
-
 static CamelFolder *
 imapx_server_ref_folder (CamelIMAPXServer *is,
                          CamelIMAPXMailbox *mailbox)
@@ -1103,19 +620,19 @@ imapx_server_stash_command_arguments (CamelIMAPXServer *is)
        /* Stash some reusable capability-based command arguments. */
 
        buffer = g_string_new ("MESSAGES UNSEEN UIDVALIDITY UIDNEXT");
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, CONDSTORE))
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, CONDSTORE))
                g_string_append (buffer, " HIGHESTMODSEQ");
        g_free (is->priv->status_data_items);
        is->priv->status_data_items = g_string_free (buffer, FALSE);
 
        g_free (is->priv->list_return_opts);
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_EXTENDED)) {
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_EXTENDED)) {
                buffer = g_string_new ("CHILDREN SUBSCRIBED");
-               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, LIST_STATUS))
+               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, LIST_STATUS))
                        g_string_append_printf (
                                buffer, " STATUS (%s)",
                                is->priv->status_data_items);
-               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, SPECIAL_USE))
+               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, SPECIAL_USE))
                        g_string_append_printf (buffer, " SPECIAL-USE");
                is->priv->list_return_opts = g_string_free (buffer, FALSE);
        } else {
@@ -1123,73 +640,54 @@ imapx_server_stash_command_arguments (CamelIMAPXServer *is)
        }
 }
 
-static gboolean
-imapx_server_inactivity_timeout_cb (gpointer data)
+static gpointer
+imapx_server_inactivity_thread (gpointer user_data)
 {
-       CamelIMAPXServer *is;
-       gboolean result = G_SOURCE_REMOVE;
-
-       is = g_weak_ref_get (data);
-
-       if (is == NULL)
-               return result;
-
-       /* IDLE command may still be active, and any other active
-        * commands would have reset this timeout.  So just check
-        * for any queued-but-not-yet-active commands. */
-
-       if (!camel_imapx_command_queue_is_empty (is->queue)) {
-               /* Do nothing. */
+       CamelIMAPXServer *is = user_data;
+       GError *local_error = NULL;
 
-       } else if (imapx_in_idle (is)) {
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
 
+       if (imapx_in_idle (is)) {
                /* Stop and restart the IDLE command. */
-               switch (imapx_stop_idle (is, NULL)) {
-                       case IMAPX_IDLE_STOP_SUCCESS:
-                               imapx_start_idle (is);
-                               result = G_SOURCE_CONTINUE;
-                               break;
-
-                       case IMAPX_IDLE_STOP_WAIT_DONE:
-                       case IMAPX_IDLE_STOP_NOOP:
-                               result = G_SOURCE_CONTINUE;
-                               break;
-
-                       default:
-                               break;
+               if (!camel_imapx_server_schedule_idle_sync (is, NULL, is->priv->cancellable, &local_error)) {
+                       g_warning ("%s: Faield to restart IDLE: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
                }
-
        } else {
-               CamelIMAPXJob *job;
-               GCancellable *cancellable;
-               GError *local_error = NULL;
-
-               /* Submit a NOOP job but indicate we don't need a
-                * reply when finished.  So this should NOT block. */
+               if (!camel_imapx_server_noop_sync (is, NULL, is->priv->cancellable, &local_error))
+                       g_warning ("%s: Failed to issue NOOP: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
+       }
 
-               cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
+       g_clear_error (&local_error);
+       g_object_unref (is);
 
-               job = camel_imapx_job_new (cancellable);
-               job->type = IMAPX_JOB_NOOP;
-               job->start = imapx_job_noop_start;
-               job->pri = IMAPX_PRIORITY_NOOP;
-               job->noreply = TRUE;
+       return NULL;
+}
 
-               imapx_submit_job (is, job, &local_error);
+static gboolean
+imapx_server_inactivity_timeout_cb (gpointer data)
+{
+       CamelIMAPXServer *is;
+       GThread *thread;
+       GError *local_error = NULL;
 
-               if (local_error != NULL) {
-                       g_warning ("%s: %s", G_STRFUNC, local_error->message);
-                       g_error_free (local_error);
-               }
+       is = g_weak_ref_get (data);
 
-               camel_imapx_job_unref (job);
+       if (is == NULL)
+               return G_SOURCE_REMOVE;
 
-               g_clear_object (&cancellable);
+       thread = g_thread_try_new (NULL, imapx_server_inactivity_thread, g_object_ref (is), &local_error);
+       if (!thread) {
+               g_warning ("%s: Failed to start inactivity thread: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
+               g_object_unref (is);
+       } else {
+               g_thread_unref (thread);
        }
 
+       g_clear_error (&local_error);
        g_object_unref (is);
 
-       return result;
+       return G_SOURCE_REMOVE;
 }
 
 static void
@@ -1209,9 +707,7 @@ imapx_server_reset_inactivity_timer (CamelIMAPXServer *is)
                imapx_server_inactivity_timeout_cb,
                imapx_weak_ref_new (is),
                (GDestroyNotify) imapx_weak_ref_free);
-       g_source_attach (
-               is->priv->inactivity_timeout,
-               is->priv->parser_main_context);
+       g_source_attach (is->priv->inactivity_timeout, NULL);
 
        g_mutex_unlock (&is->priv->inactivity_timeout_lock);
 }
@@ -1250,648 +746,16 @@ imapx_server_set_connection_timeout (GIOStream *connection,
        return previous_timeout;
 }
 
-/* Must hold QUEUE_LOCK */
-static void
-imapx_command_start (CamelIMAPXServer *is,
-                     CamelIMAPXCommand *ic)
-{
-       CamelIMAPXCommandPart *cp;
-       CamelIMAPXJob *job;
-       GInputStream *input_stream = NULL;
-       GOutputStream *output_stream = NULL;
-       GCancellable *cancellable = NULL;
-       gboolean cp_continuation;
-       gboolean cp_literal_plus;
-       gboolean success;
-       GList *head;
-       gchar *string;
-       GError *local_error = NULL;
-
-       camel_imapx_command_close (ic);
-
-       head = g_queue_peek_head_link (&ic->parts);
-       g_return_if_fail (head != NULL);
-       cp = (CamelIMAPXCommandPart *) head->data;
-       ic->current_part = head;
-
-       cp_continuation = ((cp->type & CAMEL_IMAPX_COMMAND_CONTINUATION) != 0);
-       cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
-
-       /* TODO: If we support literal+ we should be able to write the whole command out
-        * at this point .... >here< */
-
-       if (cp_continuation || cp_literal_plus)
-               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) {
-                       QUEUE_UNLOCK (is);
-                       ic->complete (is, ic);
-                       QUEUE_LOCK (is);
-               }
-
-               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);
-       cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
-       if (output_stream == NULL) {
-               local_error = g_error_new_literal (
-                       CAMEL_IMAPX_ERROR, 1,
-                       "Cannot issue command, no stream available");
-               goto fail;
-       }
-
-       c (
-               is->tagprefix,
-               "Starting command (active=%d,%s) %c%05u %s\r\n",
-               camel_imapx_command_queue_get_length (is->active),
-               is->literal ? " literal" : "",
-               is->tagprefix,
-               ic->tag,
-               cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
-                       "LOGIN..." : cp->data);
-
-       string = g_strdup_printf (
-               "%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
-       g_mutex_lock (&is->priv->stream_lock);
-       success = g_output_stream_write_all (
-               output_stream, string, strlen (string),
-               NULL, cancellable, &local_error);
-       g_mutex_unlock (&is->priv->stream_lock);
-       g_free (string);
-
-       if (local_error != NULL || !success)
-               goto fail;
-
-       while (is->literal == ic && cp_literal_plus) {
-               /* Sent LITERAL+ continuation immediately */
-               imapx_continuation (
-                       is, input_stream, output_stream,
-                       TRUE, cancellable, &local_error);
-               if (local_error != NULL)
-                       goto fail;
-       }
-
-       imapx_server_reset_inactivity_timer (is);
-
-       goto exit;
-
-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);
-       g_cancellable_cancel (cancellable);
-
-       /* Hand the error off to the command that we failed to start. */
-       camel_imapx_command_failed (ic, local_error);
-
-       if (ic->complete != NULL) {
-               QUEUE_UNLOCK (is);
-               ic->complete (is, ic);
-               QUEUE_LOCK (is);
-       }
-
-       g_clear_error (&local_error);
-
-exit:
-       g_clear_object (&input_stream);
-       g_clear_object (&output_stream);
-       g_clear_object (&cancellable);
-}
-
-static gboolean
-imapx_is_duplicate_fetch_or_refresh (CamelIMAPXServer *is,
-                                     CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       guint32 job_types;
-
-       /* Job types to match. */
-       job_types =
-               IMAPX_JOB_FETCH_NEW_MESSAGES |
-               IMAPX_JOB_REFRESH_INFO;
-
-       job = camel_imapx_command_get_job (ic);
-
-       if (job == NULL)
-               return FALSE;
-
-       if ((job->type & job_types) == 0)
-               return FALSE;
-
-       if (imapx_match_active_job (is, job_types, NULL) == NULL)
-               return FALSE;
-
-       c (is->tagprefix, "Not yet sending duplicate fetch/refresh %s command\n", ic->name);
-
-       return TRUE;
-}
-
-/* See if we can start another task yet.
- *
- * If we're waiting for a literal, we cannot proceed.
- *
- * If we're about to change the folder we're
- * looking at from user-direction, we dont proceed.
- *
- * If we have a folder selected, first see if any
- * jobs are waiting on it, but only if they are
- * at least as high priority as anything we
- * have running.
- *
- * If we dont, select the first folder required,
- * then queue all the outstanding jobs on it, that
- * are at least as high priority as the first.
- *
- * must have QUEUE lock */
-
-static void
-imapx_command_start_next (CamelIMAPXServer *is)
-{
-       CamelIMAPXCommand *first_ic;
-       CamelIMAPXMailbox *mailbox;
-       gint min_pri = -128;
-
-       c (is->tagprefix, "** Starting next command\n");
-       if (is->literal) {
-               c (
-                       is->tagprefix,
-                       "* no; waiting for literal '%s'\n",
-                       is->literal->name);
-               return;
-       }
-
-       g_mutex_lock (&is->priv->select_lock);
-       mailbox = g_weak_ref_get (&is->priv->select_pending);
-       g_mutex_unlock (&is->priv->select_lock);
-       if (mailbox != NULL) {
-               CamelIMAPXCommand *start_ic = NULL;
-               GList *head, *link;
-
-               c (
-                       is->tagprefix,
-                       "-- Checking job queue for non-mailbox jobs\n");
-
-               head = camel_imapx_command_queue_peek_head_link (is->queue);
-
-               /* Tag which commands in the queue to start. */
-               for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
-                       CamelIMAPXCommand *ic = link->data;
-                       CamelIMAPXMailbox *ic_mailbox;
-
-                       if (ic->pri < min_pri)
-                               break;
-
-                       c (
-                               is->tagprefix,
-                               "-- %3d '%s'?\n",
-                               (gint) ic->pri, ic->name);
-
-                       ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
-                       if (ic_mailbox == NULL) {
-                               c (
-                                       is->tagprefix,
-                                       "--> starting '%s'\n",
-                                       ic->name);
-                               min_pri = ic->pri;
-
-                               /* Each command must be removed from 'is->queue' before
-                                * starting it, so we temporarily reference the command
-                                * to avoid accidentally finalizing it. */
-                               start_ic = camel_imapx_command_ref (ic);
-                       }
-
-                       g_clear_object (&ic_mailbox);
-               }
-
-               if (!start_ic)
-                       c (
-                               is->tagprefix,
-                               "* no, waiting for pending select '%s'\n",
-                               camel_imapx_mailbox_get_name (mailbox));
-
-               /* Start the tagged command */
-               if (start_ic) {
-                       camel_imapx_command_queue_remove (is->queue, start_ic);
-                       imapx_server_command_removed (is, start_ic);
-                       imapx_command_start (is, start_ic);
-                       camel_imapx_command_unref (start_ic);
-               }
-
-               g_clear_object (&mailbox);
-
-               return;
-       }
-
-       if (is->state == IMAPX_SELECTED) {
-               gboolean stop_idle;
-               gboolean start_idle;
-
-               stop_idle =
-                       imapx_in_idle (is) &&
-                       !camel_imapx_command_queue_is_empty (is->queue);
-
-               start_idle =
-                       imapx_use_idle (is) &&
-                       !imapx_in_idle (is) &&
-                       imapx_is_command_queue_empty (is);
-
-               if (stop_idle) {
-                       switch (imapx_stop_idle (is, NULL)) {
-                               /* Proceed with the next queued command. */
-                               case IMAPX_IDLE_STOP_NOOP:
-                                       break;
-
-                               case IMAPX_IDLE_STOP_WAIT_DONE:
-                               case IMAPX_IDLE_STOP_SUCCESS:
-                                       c (
-                                               is->tagprefix,
-                                               "waiting for idle to stop \n");
-                                       /* if there are more pending commands,
-                                        * then they should be processed too */
-                                       return;
-
-                               case IMAPX_IDLE_STOP_ERROR:
-                                       return;
-                       }
-
-               } else if (start_idle) {
-                       imapx_start_idle (is);
-                       c (is->tagprefix, "starting idle\n");
-                       return;
-               }
-       }
-
-       if (camel_imapx_command_queue_is_empty (is->queue)) {
-               c (is->tagprefix, "* no, no jobs\n");
-               return;
-       }
-
-       /* See if any queued jobs on this select first */
-       g_mutex_lock (&is->priv->select_lock);
-       mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       g_mutex_unlock (&is->priv->select_lock);
-       if (mailbox != NULL) {
-               CamelIMAPXCommand *start_ic = NULL;
-               GList *head, *link;
-
-               c (
-                       is->tagprefix,
-                       "- we're selected on '%s', current jobs?\n",
-                       camel_imapx_mailbox_get_name (mailbox));
-
-               head = camel_imapx_command_queue_peek_head_link (is->active);
-
-               /* Find the highest priority in the active queue. */
-               for (link = head; link != NULL; link = g_list_next (link)) {
-                       CamelIMAPXCommand *ic = link->data;
-
-                       min_pri = MAX (min_pri, ic->pri);
-                       c (
-                               is->tagprefix,
-                               "-  %3d '%s'\n",
-                               (gint) ic->pri, ic->name);
-               }
-
-               if (camel_imapx_command_queue_get_length (is->active) >= MAX_COMMANDS) {
-                       c (
-                               is->tagprefix,
-                               "** too many jobs busy, "
-                               "waiting for results for now\n");
-                       g_object_unref (mailbox);
-                       return;
-               }
-
-               c (is->tagprefix, "-- Checking job queue\n");
-
-               head = camel_imapx_command_queue_peek_head_link (is->queue);
-
-               /* Tag which commands in the queue to start. */
-               for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
-                       CamelIMAPXCommand *ic = link->data;
-                       CamelIMAPXMailbox *ic_mailbox;
-                       gboolean okay_to_start;
-
-                       if (is->literal != NULL)
-                               break;
-
-                       if (ic->pri < min_pri)
-                               break;
-
-                       c (
-                               is->tagprefix,
-                               "-- %3d '%s'?\n",
-                               (gint) ic->pri, ic->name);
-
-                       ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
-                       okay_to_start =
-                               (ic_mailbox == NULL) ||
-                               (ic_mailbox == mailbox &&
-                               !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
-                       if (okay_to_start) {
-                               c (
-                                       is->tagprefix,
-                                       "--> starting '%s'\n",
-                                       ic->name);
-                               min_pri = ic->pri;
-                               /* Each command must be removed from 'is->queue' before
-                                * starting it, so we temporarily reference the command
-                                * to avoid accidentally finalizing it. */
-                               start_ic = camel_imapx_command_ref (ic);
-                       } else {
-                               /* This job isn't for the selected mailbox,
-                                * but we don't want to consider jobs with
-                                * lower priority than this, even if they
-                                * are for the selected mailbox. */
-                               min_pri = ic->pri;
-                       }
-
-                       g_clear_object (&ic_mailbox);
-               }
-
-               g_clear_object (&mailbox);
-
-               /* Start the tagged command */
-               if (start_ic) {
-                       camel_imapx_command_queue_remove (is->queue, start_ic);
-                       imapx_server_command_removed (is, start_ic);
-                       imapx_command_start (is, start_ic);
-                       camel_imapx_command_unref (start_ic);
-
-                       return;
-               }
-       }
-
-       /* This won't be NULL because we checked for an empty queue above. */
-       first_ic = camel_imapx_command_queue_peek_head (is->queue);
-
-       /* If we need to select a mailbox for the first command, do
-        * so now.  It will re-call us if it completes successfully. */
-       mailbox = camel_imapx_command_ref_mailbox (first_ic);
-       if (mailbox != NULL) {
-               CamelIMAPXJob *job;
-
-               c (
-                       is->tagprefix,
-                       "Selecting mailbox '%s' for command '%s'(%p)\n",
-                       camel_imapx_mailbox_get_name (mailbox),
-                       first_ic->name, first_ic);
-
-               /* Associate the SELECT command with the CamelIMAPXJob
-                * that triggered it.  Then if the SELECT command fails
-                * we have some destination to propagate the GError to. */
-               job = camel_imapx_command_get_job (first_ic);
-               imapx_maybe_select (is, job, mailbox);
-
-               g_clear_object (&mailbox);
-
-       } else {
-               CamelIMAPXCommand *start_ic = NULL;
-               GList *head, *link;
-
-               min_pri = first_ic->pri;
-
-               g_mutex_lock (&is->priv->select_lock);
-               mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-               g_mutex_unlock (&is->priv->select_lock);
-
-               head = camel_imapx_command_queue_peek_head_link (is->queue);
-
-               /* Tag which commands in the queue to start. */
-               for (link = head; link != NULL && !start_ic; link = g_list_next (link)) {
-                       CamelIMAPXCommand *ic = link->data;
-                       CamelIMAPXMailbox *ic_mailbox;
-                       gboolean okay_to_start;
-
-                       if (is->literal != NULL)
-                               break;
-
-                       if (ic->pri < min_pri)
-                               break;
-
-                       ic_mailbox = camel_imapx_command_ref_mailbox (ic);
-
-                       okay_to_start =
-                               (ic_mailbox == NULL) ||
-                               (ic_mailbox == mailbox &&
-                               !imapx_is_duplicate_fetch_or_refresh (is, ic));
-
-                       if (okay_to_start) {
-                               c (
-                                       is->tagprefix,
-                                       "* queueing job %3d '%s'\n",
-                                       (gint) ic->pri, ic->name);
-                               min_pri = ic->pri;
-                               /* Each command must be removed from 'is->queue' before
-                                * starting it, so we temporarily reference the command
-                                * to avoid accidentally finalizing it. */
-                               start_ic = camel_imapx_command_ref (ic);
-                       }
-
-                       g_clear_object (&ic_mailbox);
-               }
-
-               g_clear_object (&mailbox);
-
-               /* Start the tagged command */
-               if (start_ic) {
-                       camel_imapx_command_queue_remove (is->queue, start_ic);
-                       imapx_server_command_removed (is, start_ic);
-                       imapx_command_start (is, start_ic);
-                       camel_imapx_command_unref (start_ic);
-               }
-       }
-}
-
-static gboolean
-imapx_is_command_queue_empty (CamelIMAPXServer *is)
-{
-       if (!camel_imapx_command_queue_is_empty (is->queue))
-               return FALSE;
-
-       if (!camel_imapx_command_queue_is_empty (is->active))
-               return FALSE;
-
-       return TRUE;
-}
-
-static void
-imapx_command_queue (CamelIMAPXServer *is,
-                     CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-
-       /* We enqueue in priority order, new messages have
-        * higher priority than older messages with the same priority */
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       camel_imapx_command_close (ic);
-
-       c (
-               is->tagprefix,
-               "enqueue job '%.*s'\n",
-               ((CamelIMAPXCommandPart *) ic->parts.head->data)->data_size,
-               ((CamelIMAPXCommandPart *) ic->parts.head->data)->data);
-
-       QUEUE_LOCK (is);
-
-       if (is->state == IMAPX_SHUTDOWN) {
-               GError *local_error = NULL;
-
-               c (is->tagprefix, "refuse to queue job on disconnected server\n");
-
-               local_error = g_error_new (
-                       CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
-                       "%s", _("Server disconnected"));
-               camel_imapx_command_failed (ic, local_error);
-               g_error_free (local_error);
-
-               QUEUE_UNLOCK (is);
-
-               if (ic->complete != NULL)
-                       ic->complete (is, ic);
-
-               return;
-       }
-
-       camel_imapx_command_queue_insert_sorted (is->queue, ic);
-       imapx_server_command_added (is, ic);
-
-       imapx_command_start_next (is);
-
-       QUEUE_UNLOCK (is);
-}
-
-/* Must not have QUEUE lock */
-static CamelIMAPXJob *
-imapx_match_active_job (CamelIMAPXServer *is,
-                        guint32 type,
-                        const gchar *uid)
-{
-       CamelIMAPXJob *match = NULL;
-       GList *head, *link;
-
-       QUEUE_LOCK (is);
-
-       head = camel_imapx_command_queue_peek_head_link (is->active);
-
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               CamelIMAPXCommand *ic = link->data;
-               CamelIMAPXMailbox *mailbox;
-               CamelIMAPXJob *job;
-               gboolean job_matches;
-
-               job = camel_imapx_command_get_job (ic);
-
-               if (job == NULL)
-                       continue;
-
-               if (!(job->type & type))
-                       continue;
-
-               g_mutex_lock (&is->priv->select_lock);
-               mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-               g_mutex_unlock (&is->priv->select_lock);
-
-               job_matches = camel_imapx_job_matches (job, mailbox, uid);
-               g_clear_object (&mailbox);
-
-               if (job_matches) {
-                       match = job;
-                       break;
-               }
-       }
-
-       QUEUE_UNLOCK (is);
-
-       return match;
-}
-
-/* Do *not* call this when the queue_lock is held, it can cause
-   deadlock when searching between multiple servers */
-static CamelIMAPXJob *
-imapx_server_ref_job (CamelIMAPXServer *imapx_server,
-                     CamelIMAPXMailbox *mailbox,
-                     guint32 job_type,
-                     const gchar *uid)
-{
-       CamelIMAPXStore *imapx_store;
-       CamelIMAPXJob *job;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
-       /* first try its own queue */
-       job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
-       if (job)
-               return job;
-
-       /* then try queue for all the opened servers */
-       imapx_store = camel_imapx_server_ref_store (imapx_server);
-       if (!imapx_store)
-               return NULL;
-
-       job = camel_imapx_store_ref_job (imapx_store, mailbox, job_type, uid);
-
-       g_object_unref (imapx_store);
-
-       return job;
-}
-
-static gboolean
-imapx_has_expunge_command (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox)
-{
-       CamelIMAPXStore *imapx_store;
-       CamelIMAPXJob *job;
-
-       imapx_store = camel_imapx_server_ref_store (is);
-       if (!imapx_store)
-               return FALSE;
-
-       job = camel_imapx_store_ref_job (imapx_store, mailbox, IMAPX_JOB_EXPUNGE, NULL);
-
-       if (job)
-               camel_imapx_job_unref (job);
-
-       return job != NULL;
-}
-
 static void
 imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
-                                gchar *uid,
+                                const gchar *uid,
                                 gboolean unsolicited)
 {
        CamelFolder *folder;
        CamelIMAPXMailbox *mailbox;
        guint32 messages;
 
-       g_mutex_lock (&is->priv->select_lock);
-       mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       g_mutex_unlock (&is->priv->select_lock);
+       mailbox = camel_imapx_server_ref_pending_or_selected (is);
 
        g_return_if_fail (mailbox != NULL);
 
@@ -1903,8 +767,7 @@ imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
        if (unsolicited && messages > 0)
                camel_imapx_mailbox_set_messages (mailbox, messages - 1);
 
-       if (is->priv->changes == NULL)
-               is->priv->changes = camel_folder_change_info_new ();
+       g_return_if_fail (is->priv->changes != NULL);
 
        camel_folder_summary_remove_uid (folder->summary, uid);
        camel_folder_change_info_remove_uid (is->priv->changes, uid);
@@ -1931,16 +794,16 @@ imapx_untagged_capability (CamelIMAPXServer *is,
 {
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       if (is->cinfo != NULL)
-               imapx_free_capability (is->cinfo);
+       if (is->priv->cinfo != NULL)
+               imapx_free_capability (is->priv->cinfo);
 
-       is->cinfo = imapx_parse_capability (
+       is->priv->cinfo = imapx_parse_capability (
                CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
 
-       if (is->cinfo == NULL)
+       if (is->priv->cinfo == NULL)
                return FALSE;
 
-       c (is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
+       c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo->capa);
 
        imapx_server_stash_command_arguments (is);
 
@@ -1954,46 +817,43 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
                         GError **error)
 {
        CamelIMAPXMailbox *mailbox;
-       CamelIMAPXJob *job = NULL;
-       guint32 expunge = 0;
+       gulong expunge = 0;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
        expunge = is->priv->context->id;
-       job = imapx_match_active_job (is, IMAPX_JOB_EXPUNGE, NULL);
 
-       /* If there is a job running, let it handle the deletion */
-       if (job != NULL)
-               return TRUE;
+       COMMAND_LOCK (is);
 
-       job = imapx_match_active_job (is, IMAPX_JOB_COPY_MESSAGE, NULL);
        /* Ignore EXPUNGE responses when not running a COPY(MOVE)_MESSAGE job */
-       if (!job) {
-               c (is->tagprefix, "ignoring untagged expunge: %lu\n", is->priv->context->id);
+       if (!is->priv->current_command || (is->priv->current_command->job_kind != 
CAMEL_IMAPX_JOB_COPY_MESSAGE &&
+           is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_MOVE_MESSAGE)) {
+               COMMAND_UNLOCK (is);
+
+               c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunge);
                return TRUE;
        }
 
-       c (is->tagprefix, "expunged: %lu\n", is->priv->context->id);
+       COMMAND_UNLOCK (is);
 
-       g_mutex_lock (&is->priv->select_lock);
-       mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       g_mutex_unlock (&is->priv->select_lock);
+       c (is->priv->tagprefix, "expunged: %lu\n", expunge);
 
-       /* Ignore EXPUNGE responses when there is an ongoing EXPUNGE job */
-       if (mailbox != NULL && !imapx_has_expunge_command (is, mailbox)) {
+       mailbox = camel_imapx_server_ref_pending_or_selected (is);
+
+       if (mailbox != NULL) {
                CamelFolder *folder;
                gchar *uid;
 
                folder = imapx_server_ref_folder (is, mailbox);
                g_return_val_if_fail (folder != NULL, FALSE);
 
-               uid = camel_imapx_dup_uid_from_summary_index (
-                       folder, expunge - 1);
+               uid = camel_imapx_dup_uid_from_summary_index (folder, expunge - 1);
 
                if (uid != NULL)
                        imapx_expunge_uid_from_summary (is, uid, TRUE);
 
                g_object_unref (folder);
+               g_free (uid);
        }
 
        g_clear_object (&mailbox);
@@ -2045,9 +905,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
        if (uids == NULL)
                return FALSE;
 
-       g_mutex_lock (&is->priv->select_lock);
-       mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       g_mutex_unlock (&is->priv->select_lock);
+       mailbox = camel_imapx_server_ref_pending_or_selected (is);
 
        g_return_val_if_fail (mailbox != NULL, FALSE);
 
@@ -2061,7 +919,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
                if (messages < uids->len) {
                        c (
-                               is->tagprefix,
+                               is->priv->tagprefix,
                                "Error: mailbox messages (%u) is "
                                "fewer than vanished %u\n",
                                messages, uids->len);
@@ -2073,8 +931,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
                camel_imapx_mailbox_set_messages (mailbox, messages);
        }
 
-       if (is->priv->changes == NULL)
-               is->priv->changes = camel_folder_change_info_new ();
+       g_return_val_if_fail (is->priv->changes != NULL, FALSE);
 
        for (ii = 0; ii < uids->len; ii++) {
                guint32 uid;
@@ -2082,7 +939,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
                uid = g_array_index (uids, guint32, ii);
 
-               e (is->tagprefix, "vanished: %u\n", uid);
+               e (is->priv->tagprefix, "vanished: %u\n", uid);
 
                str = g_strdup_printf ("%u", uid);
                uid_list = g_list_prepend (uid_list, str);
@@ -2092,9 +949,11 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
        uid_list = g_list_reverse (uid_list);
        camel_folder_summary_remove_uids (folder->summary, uid_list);
 
+       COMMAND_LOCK (is);
+
        /* If the response is truly unsolicited (e.g. via NOTIFY)
         * then go ahead and emit the change notification now. */
-       if (camel_imapx_command_queue_is_empty (is->queue) && is->priv->changes->uid_removed &&
+       if (!is->priv->current_command && is->priv->changes->uid_removed &&
            is->priv->changes->uid_removed->len >= 100) {
                camel_folder_summary_save_to_db (folder->summary, NULL);
                imapx_update_store_summary (folder);
@@ -2102,6 +961,8 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
                camel_folder_change_info_clear (is->priv->changes);
        }
 
+       COMMAND_UNLOCK (is);
+
        g_list_free_full (uid_list, (GDestroyNotify) g_free);
        g_array_free (uids, TRUE);
 
@@ -2159,6 +1020,11 @@ imapx_untagged_exists (CamelIMAPXServer *is,
 
        exists = (guint32) is->priv->context->id;
 
+       c (is->priv->tagprefix, "%s: updating mailbox '%s' messages: %d ~> %d\n", G_STRFUNC,
+               camel_imapx_mailbox_get_name (mailbox),
+               camel_imapx_mailbox_get_messages (mailbox),
+               exists);
+
        camel_imapx_mailbox_set_messages (mailbox, exists);
 
        folder = imapx_server_ref_folder (is, mailbox);
@@ -2168,12 +1034,8 @@ imapx_untagged_exists (CamelIMAPXServer *is,
                guint count;
 
                count = camel_folder_summary_count (folder->summary);
-               if (count < exists) {
-                       CamelIMAPXIdleStopResult stop_result;
-
-                       stop_result = imapx_stop_idle (is, error);
-                       success = (stop_result != IMAPX_IDLE_STOP_ERROR);
-               }
+               if (count < exists)
+                       g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
        }
 
        g_object_unref (folder);
@@ -2197,7 +1059,7 @@ imapx_untagged_flags (CamelIMAPXServer *is,
                CAMEL_IMAPX_INPUT_STREAM (input_stream),
                &flags, NULL, cancellable, error);
 
-       c (is->tagprefix, "flags: %08x\n", flags);
+       c (is->priv->tagprefix, "flags: %08x\n", flags);
 
        return success;
 }
@@ -2236,72 +1098,49 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
        }
 
        if ((finfo->got & (FETCH_BODY | FETCH_UID)) == (FETCH_BODY | FETCH_UID)) {
-               CamelIMAPXJob *job;
-               GetMessageData *data;
+               GOutputStream *output_stream;
+               gconstpointer body_data;
+               gsize body_size;
 
-               job = imapx_match_active_job (
-                       is, IMAPX_JOB_GET_MESSAGE, finfo->uid);
-               if (job == NULL) {
-                       g_warn_if_reached ();
-                       return FALSE;
-               }
+               g_return_val_if_fail (is->priv->get_message_stream != NULL, FALSE);
 
-               data = camel_imapx_job_get_data (job);
-               g_return_val_if_fail (data != NULL, FALSE);
+               /* Fill out the body stream, in the right spot. */
 
-               /* This must've been a get-message request,
-                * fill out the body stream, in the right spot. */
+               g_seekable_seek (
+                       G_SEEKABLE (is->priv->get_message_stream),
+                       finfo->offset, G_SEEK_SET,
+                       NULL, NULL);
 
-               if (job != NULL) {
-                       GOutputStream *output_stream;
-                       gconstpointer body_data;
-                       gsize body_size;
-
-                       if (data->use_multi_fetch) {
-                               data->body_offset = finfo->offset;
-                               g_seekable_seek (
-                                       G_SEEKABLE (data->stream),
-                                       finfo->offset, G_SEEK_SET,
-                                       NULL, NULL);
-                       }
+               output_stream = g_io_stream_get_output_stream (is->priv->get_message_stream);
 
-                       output_stream =
-                               g_io_stream_get_output_stream (data->stream);
-
-                       body_data = g_bytes_get_data (finfo->body, &body_size);
-
-                       /* Sometimes the server, like Microsoft Exchange, reports larger message
-                          size than it actually is, which results in no data being read from
-                          the server for that particular offset. */
-                       if (body_size) {
-                               g_mutex_lock (&is->priv->stream_lock);
-                               if (!g_output_stream_write_all (
-                                       output_stream, body_data, body_size,
-                                       NULL, cancellable, error)) {
-                                       g_mutex_unlock (&is->priv->stream_lock);
-                                       g_prefix_error (
-                                               error, "%s: ",
-                                               _("Error writing to cache stream"));
-                                       return FALSE;
-                               }
+               body_data = g_bytes_get_data (finfo->body, &body_size);
+
+               /* Sometimes the server, like Microsoft Exchange, reports larger message
+                  size than it actually is, which results in no data being read from
+                  the server for that particular offset. */
+               if (body_size) {
+                       g_mutex_lock (&is->priv->stream_lock);
+                       if (!g_output_stream_write_all (
+                               output_stream, body_data, body_size,
+                               NULL, cancellable, error)) {
                                g_mutex_unlock (&is->priv->stream_lock);
+                               g_prefix_error (
+                                       error, "%s: ",
+                                       _("Error writing to cache stream"));
+                               return FALSE;
                        }
+                       g_mutex_unlock (&is->priv->stream_lock);
                }
        }
 
        if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
-               CamelIMAPXJob *job;
                CamelIMAPXMailbox *select_mailbox;
                CamelIMAPXMailbox *select_pending;
-               RefreshInfoData *data = NULL;
 
-               job = imapx_match_active_job (
-                       is, IMAPX_JOB_FETCH_NEW_MESSAGES |
-                       IMAPX_JOB_REFRESH_INFO, NULL);
-
-               if (job != NULL) {
-                       data = camel_imapx_job_get_data (job);
-                       g_return_val_if_fail (data != NULL, FALSE);
+               if (is->priv->fetch_changes_mailbox) {
+                       g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+                       g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+                       g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
                }
 
                g_mutex_lock (&is->priv->select_lock);
@@ -2312,27 +1151,49 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                /* This is either a refresh_info job, check to see if it is
                 * and update if so, otherwise it must've been an unsolicited
                 * response, so update the summary to match. */
-               if (data && (finfo->got & FETCH_UID) && data->scan_changes) {
-                       struct _refresh_info r;
+               if ((finfo->got & FETCH_UID) != 0 && is->priv->fetch_changes_folder && 
is->priv->fetch_changes_infos) {
+                       FetchChangesInfo *nfo;
+                       gint64 monotonic_time;
+                       gint n_messages;
+
+                       nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+                       if (!nfo) {
+                               nfo = g_new0 (FetchChangesInfo, 1);
 
-                       r.uid = finfo->uid;
-                       finfo->uid = NULL;
-                       r.server_flags = finfo->flags;
-                       r.server_user_flags = finfo->user_flags;
+                               g_hash_table_insert (is->priv->fetch_changes_infos, (gpointer) 
camel_pstring_strdup (finfo->uid), nfo);
+                       }
+
+                       nfo->server_flags = finfo->flags;
+                       nfo->server_user_flags = finfo->user_flags;
                        finfo->user_flags = NULL;
-                       r.exists = FALSE;
-                       g_array_append_val (data->infos, r);
 
+                       monotonic_time = g_get_monotonic_time ();
+                       n_messages = camel_imapx_mailbox_get_messages (is->priv->fetch_changes_mailbox);
+
+                       if (n_messages > 0 && is->priv->fetch_changes_last_progress + G_USEC_PER_SEC / 2 < 
monotonic_time &&
+                           is->priv->context && is->priv->context->id <= n_messages) {
+                               COMMAND_LOCK (is);
+
+                               if (is->priv->current_command) {
+                                       COMMAND_UNLOCK (is);
+
+                                       is->priv->fetch_changes_last_progress = monotonic_time;
+
+                                       camel_operation_progress (cancellable, 100 * is->priv->context->id
+                                               / camel_imapx_mailbox_get_messages 
(is->priv->fetch_changes_mailbox));
+                               } else {
+                                       COMMAND_UNLOCK (is);
+                               }
+                       }
                } else if (select_mailbox != NULL) {
                        CamelFolder *select_folder;
                        CamelMessageInfo *mi = NULL;
                        gboolean changed = FALSE;
                        gchar *uid = NULL;
 
-                       c (is->tagprefix, "flag changed: %lu\n", is->priv->context->id);
+                       c (is->priv->tagprefix, "flag changed: %lu\n", is->priv->context->id);
 
-                       select_folder =
-                               imapx_server_ref_folder (is, select_mailbox);
+                       select_folder = imapx_server_ref_folder (is, select_mailbox);
                        g_return_val_if_fail (select_folder != NULL, FALSE);
 
                        if (finfo->got & FETCH_UID) {
@@ -2345,8 +1206,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                        }
 
                        if (uid) {
-                               mi = camel_folder_summary_get (
-                                       select_folder->summary, uid);
+                               mi = camel_folder_summary_get (select_folder->summary, uid);
                                if (mi) {
                                        /* It's unsolicited _unless_ select_pending (i.e. during
                                         * a QRESYNC SELECT */
@@ -2359,29 +1219,23 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                                } else {
                                        /* This (UID + FLAGS for previously unknown message) might
                                         * happen during a SELECT (QRESYNC). We should use it. */
-                                       c (is->tagprefix, "flags changed for unknown uid %s\n.", uid);
+                                       c (is->priv->tagprefix, "flags changed for unknown uid %s\n.", uid);
                                }
                                finfo->user_flags = NULL;
                        }
 
                        if (changed) {
-                               if (is->priv->changes == NULL)
-                                       is->priv->changes =
-                                               camel_folder_change_info_new ();
+                               g_return_val_if_fail (is->priv->changes != NULL, FALSE);
 
-                               camel_folder_change_info_change_uid (
-                                       is->priv->changes, uid);
+                               camel_folder_change_info_change_uid (is->priv->changes, uid);
                        }
                        g_free (uid);
 
                        if (changed && imapx_in_idle (is)) {
-                               camel_folder_summary_save_to_db (
-                                       select_folder->summary, NULL);
+                               camel_folder_summary_save_to_db (select_folder->summary, NULL);
                                imapx_update_store_summary (select_folder);
-                               camel_folder_changed (
-                                       select_folder, is->priv->changes);
-                               camel_folder_change_info_clear (
-                                       is->priv->changes);
+                               camel_folder_changed (select_folder, is->priv->changes);
+                               camel_folder_change_info_clear (is->priv->changes);
                        }
 
                        if (mi)
@@ -2395,151 +1249,119 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
        }
 
        if ((finfo->got & (FETCH_HEADER | FETCH_UID)) == (FETCH_HEADER | FETCH_UID)) {
-               CamelIMAPXJob *job;
+               CamelIMAPXMailbox *mailbox;
+               CamelFolder *folder;
+               CamelMimeParser *mp;
+               CamelMessageInfo *mi;
+               guint32 messages;
+               guint32 unseen;
+               guint32 uidnext;
 
                /* This must be a refresh info job as well, but it has
                 * asked for new messages to be added to the index. */
 
-               job = imapx_match_active_job (
-                       is, IMAPX_JOB_FETCH_NEW_MESSAGES |
-                       IMAPX_JOB_REFRESH_INFO, NULL);
-
-               if (job != NULL) {
-                       CamelIMAPXMailbox *mailbox;
-                       CamelFolder *folder;
-                       CamelMimeParser *mp;
-                       CamelMessageInfo *mi;
-                       guint32 messages;
-                       guint32 unseen;
-                       guint32 uidnext;
-
-                       mailbox = camel_imapx_job_ref_mailbox (job);
-                       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-                       folder = imapx_server_ref_folder (is, mailbox);
-                       g_return_val_if_fail (folder != NULL, FALSE);
+               if (is->priv->fetch_changes_mailbox) {
+                       g_return_val_if_fail (is->priv->fetch_changes_mailbox != NULL, FALSE);
+                       g_return_val_if_fail (is->priv->fetch_changes_folder != NULL, FALSE);
+                       g_return_val_if_fail (is->priv->fetch_changes_infos != NULL, FALSE);
 
-                       messages = camel_imapx_mailbox_get_messages (mailbox);
-                       unseen = camel_imapx_mailbox_get_unseen (mailbox);
-                       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+                       folder = g_object_ref (is->priv->fetch_changes_folder);
+                       mailbox = g_object_ref (is->priv->fetch_changes_mailbox);
+               } else {
+                       mailbox = camel_imapx_server_ref_selected (is);
+                       folder = mailbox ? imapx_server_ref_folder (is, mailbox) : NULL;
+               }
 
-                       /* Do we want to save these headers for later too?  Do we care? */
+               if (!mailbox || (!(finfo->got & FETCH_FLAGS) && !is->priv->fetch_changes_infos)) {
+                       g_clear_object (&mailbox);
+                       g_clear_object (&folder);
+                       imapx_free_fetch (finfo);
 
-                       mp = camel_mime_parser_new ();
-                       camel_mime_parser_init_with_bytes (mp, finfo->header);
-                       mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
-                       g_object_unref (mp);
+                       return TRUE;
+               }
 
-                       if (mi != NULL) {
-                               guint32 server_flags;
-                               CamelFlag *server_user_flags;
-                               CamelMessageInfoBase *binfo;
-                               gboolean free_user_flags = FALSE;
+               messages = camel_imapx_mailbox_get_messages (mailbox);
+               unseen = camel_imapx_mailbox_get_unseen (mailbox);
+               uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
 
-                               mi->uid = camel_pstring_strdup (finfo->uid);
+               /* Do we want to save these headers for later too?  Do we care? */
 
-                               if (!(finfo->got & FETCH_FLAGS)) {
-                                       RefreshInfoData *data;
-                                       struct _refresh_info *r = NULL;
-                                       gint min, max, mid;
-                                       gboolean found = FALSE;
+               mp = camel_mime_parser_new ();
+               camel_mime_parser_init_with_bytes (mp, finfo->header);
+               mi = camel_folder_summary_info_new_from_parser (folder->summary, mp);
+               g_object_unref (mp);
 
-                                       data = camel_imapx_job_get_data (job);
-                                       g_return_val_if_fail (data != NULL, FALSE);
+               if (mi != NULL) {
+                       guint32 server_flags;
+                       CamelFlag *server_user_flags;
+                       CamelMessageInfoBase *binfo;
+                       gboolean free_user_flags = FALSE;
 
-                                       min = data->last_index;
-                                       max = data->index - 1;
+                       mi->uid = camel_pstring_strdup (finfo->uid);
 
-                                       /* array is sorted, so use a binary search */
-                                       do {
-                                               gint cmp = 0;
+                       if (!(finfo->got & FETCH_FLAGS) && is->priv->fetch_changes_infos) {
+                               FetchChangesInfo *nfo;
 
-                                               mid = (min + max) / 2;
-                                               r = &g_array_index (data->infos, struct _refresh_info, mid);
-                                               cmp = imapx_refresh_info_uid_cmp (
-                                                       finfo->uid,
-                                                       r->uid,
-                                                       is->priv->context->fetch_order == 
CAMEL_SORT_ASCENDING);
+                               nfo = g_hash_table_lookup (is->priv->fetch_changes_infos, finfo->uid);
+                               g_return_val_if_fail (nfo != NULL, FALSE);
 
-                                               if (cmp > 0)
-                                                       min = mid + 1;
-                                               else if (cmp < 0)
-                                                       max = mid - 1;
-                                               else
-                                                       found = TRUE;
+                               server_flags = nfo->server_flags;
+                               server_user_flags = nfo->server_user_flags;
+                       } else {
+                               server_flags = finfo->flags;
+                               server_user_flags = finfo->user_flags;
+                               /* free user_flags ? */
+                               finfo->user_flags = NULL;
+                               free_user_flags = TRUE;
+                       }
 
-                                       } while (!found && min <= max);
+                       /* If the message is a really new one -- equal or higher than what
+                        * we know as UIDNEXT for the folder, then it came in since we last
+                        * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
+                        * command completion, but update UNREAD count now according to the
+                        * message SEEN flag */
+                       if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
+                               guint64 uidl;
 
-                                       g_return_val_if_fail (found, FALSE);
+                               uidl = strtoull (mi->uid, NULL, 10);
 
-                                       server_flags = r->server_flags;
-                                       server_user_flags = r->server_user_flags;
+                               if (uidl >= uidnext) {
+                                       c (is->priv->tagprefix, "Updating unseen count for new message %s\n", 
mi->uid);
+                                       camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
                                } else {
-                                       server_flags = finfo->flags;
-                                       server_user_flags = finfo->user_flags;
-                                       /* free user_flags ? */
-                                       finfo->user_flags = NULL;
-                                       free_user_flags = TRUE;
-                               }
-
-                               /* If the message is a really new one -- equal or higher than what
-                                * we know as UIDNEXT for the folder, then it came in since we last
-                                * fetched UIDNEXT and UNREAD count. We'll update UIDNEXT in the
-                                * command completion, but update UNREAD count now according to the
-                                * message SEEN flag */
-                               if (!(server_flags & CAMEL_MESSAGE_SEEN)) {
-                                       guint64 uidl;
-
-                                       uidl = strtoull (mi->uid, NULL, 10);
-
-                                       if (uidl >= uidnext) {
-                                               c (is->tagprefix, "Updating unseen count for new message 
%s\n", mi->uid);
-                                               camel_imapx_mailbox_set_unseen (mailbox, unseen + 1);
-                                       } else {
-                                               c (is->tagprefix, "Not updating unseen count for new message 
%s\n", mi->uid);
-                                       }
+                                       c (is->priv->tagprefix, "Not updating unseen count for new message 
%s\n", mi->uid);
                                }
+                       }
 
-                               binfo = (CamelMessageInfoBase *) mi;
-                               binfo->size = finfo->size;
-
-                               camel_folder_summary_lock (folder->summary);
-
-                               if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
-                                       RefreshInfoData *data;
-
-                                       data = camel_imapx_job_get_data (job);
-                                       g_return_val_if_fail (data != NULL, FALSE);
+                       binfo = (CamelMessageInfoBase *) mi;
+                       binfo->size = finfo->size;
 
-                                       imapx_set_message_info_flags_for_new_message (mi, server_flags, 
server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
-                                       camel_folder_summary_add (folder->summary, mi);
-                                       camel_folder_change_info_add_uid (data->changes, mi->uid);
+                       camel_folder_summary_lock (folder->summary);
 
-                                       camel_folder_change_info_recent_uid (data->changes, mi->uid);
+                       if (!camel_folder_summary_check_uid (folder->summary, mi->uid)) {
+                               imapx_set_message_info_flags_for_new_message (mi, server_flags, 
server_user_flags, FALSE, NULL, camel_imapx_mailbox_get_permanentflags (mailbox));
+                               camel_folder_summary_add (folder->summary, mi);
 
-                                       if (messages > 0) {
-                                               GCancellable *use_cancellable;
-                                               gint cnt = (camel_folder_summary_count (folder->summary) * 
100) / messages;
+                               camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
+                               camel_folder_change_info_recent_uid (is->priv->changes, mi->uid);
 
-                                               use_cancellable = camel_imapx_job_get_cancellable (job);
-                                               if (!use_cancellable)
-                                                       use_cancellable = cancellable;
+                               if (messages > 0) {
+                                       gint cnt = (camel_folder_summary_count (folder->summary) * 100) / 
messages;
 
-                                               camel_operation_progress (use_cancellable, cnt ? cnt : 1);
-                                       }
-                               } else {
-                                       camel_message_info_unref (mi);
+                                       camel_operation_progress (cancellable, cnt ? cnt : 1);
                                }
-
-                               camel_folder_summary_unlock (folder->summary);
-
-                               if (free_user_flags && server_user_flags)
-                                       camel_flag_list_free (&server_user_flags);
+                       } else {
+                               camel_message_info_unref (mi);
                        }
 
-                       g_object_unref (folder);
-                       g_object_unref (mailbox);
+                       camel_folder_summary_unlock (folder->summary);
+
+                       if (free_user_flags && server_user_flags)
+                               camel_flag_list_free (&server_user_flags);
                }
+
+               g_clear_object (&mailbox);
+               g_clear_object (&folder);
        }
 
        imapx_free_fetch (finfo);
@@ -2717,6 +1539,11 @@ imapx_untagged_recent (CamelIMAPXServer *is,
 
        recent = (guint32) is->priv->context->id;
 
+       c (is->priv->tagprefix, "%s: updating mailbox '%s' recent: %d ~> %d\n", G_STRFUNC,
+               camel_imapx_mailbox_get_name (mailbox),
+               camel_imapx_mailbox_get_recent (mailbox),
+               recent);
+
        camel_imapx_mailbox_set_recent (mailbox, recent);
 
        g_object_unref (mailbox);
@@ -2836,7 +1663,9 @@ imapx_untagged_bye (CamelIMAPXServer *is,
        /* XXX It's weird to be setting an error on success,
         *     but it's to indicate the server hung up on us. */
        if (success) {
-               c (is->tagprefix, "BYE: %s\n", token);
+               g_strstrip ((gchar *) token);
+
+               c (is->priv->tagprefix, "BYE: %s\n", token);
                g_set_error (
                        error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
                        "IMAP server said BYE: %s", token);
@@ -2844,7 +1673,7 @@ imapx_untagged_bye (CamelIMAPXServer *is,
 
        g_free (token);
 
-       is->state = IMAPX_SHUTDOWN;
+       is->priv->state = IMAPX_SHUTDOWN;
 
        return FALSE;
 }
@@ -2857,9 +1686,9 @@ imapx_untagged_preauth (CamelIMAPXServer *is,
 {
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       c (is->tagprefix, "preauthenticated\n");
-       if (is->state < IMAPX_AUTHENTICATED)
-               is->state = IMAPX_AUTHENTICATED;
+       c (is->priv->tagprefix, "preauthenticated\n");
+       if (is->priv->state < IMAPX_AUTHENTICATED)
+               is->priv->state = IMAPX_AUTHENTICATED;
 
        return TRUE;
 }
@@ -2903,43 +1732,28 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
        switch (is->priv->context->sinfo->condition) {
        case IMAPX_CLOSED:
                c (
-                       is->tagprefix,
+                       is->priv->tagprefix,
                        "previously selected mailbox is now closed\n");
                {
                        CamelIMAPXMailbox *select_mailbox;
-                       CamelIMAPXMailbox *select_closing;
                        CamelIMAPXMailbox *select_pending;
 
                        g_mutex_lock (&is->priv->select_lock);
 
-                       select_mailbox =
-                               g_weak_ref_get (&is->priv->select_mailbox);
-                       select_closing =
-                               g_weak_ref_get (&is->priv->select_closing);
-                       select_pending =
-                               g_weak_ref_get (&is->priv->select_pending);
+                       select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+                       select_pending = g_weak_ref_get (&is->priv->select_pending);
 
                        if (select_mailbox == NULL)
-                               g_weak_ref_set (
-                                       &is->priv->select_mailbox,
-                                       select_pending);
-
-                       g_weak_ref_set (&is->priv->select_closing, NULL);
+                               g_weak_ref_set (&is->priv->select_mailbox, select_pending);
 
                        g_mutex_unlock (&is->priv->select_lock);
 
-                       if (select_closing != NULL)
-                               g_signal_emit (
-                                       is, signals[MAILBOX_CLOSED], 0,
-                                       select_closing);
-
                        g_clear_object (&select_mailbox);
-                       g_clear_object (&select_closing);
                        g_clear_object (&select_pending);
                }
                break;
        case IMAPX_ALERT:
-               c (is->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
+               c (is->priv->tagprefix, "ALERT!: %s\n", is->priv->context->sinfo->text);
                {
                        const gchar *alert_message;
                        gboolean emit_alert = FALSE;
@@ -2981,16 +1795,16 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
                }
                break;
        case IMAPX_PARSE:
-               c (is->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
+               c (is->priv->tagprefix, "PARSE: %s\n", is->priv->context->sinfo->text);
                break;
        case IMAPX_CAPABILITY:
                if (is->priv->context->sinfo->u.cinfo) {
-                       struct _capability_info *cinfo = is->cinfo;
-                       is->cinfo = is->priv->context->sinfo->u.cinfo;
+                       struct _capability_info *cinfo = is->priv->cinfo;
+                       is->priv->cinfo = is->priv->context->sinfo->u.cinfo;
                        is->priv->context->sinfo->u.cinfo = NULL;
                        if (cinfo)
                                imapx_free_capability (cinfo);
-                       c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa : 
0xFFFFFFFF);
+                       c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? 
is->priv->cinfo->capa : 0xFFFFFFFF);
                        imapx_server_stash_command_arguments (is);
                }
                break;
@@ -3031,7 +1845,7 @@ imapx_untagged (CamelIMAPXServer *is,
        is->priv->context->lsub = FALSE;
        is->priv->context->fetch_order = fetch_order;
 
-       e (is->tagprefix, "got untagged response\n");
+       e (is->priv->tagprefix, "got untagged response\n");
        is->priv->context->id = 0;
        is->priv->context->tok = camel_imapx_input_stream_token (
                CAMEL_IMAPX_INPUT_STREAM (input_stream),
@@ -3060,7 +1874,7 @@ imapx_untagged (CamelIMAPXServer *is,
                goto exit;
        }
 
-       e (is->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
+       e (is->priv->tagprefix, "Have token '%s' id %lu\n", is->priv->context->token, is->priv->context->id);
        p = is->priv->context->token;
        while ((c = *p))
                *p++ = g_ascii_toupper ((gchar) c);
@@ -3072,12 +1886,12 @@ imapx_untagged (CamelIMAPXServer *is,
                desc = g_hash_table_lookup (is->priv->untagged_handlers, token);
                if (desc == NULL) {
                        /* unknown response, just ignore it */
-                       c (is->tagprefix, "unknown token: %s\n", is->priv->context->token);
+                       c (is->priv->tagprefix, "unknown token: %s\n", is->priv->context->token);
                        break;
                }
                if (desc->handler == NULL) {
                        /* no handler function, ignore token */
-                       c (is->tagprefix, "no handler for token: %s\n", is->priv->context->token);
+                       c (is->priv->tagprefix, "no handler for token: %s\n", is->priv->context->token);
                        break;
                }
 
@@ -3115,6 +1929,61 @@ exit:
        return success;
 }
 
+static gssize
+imapx_server_write_file_with_progress (GOutputStream *output_stream,
+                                      GInputStream *input_stream,
+                                      goffset file_size,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+       gssize n_read;
+       gsize bytes_copied, n_written;
+       gchar buffer[8192];
+       goffset file_offset;
+       gboolean res;
+
+       g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1);
+       g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
+
+       file_offset = 0;
+       bytes_copied = 0;
+       res = TRUE;
+       do {
+               n_read = g_input_stream_read (input_stream, buffer, sizeof (buffer), cancellable, error);
+               if (n_read == -1) {
+                       res = FALSE;
+                       break;
+               }
+
+               if (n_read == 0)
+                       break;
+
+               if (!g_output_stream_write_all (output_stream, buffer, n_read, &n_written, cancellable, 
error) || n_written == -1) {
+                       res = FALSE;
+                       break;
+               }
+
+               file_offset += n_read;
+
+               if (file_size > 0) {
+                       gdouble divd = (gdouble) file_offset / (gdouble) file_size;
+                       camel_operation_progress (cancellable, (gint) (100 * divd));
+               }
+
+               bytes_copied += n_written;
+               if (bytes_copied > G_MAXSSIZE)
+                       bytes_copied = G_MAXSSIZE;
+       } while (res);
+
+       if (res)
+               return bytes_copied;
+
+       return -1;
+}
+
 /* handle any continuation requests
  * either data continuations, or auth continuation */
 static gboolean
@@ -3125,7 +1994,7 @@ imapx_continuation (CamelIMAPXServer *is,
                     GCancellable *cancellable,
                     GError **error)
 {
-       CamelIMAPXCommand *ic, *newliteral = NULL;
+       CamelIMAPXCommand *ic, *newic = NULL;
        CamelIMAPXCommandPart *cp;
        GList *link;
        gssize n_bytes_written;
@@ -3143,57 +2012,32 @@ imapx_continuation (CamelIMAPXServer *is,
                if (!success)
                        return FALSE;
 
-               c (is->tagprefix, "Got continuation response for IDLE \n");
-               g_rec_mutex_lock (&is->priv->idle_lock);
-               /* We might have actually sent the DONE already! */
-               if (is->priv->idle_state == IMAPX_IDLE_ISSUED) {
-                       is->priv->idle_state = IMAPX_IDLE_STARTED;
-               } else if (is->priv->idle_state == IMAPX_IDLE_CANCEL) {
-                       /* IDLE got cancelled after we sent the command, while
-                        * we were waiting for this continuation. Send DONE
-                        * immediately. */
-                       if (!imapx_command_idle_stop (is, error)) {
-                               g_rec_mutex_unlock (&is->priv->idle_lock);
-                               return FALSE;
-                       }
-                       is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
-               } else if (is->priv->idle_state == IMAPX_IDLE_WAIT_DONE) {
-                       /* Do nothing, just wait */
-               } else {
-                       c (
-                               is->tagprefix, "idle starts in wrong state %d\n",
-                               is->priv->idle_state);
-               }
-               g_rec_mutex_unlock (&is->priv->idle_lock);
-
-               QUEUE_LOCK (is);
-               is->literal = NULL;
-               imapx_command_start_next (is);
-               QUEUE_UNLOCK (is);
+               c (is->priv->tagprefix, "Got continuation response for IDLE \n");
 
                return TRUE;
        }
 
-       ic = is->literal;
+       ic = is->priv->continuation_command;
        if (!litplus) {
                if (ic == NULL) {
-                       c (is->tagprefix, "got continuation response with no outstanding continuation 
requests?\n");
+                       c (is->priv->tagprefix, "got continuation response with no outstanding continuation 
requests?\n");
                        return camel_imapx_input_stream_skip (
                                CAMEL_IMAPX_INPUT_STREAM (input_stream),
                                cancellable, error);
                }
-               c (is->tagprefix, "got continuation response for data\n");
+               c (is->priv->tagprefix, "got continuation response for data\n");
        } else {
-               c (is->tagprefix, "sending LITERAL+ continuation\n");
+               c (is->priv->tagprefix, "sending LITERAL+ continuation\n");
+               g_return_val_if_fail (ic != NULL, FALSE);
        }
 
-       link = ic->current_part;
+       link = ic ? ic->current_part : NULL;
        g_return_val_if_fail (link != NULL, FALSE);
        cp = (CamelIMAPXCommandPart *) link->data;
 
        switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
        case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
-               c (is->tagprefix, "writing data wrapper to literal\n");
+               c (is->priv->tagprefix, "writing data wrapper to literal\n");
                n_bytes_written =
                        camel_data_wrapper_write_to_output_stream_sync (
                                CAMEL_DATA_WRAPPER (cp->ob),
@@ -3218,7 +2062,7 @@ imapx_continuation (CamelIMAPXServer *is,
                g_free (token);
                if (resp == NULL)
                        return FALSE;
-               c (is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
+               c (is->priv->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", 
resp);
 
                g_mutex_lock (&is->priv->stream_lock);
                n_bytes_written = g_output_stream_write_all (
@@ -3232,15 +2076,17 @@ imapx_continuation (CamelIMAPXServer *is,
 
                /* we want to keep getting called until we get a status reponse from the server
                 * ignore what sasl tells us */
-               newliteral = ic;
+               newic = ic;
                /* We already ate the end of the input stream line */
                goto noskip;
                break; }
        case CAMEL_IMAPX_COMMAND_FILE: {
                GFile *file;
+               GFileInfo *file_info;
                GFileInputStream *file_input_stream;
+               goffset file_size = 0;
 
-               c (is->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
+               c (is->priv->tagprefix, "writing file '%s' to literal\n", (gchar *) cp->ob);
 
                file = g_file_new_for_path (cp->ob);
                file_input_stream = g_file_read (file, cancellable, error);
@@ -3249,14 +2095,22 @@ imapx_continuation (CamelIMAPXServer *is,
                if (file_input_stream == NULL)
                        return FALSE;
 
+               file_info = g_file_input_stream_query_info (file_input_stream,
+                       G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, NULL);
+               if (file_info) {
+                       file_size = g_file_info_get_size (file_info);
+                       g_object_unref (file_info);
+               }
+
                g_mutex_lock (&is->priv->stream_lock);
-               n_bytes_written = g_output_stream_splice (
-                       output_stream,
-                       G_INPUT_STREAM (file_input_stream),
-                       G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
-                       cancellable, error);
+
+               n_bytes_written = imapx_server_write_file_with_progress (
+                       output_stream, G_INPUT_STREAM (file_input_stream),
+                       file_size, cancellable, error);
+
                g_mutex_unlock (&is->priv->stream_lock);
 
+               g_input_stream_close (G_INPUT_STREAM (file_input_stream), cancellable, NULL);
                g_object_unref (file_input_stream);
 
                if (n_bytes_written < 0)
@@ -3274,7 +2128,6 @@ imapx_continuation (CamelIMAPXServer *is,
                break;
        default:
                /* should we just ignore? */
-               is->literal = NULL;
                g_set_error (
                        error, CAMEL_IMAPX_ERROR, 1,
                        "continuation response for non-continuation request");
@@ -3296,7 +2149,7 @@ noskip:
                ic->current_part = link;
                cp = (CamelIMAPXCommandPart *) link->data;
 
-               c (is->tagprefix, "next part of command \"%c%05u: %s\"\n", is->tagprefix, ic->tag, cp->data);
+               c (is->priv->tagprefix, "next part of command \"%c%05u: %s\"\n", is->priv->tagprefix, 
ic->tag, cp->data);
 
                g_mutex_lock (&is->priv->stream_lock);
                n_bytes_written = g_output_stream_write_all (
@@ -3307,12 +2160,12 @@ noskip:
                        return FALSE;
 
                if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
-                       newliteral = ic;
+                       newic = ic;
                } else {
                        g_warn_if_fail (g_list_next (link) == NULL);
                }
        } else {
-               c (is->tagprefix, "%p: queueing continuation\n", ic);
+               c (is->priv->tagprefix, "%p: queueing continuation\n", ic);
        }
 
        g_mutex_lock (&is->priv->stream_lock);
@@ -3322,12 +2175,7 @@ noskip:
        if (n_bytes_written < 0)
                return FALSE;
 
-       QUEUE_LOCK (is);
-       is->literal = newliteral;
-
-       if (!litplus)
-               imapx_command_start_next (is);
-       QUEUE_UNLOCK (is);
+       is->priv->continuation_command = newic;
 
        return TRUE;
 }
@@ -3348,7 +2196,7 @@ imapx_completion (CamelIMAPXServer *is,
 
        /* Given "A0001 ...", 'A' = tag prefix, '0001' = tag. */
 
-       if (token[0] != is->tagprefix) {
+       if (token[0] != is->priv->tagprefix) {
                g_set_error (
                        error, CAMEL_IMAPX_ERROR, 1,
                        "Server sent unexpected response: %s", token);
@@ -3357,14 +2205,14 @@ imapx_completion (CamelIMAPXServer *is,
 
        tag = strtoul ((gchar *) token + 1, NULL, 10);
 
-       QUEUE_LOCK (is);
+       COMMAND_LOCK (is);
 
-       if (is->literal != NULL && is->literal->tag == tag)
-               ic = camel_imapx_command_ref (is->literal);
+       if (is->priv->current_command != NULL && is->priv->current_command->tag == tag)
+               ic = camel_imapx_command_ref (is->priv->current_command);
        else
-               ic = camel_imapx_command_queue_ref_by_tag (is->active, tag);
+               ic = NULL;
 
-       QUEUE_UNLOCK (is);
+       COMMAND_UNLOCK (is);
 
        if (ic == NULL) {
                g_set_error (
@@ -3373,55 +2221,39 @@ imapx_completion (CamelIMAPXServer *is,
                return FALSE;
        }
 
-       c (is->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
+       c (is->priv->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, 
camel_imapx_job_get_kind_name (ic->job_kind));
 
        if (camel_folder_change_info_changed (is->priv->changes)) {
-               CamelFolder *folder;
+               CamelFolder *folder = NULL;
                CamelIMAPXMailbox *mailbox;
 
-               g_mutex_lock (&is->priv->select_lock);
-               mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-               g_mutex_unlock (&is->priv->select_lock);
+               mailbox = camel_imapx_server_ref_selected (is);
 
-               g_return_val_if_fail (mailbox != NULL, FALSE);
+               g_warn_if_fail (mailbox != NULL);
 
-               folder = imapx_server_ref_folder (is, mailbox);
-               g_return_val_if_fail (folder != NULL, FALSE);
+               if (mailbox) {
+                       folder = imapx_server_ref_folder (is, mailbox);
+                       g_return_val_if_fail (folder != NULL, FALSE);
 
-               camel_folder_summary_save_to_db (folder->summary, NULL);
+                       camel_folder_summary_save_to_db (folder->summary, NULL);
+
+                       imapx_update_store_summary (folder);
+                       camel_folder_changed (folder, is->priv->changes);
+               }
 
-               imapx_update_store_summary (folder);
-               camel_folder_changed (folder, is->priv->changes);
                camel_folder_change_info_clear (is->priv->changes);
 
-               g_object_unref (folder);
-               g_object_unref (mailbox);
+               g_clear_object (&folder);
+               g_clear_object (&mailbox);
        }
 
-       QUEUE_LOCK (is);
-
-       /* Move the command from the active queue to the done queue.
-        * 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)
-               is->literal = NULL;
-
        if (g_list_next (ic->current_part) != NULL) {
-               QUEUE_UNLOCK (is);
                g_set_error (
                        error, CAMEL_IMAPX_ERROR, 1,
-                       "command still has unsent parts? %s", ic->name);
+                       "command still has unsent parts? %s", camel_imapx_job_get_kind_name (ic->job_kind));
                goto exit;
        }
 
-       camel_imapx_command_queue_remove (is->done, ic);
-
-       QUEUE_UNLOCK (is);
-
        mailbox = camel_imapx_server_ref_selected (is);
 
        ic->status = imapx_parse_status (
@@ -3439,21 +2271,16 @@ imapx_completion (CamelIMAPXServer *is,
                is->priv->is_cyrus = is->priv->is_cyrus || (ic->status->text && camel_strstrcase 
(ic->status->text, "cyrus"));
                if (is->priv->is_cyrus && ic->status->u.cinfo && (ic->status->u.cinfo->capa & list_extended) 
!= 0) {
                        /* Disable LIST-EXTENDED for cyrus servers */
-                       c (is->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
+                       c (is->priv->tagprefix, "Disabling LIST-EXTENDED extension for a Cyrus server\n");
                        ic->status->u.cinfo->capa &= ~list_extended;
                }
        }
 
-       if (ic->complete != NULL)
-               ic->complete (is, ic);
-
        success = TRUE;
 
 exit:
-       QUEUE_LOCK (is);
-       imapx_command_start_next (is);
-       QUEUE_UNLOCK (is);
 
+       ic->completed = TRUE;
        camel_imapx_command_unref (ic);
 
        return success;
@@ -3471,13 +2298,18 @@ imapx_step (CamelIMAPXServer *is,
        gint tok;
        gboolean success = FALSE;
 
-       // poll ? wait for other stuff? loop?
        tok = camel_imapx_input_stream_token (
                CAMEL_IMAPX_INPUT_STREAM (input_stream),
                &token, &len, cancellable, error);
 
        output_stream = camel_imapx_server_ref_output_stream (is);
-       g_return_val_if_fail (output_stream != NULL, FALSE);
+       if (!output_stream) {
+               g_set_error_literal (error,
+                       CAMEL_IMAPX_ERROR, 1,
+                       _("Cannot issue command, no stream available"));
+
+               return FALSE;
+       }
 
        switch (tok) {
                case IMAPX_TOK_ERROR:
@@ -3509,540 +2341,16 @@ imapx_step (CamelIMAPXServer *is,
        return success;
 }
 
-/* Used to run 1 command synchronously,
- * use for capa, login, and namespaces only. */
-static gboolean
-imapx_command_run (CamelIMAPXServer *is,
-                   CamelIMAPXCommand *ic,
-                   GCancellable *cancellable,
-                   GError **error)
-{
-       GInputStream *input_stream;
-       gboolean success = TRUE;
-
-       input_stream = camel_imapx_server_ref_input_stream (is);
-       g_return_val_if_fail (input_stream != NULL, FALSE);
-
-       camel_imapx_command_close (ic);
-
-       QUEUE_LOCK (is);
-       imapx_command_start (is, ic);
-       QUEUE_UNLOCK (is);
-
-       while (success && ic->status == NULL)
-               success = imapx_step (is, input_stream, cancellable, error);
-
-       if (is->literal == ic)
-               is->literal = NULL;
-
-       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);
-
-       return success;
-}
-
-static void
-imapx_command_complete (CamelIMAPXServer *is,
-                        CamelIMAPXCommand *ic)
-{
-       camel_imapx_command_done (ic);
-       camel_imapx_command_unref (ic);
-}
-
-static void
-imapx_command_cancelled (GCancellable *cancellable,
-                         CamelIMAPXCommand *ic)
-{
-       /* Unblock imapx_command_run_sync() immediately.
-        *
-        * If camel_imapx_command_done() is called sometime later,
-        * the GCond will broadcast but no one will be listening. */
-
-       camel_imapx_command_done (ic);
-}
-
-/* The caller should free the command as well */
-static gboolean
-imapx_command_run_sync (CamelIMAPXServer *is,
-                        CamelIMAPXCommand *ic,
-                        GCancellable *cancellable,
-                        GError **error)
-{
-       guint cancel_id = 0;
-       gboolean success = TRUE;
-
-       /* FIXME The only caller of this function currently does not set
-        *       a "complete" callback function, so we can get away with
-        *       referencing the command here and dropping the reference
-        *       in imapx_command_complete().  The queueing/dequeueing
-        *       of these things is too complex for my little mind, so
-        *       we may have to revisit the reference counting if this
-        *       function gets another caller. */
-
-       g_warn_if_fail (ic->complete == NULL);
-       ic->complete = imapx_command_complete;
-
-       if (G_IS_CANCELLABLE (cancellable))
-               cancel_id = g_cancellable_connect (
-                       cancellable,
-                       G_CALLBACK (imapx_command_cancelled),
-                       camel_imapx_command_ref (ic),
-                       (GDestroyNotify) camel_imapx_command_unref);
-
-       /* Unref'ed in imapx_command_complete(). */
-       camel_imapx_command_ref (ic);
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_wait (ic);
-
-       if (cancel_id > 0)
-               g_cancellable_disconnect (cancellable, cancel_id);
-
-       if (camel_imapx_command_set_error_if_failed (ic, error))
-               return FALSE;
-
-       return success;
-}
-
-static gboolean
-imapx_ensure_mailbox_permanentflags (CamelIMAPXServer *is,
-                                    CamelIMAPXMailbox *mailbox,
-                                    GCancellable *cancellable,
-                                    GError **error)
-{
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
-
-       if (camel_imapx_mailbox_get_permanentflags (mailbox) != ~0)
-               return TRUE;
-
-       /* This will also invoke SELECT command, which updates PERMANENTFLAGS
-          for the mailbox. There might be possible to use EXAMINE for it,
-          but some servers do not return the same set of flags as with SELECT.
-          It's a little hack on top of the IMAPx implementation. */
-       return camel_imapx_server_noop (is, mailbox, cancellable, error);
-}
-
-/* ********************************************************************** */
-// IDLE support
-
-/*TODO handle negative cases sanely */
-static gboolean
-imapx_command_idle_stop (CamelIMAPXServer *is,
-                         GError **error)
-{
-       GOutputStream *output_stream;
-       GCancellable *cancellable;
-       gboolean success;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
-
-       output_stream = camel_imapx_server_ref_output_stream (is);
-       g_return_val_if_fail (output_stream != NULL, FALSE);
-
-       cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
-       g_mutex_lock (&is->priv->stream_lock);
-       success = g_output_stream_write_all (
-               output_stream, "DONE\r\n", 6, NULL, cancellable, error);
-       g_mutex_unlock (&is->priv->stream_lock);
-
-       if (!success) {
-               g_prefix_error (error, "Unable to issue DONE: ");
-               c (is->tagprefix, "Failed to issue DONE to terminate IDLE\n");
-               is->state = IMAPX_SHUTDOWN;
-               g_main_loop_quit (is->priv->parser_main_loop);
-       }
-
-       g_clear_object (&cancellable);
-       g_clear_object (&output_stream);
-
-       return success;
-}
-
-static void
-imapx_command_idle_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error performing IDLE"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       g_rec_mutex_lock (&is->priv->idle_lock);
-       is->priv->idle_state = IMAPX_IDLE_OFF;
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_idle_start (CamelIMAPXJob *job,
-                      CamelIMAPXServer *is,
-                      GCancellable *cancellable,
-                      GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXCommandPart *cp;
-       CamelIMAPXMailbox *mailbox;
-       gboolean success = TRUE;
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "IDLE", mailbox, "IDLE");
-       camel_imapx_command_set_job (ic, job);
-       ic->pri = job->pri;
-       ic->complete = imapx_command_idle_done;
-
-       camel_imapx_command_close (ic);
-       cp = g_queue_peek_head (&ic->parts);
-       cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
-
-       QUEUE_LOCK (is);
-       g_rec_mutex_lock (&is->priv->idle_lock);
-       /* Don't issue it if the idle was cancelled already */
-       if (is->priv->idle_state == IMAPX_IDLE_PENDING) {
-               is->priv->idle_state = IMAPX_IDLE_ISSUED;
-
-               if (camel_imapx_command_queue_is_empty (is->active)) {
-                       imapx_command_start (is, ic);
-               } else {
-                       c (is->tagprefix, "finally cancelling IDLE, other command was quicker\n");
-                       is->priv->idle_state = IMAPX_IDLE_OFF;
-                       imapx_unregister_job (is, job);
-               }
-       } else {
-               imapx_unregister_job (is, job);
-       }
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-       QUEUE_UNLOCK (is);
-
-       camel_imapx_command_unref (ic);
-
-       g_object_unref (mailbox);
-
-       return success;
-}
-
-static gboolean
-camel_imapx_server_idle (CamelIMAPXServer *is,
-                         CamelIMAPXMailbox *mailbox,
-                         GCancellable *cancellable,
-                         GError **error)
-{
-       CamelIMAPXJob *job;
-       gint previous_connection_timeout;
-       gboolean success;
-
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_IDLE;
-       job->start = imapx_job_idle_start;
-
-       camel_imapx_job_set_mailbox (job, mailbox);
-       QUEUE_LOCK (is);
-       imapx_maybe_select (is, job, mailbox);
-       QUEUE_UNLOCK (is);
-
-       previous_connection_timeout = imapx_server_set_connection_timeout (is->priv->connection, 0);
-
-       success = imapx_submit_job (is, job, error);
-
-       if (previous_connection_timeout >= 0)
-               imapx_server_set_connection_timeout (is->priv->connection, previous_connection_timeout);
-
-       camel_imapx_job_unref (job);
-
-       return success;
-}
-
-static gboolean
-imapx_job_fetch_new_messages_matches (CamelIMAPXJob *job,
-                                      CamelIMAPXMailbox *mailbox,
-                                      const gchar *uid)
-{
-       return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-static gboolean
-imapx_server_fetch_new_messages (CamelIMAPXServer *is,
-                                 CamelIMAPXMailbox *mailbox,
-                                 gboolean async,
-                                 gboolean update_unseen,
-                                 GCancellable *cancellable,
-                                 GError **error)
-{
-       CamelIMAPXJob *job;
-       RefreshInfoData *data;
-       gboolean success;
-
-       data = g_slice_new0 (RefreshInfoData);
-       data->changes = camel_folder_change_info_new ();
-       data->update_unseen = update_unseen;
-
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_FETCH_NEW_MESSAGES;
-       job->start = imapx_job_fetch_new_messages_start;
-       job->matches = imapx_job_fetch_new_messages_matches;
-       job->noreply = async;
-
-       camel_imapx_job_set_mailbox (job, mailbox);
-
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) refresh_info_data_free);
-
-       success = imapx_submit_job (is, job, error);
-
-       camel_imapx_job_unref (job);
-
-       return success;
-}
-
-static gboolean
-imapx_call_idle (gpointer data)
-{
-       CamelFolder *folder;
-       CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *is;
-       CamelIMAPXMailbox *mailbox = NULL;
-       GCancellable *cancellable;
-       GError *local_error = NULL;
-
-       is = g_weak_ref_get (data);
-
-       if (is == NULL)
-               goto exit;
-
-       /* XXX Rename to 'pending_lock'? */
-       g_rec_mutex_lock (&is->priv->idle_lock);
-       g_source_unref (is->priv->idle_pending);
-       is->priv->idle_pending = NULL;
-
-       if (is->priv->idle_state != IMAPX_IDLE_PENDING) {
-               g_rec_mutex_unlock (&is->priv->idle_lock);
-               goto exit;
-       }
-
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-
-       imapx_store = camel_imapx_server_ref_store (is);
-       mailbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
-       g_clear_object (&imapx_store);
-
-       if (mailbox == NULL)
-               goto exit;
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       if (folder == NULL)
-               goto exit;
-
-       cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
-       /* We block here until the IDLE command completes. */
-       camel_imapx_server_idle (is, mailbox, cancellable, &local_error);
-
-       if (local_error == NULL) {
-               gboolean have_new_messages;
-               gboolean fetch_new_messages;
-
-               have_new_messages =
-                       camel_imapx_mailbox_get_messages (mailbox) >
-                       camel_folder_summary_count (folder->summary);
-
-               fetch_new_messages =
-                       have_new_messages &&
-                       imapx_is_command_queue_empty (is);
-
-               if (fetch_new_messages)
-                       imapx_server_fetch_new_messages (
-                               is, mailbox, TRUE, TRUE,
-                               cancellable, &local_error);
-       }
-
-       /* XXX Need a better way to propagate IDLE errors. */
-       if (local_error != NULL) {
-               if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
-                   is->state != IMAPX_SHUTDOWN)
-                       g_warning ("%s: %s", G_STRFUNC, local_error->message);
-               g_clear_error (&local_error);
-       }
-
-       g_clear_object (&folder);
-       g_clear_object (&cancellable);
-
-exit:
-       g_clear_object (&is);
-       g_clear_object (&mailbox);
-
-       return G_SOURCE_REMOVE;
-}
-
-static gpointer
-imapx_idle_thread (gpointer data)
-{
-       CamelIMAPXServer *is = (CamelIMAPXServer *) data;
-       GSource *pending;
-
-       g_main_context_push_thread_default (is->priv->idle_main_context);
-
-       /* Schedule the first IDLE command after a brief "dwell"
-        * delay so any other pending commands get priority.
-        *
-        * XXX Don't fully understand why this is necessary, but
-        *     for now just adapting old code and hoping to avoid
-        *     regressions.
-        */
-
-       g_rec_mutex_lock (&is->priv->idle_lock);
-
-       g_warn_if_fail (is->priv->idle_pending == NULL);
-       pending = g_timeout_source_new_seconds (IMAPX_IDLE_DWELL_TIME);
-       g_source_set_name (pending, "imapx_call_idle");
-       g_source_set_callback (
-               pending, imapx_call_idle,
-               imapx_weak_ref_new (is),
-               (GDestroyNotify) imapx_weak_ref_free);
-       g_source_attach (pending, is->priv->idle_main_context);
-       is->priv->idle_pending = g_source_ref (pending);
-       g_source_unref (pending);
-
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-
-       g_main_loop_run (is->priv->idle_main_loop);
-
-       g_main_context_pop_thread_default (is->priv->idle_main_context);
-
-       g_object_unref (is);
-
-       return NULL;
-}
-
-static CamelIMAPXIdleStopResult
-imapx_stop_idle (CamelIMAPXServer *is,
-                 GError **error)
-{
-       CamelIMAPXIdleStopResult result = IMAPX_IDLE_STOP_NOOP;
-       time_t now;
-
-       time (&now);
-
-       g_rec_mutex_lock (&is->priv->idle_lock);
-
-       switch (is->priv->idle_state) {
-               case IMAPX_IDLE_ISSUED:
-                       is->priv->idle_state = IMAPX_IDLE_CANCEL;
-                       result = IMAPX_IDLE_STOP_SUCCESS;
-                       break;
-
-               case IMAPX_IDLE_CANCEL:
-                       result = IMAPX_IDLE_STOP_SUCCESS;
-                       break;
-
-               case IMAPX_IDLE_WAIT_DONE:
-                       result = IMAPX_IDLE_STOP_WAIT_DONE;
-                       break;
-
-               case IMAPX_IDLE_STARTED:
-                       if (imapx_command_idle_stop (is, error)) {
-                               result = IMAPX_IDLE_STOP_WAIT_DONE;
-                               is->priv->idle_state = IMAPX_IDLE_WAIT_DONE;
-                       } else {
-                               result = IMAPX_IDLE_STOP_ERROR;
-                               is->priv->idle_state = IMAPX_IDLE_OFF;
-                               goto exit;
-                       }
-                       break;
-
-               case IMAPX_IDLE_PENDING:
-                       is->priv->idle_state = IMAPX_IDLE_OFF;
-                       break;
-
-               case IMAPX_IDLE_OFF:
-                       break;
-       }
-
-exit:
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-
-       return result;
-}
-
-static void
-imapx_start_idle (CamelIMAPXServer *is)
-{
-       if (camel_application_is_exiting)
-               return;
-
-       g_rec_mutex_lock (&is->priv->idle_lock);
-
-       if (is->priv->idle_state != IMAPX_IDLE_OFF) {
-               g_warn_if_fail (is->priv->idle_state == IMAPX_IDLE_OFF);
-               g_rec_mutex_unlock (&is->priv->idle_lock);
-               return;
-       }
-
-       is->priv->idle_state = IMAPX_IDLE_PENDING;
-
-       if (is->priv->idle_thread == NULL) {
-               is->priv->idle_thread = g_thread_new (
-                       NULL, imapx_idle_thread, g_object_ref (is));
-
-       } else if (is->priv->idle_pending == NULL) {
-               GSource *pending;
-
-               pending = g_idle_source_new ();
-               g_source_set_name (pending, "imapx_call_idle");
-               g_source_set_callback (
-                       pending, imapx_call_idle,
-                       imapx_weak_ref_new (is),
-                       (GDestroyNotify) imapx_weak_ref_free);
-               g_source_attach (pending, is->priv->idle_main_context);
-               is->priv->idle_pending = g_source_ref (pending);
-               g_source_unref (pending);
-       }
-
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-}
-
-static gboolean
-imapx_in_idle (CamelIMAPXServer *is)
-{
-       gboolean in_idle = FALSE;
-
-       g_rec_mutex_lock (&is->priv->idle_lock);
-
-       if (is->priv->idle_thread != NULL)
-               in_idle = (is->priv->idle_state > IMAPX_IDLE_OFF);
-
-       g_rec_mutex_unlock (&is->priv->idle_lock);
-
-       return in_idle;
-}
-
 static gboolean
 imapx_use_idle (CamelIMAPXServer *is)
 {
        gboolean use_idle = FALSE;
 
        /* No need for IDLE if the server supports NOTIFY. */
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY))
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY))
                return FALSE;
 
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, IDLE)) {
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, IDLE)) {
                CamelIMAPXSettings *settings;
 
                settings = camel_imapx_server_ref_settings (is);
@@ -4053,247 +2361,18 @@ imapx_use_idle (CamelIMAPXServer *is)
        return use_idle;
 }
 
-// end IDLE
-/* ********************************************************************** */
-static void
-imapx_command_select_done (CamelIMAPXServer *is,
-                           CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXMailbox *select_closing;
-       CamelIMAPXMailbox *select_pending;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               CamelIMAPXCommandQueue *failed;
-               GQueue trash = G_QUEUE_INIT;
-               GList *list, *link;
-               gboolean noperm_error;
-
-               c (is->tagprefix, "Select failed: %s\n", local_error ? local_error->message : "Unknown 
error");
-
-               g_mutex_lock (&is->priv->select_lock);
-               select_closing = g_weak_ref_get (&is->priv->select_closing);
-               select_pending = g_weak_ref_get (&is->priv->select_pending);
-               g_weak_ref_set (&is->priv->select_mailbox, NULL);
-               g_weak_ref_set (&is->priv->select_closing, NULL);
-               g_weak_ref_set (&is->priv->select_pending, NULL);
-               is->state = IMAPX_INITIALISED;
-               g_mutex_unlock (&is->priv->select_lock);
-
-               failed = camel_imapx_command_queue_new ();
-
-               QUEUE_LOCK (is);
-
-               noperm_error = select_pending != NULL && ic->status && ic->status->result == IMAPX_NO &&
-                       (ic->status->condition == IMAPX_NOPERM || ic->status->condition == IMAPX_UNKNOWN);
-
-               if (select_pending != NULL) {
-                       GList *head = camel_imapx_command_queue_peek_head_link (is->queue);
-
-                       for (link = head; link != NULL; link = g_list_next (link)) {
-                               CamelIMAPXCommand *cw = link->data;
-                               CamelIMAPXMailbox *cw_mailbox;
-
-                               cw_mailbox = camel_imapx_command_ref_mailbox (cw);
-
-                               if (cw_mailbox == select_pending) {
-                                       c (
-                                               is->tagprefix,
-                                               "Cancelling command '%s'(%p) "
-                                               "for mailbox '%s'\n",
-                                               cw->name, cw,
-                                               camel_imapx_mailbox_get_name (cw_mailbox));
-                                       g_queue_push_tail (&trash, link);
-                               }
-
-                               g_clear_object (&cw_mailbox);
-                       }
-               }
-
-               if (noperm_error) {
-                       /* This avoids another SELECT try on this mailbox;
-                          the mailbox can be write-only in this case. */
-                       if (camel_imapx_mailbox_get_permanentflags (select_pending) == ~0)
-                               camel_imapx_mailbox_set_permanentflags (select_pending, 0);
-               }
-
-               while ((link = g_queue_pop_head (&trash)) != NULL) {
-                       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);
-               }
-
-               QUEUE_UNLOCK (is);
-
-               list = camel_imapx_command_queue_peek_head_link (failed);
-
-               for (link = list; link != NULL; link = g_list_next (link)) {
-                       CamelIMAPXCommand *cw = link->data;
-                       CamelIMAPXJob *failed_job;
-
-                       failed_job = camel_imapx_command_get_job (cw);
-
-                       if (!CAMEL_IS_IMAPX_JOB (failed_job)) {
-                               g_warn_if_reached ();
-                               continue;
-                       }
-
-                       if (!noperm_error)
-                               camel_imapx_job_cancel (failed_job);
-
-                       if (ic->status)
-                               cw->status = imapx_copy_status (ic->status);
-
-                       cw->complete (is, cw);
-               }
-
-               camel_imapx_command_queue_free (failed);
-
-               camel_imapx_job_take_error (job, local_error);
-               imapx_unregister_job (is, job);
-
-       } else {
-               CamelFolder *folder;
-               CamelIMAPXSummary *imapx_summary;
-               guint32 uidnext;
-
-               c (is->tagprefix, "Select ok!\n");
-
-               g_mutex_lock (&is->priv->select_lock);
-               select_closing = g_weak_ref_get (&is->priv->select_closing);
-               select_pending = g_weak_ref_get (&is->priv->select_pending);
-               g_weak_ref_set (&is->priv->select_mailbox, select_pending);
-               g_weak_ref_set (&is->priv->select_closing, NULL);
-               g_weak_ref_set (&is->priv->select_pending, NULL);
-               is->state = IMAPX_SELECTED;
-               g_mutex_unlock (&is->priv->select_lock);
-
-               /* We should have a strong reference
-                * on the newly-selected CamelFolder. */
-               folder = imapx_server_ref_folder (is, select_pending);
-               g_return_if_fail (folder != NULL);
-
-               uidnext = camel_imapx_mailbox_get_uidnext (select_pending);
-               imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
-
-               if (imapx_summary->uidnext < uidnext) {
-                       /* We don't want to fetch new messages if the command we selected this
-                        * folder for is *already* fetching all messages (i.e. scan_changes).
-                        * Bug #667725. */
-                       CamelIMAPXJob *job = imapx_server_ref_job (
-                               is, select_pending,
-                               IMAPX_JOB_REFRESH_INFO, NULL);
-                       if (job) {
-                               camel_imapx_job_unref (job);
-                               c (
-                                       is->tagprefix,
-                                       "Will not fetch_new_messages when already refreshing information\n");
-                       } else {
-                               imapx_server_fetch_new_messages (is, select_pending, TRUE, TRUE, NULL, NULL);
-                       }
-               }
-
-#if 0  /* see comment for disabled bits in imapx_job_refresh_info_start() */
-               /* This should trigger a new messages scan */
-               if (is->exists != folder->summary->root_view->total_count)
-                       g_warning (
-                               "exists is %d our summary is %d and summary exists is %d\n", is->exists,
-                               folder->summary->root_view->total_count,
-                               ((CamelIMAPXSummary *) folder->summary)->exists);
-#endif
-
-               g_clear_object (&folder);
-       }
-
-       if (select_closing != NULL)
-               g_signal_emit (is, signals[MAILBOX_CLOSED], 0, select_closing);
-
-       g_clear_object (&select_closing);
-       g_clear_object (&select_pending);
-}
-
-/* Should have a queue lock. TODO Change the way select is written */
-static void
-imapx_maybe_select (CamelIMAPXServer *is,
-                    CamelIMAPXJob *job,
-                    CamelIMAPXMailbox *mailbox)
+static gboolean
+imapx_in_idle (CamelIMAPXServer *is)
 {
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *select_mailbox;
-       CamelIMAPXMailbox *select_pending;
-       gboolean nothing_to_do = FALSE;
-
-       /* Select is complicated by the fact we may have commands
-        * active on the server for a different selection.
-        *
-        * So this waits for any commands to complete, selects the
-        * new mailbox, and halts the queuing of any new commands.
-        * It is assumed whomever called us is about to issue a
-        * high-priority command anyway. */
-
-       g_mutex_lock (&is->priv->select_lock);
-
-       select_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       select_pending = g_weak_ref_get (&is->priv->select_pending);
-
-       if (select_pending != NULL) {
-               nothing_to_do = TRUE;
-       } else if (select_mailbox == mailbox) {
-               nothing_to_do = TRUE;
-       } else if (!camel_imapx_command_queue_is_empty (is->active)) {
-               nothing_to_do = TRUE;
-       } else {
-               g_weak_ref_set (&is->priv->select_pending, mailbox);
-
-               if (select_mailbox != NULL) {
-                       g_weak_ref_set (&is->priv->select_mailbox, NULL);
-               } else {
-                       /* If no mailbox was selected, we won't get a
-                        * [CLOSED] status so just point select_mailbox
-                        * at the newly-selected mailbox immediately. */
-                       g_weak_ref_set (&is->priv->select_mailbox, mailbox);
-               }
-
-               g_weak_ref_set (&is->priv->select_closing, select_mailbox);
-
-               /* Hrm, what about reconnecting? */
-               is->state = IMAPX_INITIALISED;
-       }
-
-       g_clear_object (&select_mailbox);
-       g_clear_object (&select_pending);
-
-       g_mutex_unlock (&is->priv->select_lock);
-
-       if (nothing_to_do)
-               return;
-
-       g_signal_emit (is, signals[MAILBOX_SELECT], 0, mailbox);
-
-       ic = camel_imapx_command_new (
-               is, "SELECT", NULL, "SELECT %M", mailbox);
+       gboolean in_idle;
 
-       if (is->use_qresync) {
-               CamelFolder *folder;
-
-               folder = imapx_server_ref_folder (is, mailbox);
-               camel_imapx_command_add_qresync_parameter (ic, folder);
-               g_clear_object (&folder);
-       }
-
-       ic->complete = imapx_command_select_done;
-       camel_imapx_command_set_job (ic, job);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       imapx_command_start (is, ic);
+       g_rec_mutex_lock (&is->priv->idle_lock);
+       in_idle = is->priv->idle_running || is->priv->idle_pending;
+       g_rec_mutex_unlock (&is->priv->idle_lock);
 
-       camel_imapx_command_unref (ic);
+       return in_idle;
 }
 
 static void
@@ -4307,7 +2386,7 @@ imapx_server_set_streams (CamelIMAPXServer *is,
                GInputStream *temp_stream;
 
                /* The logger produces debugging output. */
-               logger = camel_imapx_logger_new (is->tagprefix);
+               logger = camel_imapx_logger_new (is->priv->tagprefix);
                input_stream = g_converter_input_stream_new (
                        input_stream, logger);
                g_clear_object (&logger);
@@ -4324,7 +2403,7 @@ imapx_server_set_streams (CamelIMAPXServer *is,
 
        if (output_stream != NULL) {
                /* The logger produces debugging output. */
-               logger = camel_imapx_logger_new (is->tagprefix);
+               logger = camel_imapx_logger_new (is->priv->tagprefix);
                output_stream = g_converter_output_stream_new (
                        output_stream, logger);
                g_clear_object (&logger);
@@ -4535,7 +2614,7 @@ connect_to_server_process (CamelIMAPXServer *is,
        return TRUE;
 }
 
-gboolean
+static gboolean
 imapx_connect_to_server (CamelIMAPXServer *is,
                          GCancellable *cancellable,
                          GError **error)
@@ -4663,20 +2742,10 @@ connected:
                        goto exit;
        }
 
-       if (!is->cinfo) {
-               ic = camel_imapx_command_new (
-                       is, "CAPABILITY", NULL, "CAPABILITY");
+       if (!is->priv->cinfo) {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
 
-               success = imapx_command_run (is, ic, cancellable, error);
-
-               /* Server reported error. */
-               if (success && ic->status->result != IMAPX_OK) {
-                       g_set_error (
-                               error, CAMEL_ERROR,
-                               CAMEL_ERROR_GENERIC,
-                               "%s", ic->status->text);
-                       success = FALSE;
-               }
+               success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"), 
cancellable, error);
 
                camel_imapx_command_unref (ic);
 
@@ -4686,7 +2755,7 @@ connected:
 
        if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
 
-               if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, STARTTLS)) {
+               if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, STARTTLS)) {
                        g_set_error (
                                &local_error, CAMEL_ERROR,
                                CAMEL_ERROR_GENERIC,
@@ -4695,29 +2764,19 @@ connected:
                        goto exit;
                }
 
-               ic = camel_imapx_command_new (
-                       is, "STARTTLS", NULL, "STARTTLS");
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STARTTLS, "STARTTLS");
 
-               success = imapx_command_run (is, ic, cancellable, error);
-
-               /* Server reported error. */
-               if (success && ic->status->result != IMAPX_OK) {
-                       g_set_error (
-                               error, CAMEL_ERROR,
-                               CAMEL_ERROR_GENERIC,
-                               "%s", ic->status->text);
-                       success = FALSE;
-               }
+               success = camel_imapx_server_process_command_sync (is, ic, _("Failed to issue STARTTLS"), 
cancellable, error);
 
                if (success) {
                        /* See if we got new capabilities
                         * in the STARTTLS response. */
-                       imapx_free_capability (is->cinfo);
-                       is->cinfo = NULL;
+                       imapx_free_capability (is->priv->cinfo);
+                       is->priv->cinfo = NULL;
                        if (ic->status->condition == IMAPX_CAPABILITY) {
-                               is->cinfo = ic->status->u.cinfo;
+                               is->priv->cinfo = ic->status->u.cinfo;
                                ic->status->u.cinfo = NULL;
-                               c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa 
: 0xFFFFFFFF);
+                               c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? 
is->priv->cinfo->capa : 0xFFFFFFFF);
                                imapx_server_stash_command_arguments (is);
                        }
                }
@@ -4758,10 +2817,9 @@ connected:
                }
 
                /* Get new capabilities if they weren't already given */
-               if (is->cinfo == NULL) {
-                       ic = camel_imapx_command_new (
-                               is, "CAPABILITY", NULL, "CAPABILITY");
-                       success = imapx_command_run (is, ic, cancellable, error);
+               if (is->priv->cinfo == NULL) {
+                       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+                       success = camel_imapx_server_process_command_sync (is, ic, _("Failed to get 
capabilities"), cancellable, error);
                        camel_imapx_command_unref (ic);
 
                        if (!success)
@@ -4778,9 +2836,9 @@ exit:
                g_clear_object (&is->priv->connection);
                g_clear_object (&is->priv->subprocess);
 
-               if (is->cinfo != NULL) {
-                       imapx_free_capability (is->cinfo);
-                       is->cinfo = NULL;
+               if (is->priv->cinfo != NULL) {
+                       imapx_free_capability (is->priv->cinfo);
+                       is->priv->cinfo = NULL;
                }
 
                g_mutex_unlock (&is->priv->stream_lock);
@@ -4799,14 +2857,14 @@ camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server)
 {
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
 
-       return imapx_server->state >= IMAPX_CONNECTED;
+       return imapx_server->priv->state >= IMAPX_CONNECTED;
 }
 
 CamelAuthenticationResult
-camel_imapx_server_authenticate (CamelIMAPXServer *is,
-                                 const gchar *mechanism,
-                                 GCancellable *cancellable,
-                                 GError **error)
+camel_imapx_server_authenticate_sync (CamelIMAPXServer *is,
+                                     const gchar *mechanism,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
        CamelNetworkSettings *network_settings;
        CamelIMAPXStore *store;
@@ -4834,7 +2892,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
        g_object_unref (settings);
 
        if (mechanism != NULL) {
-               if (is->cinfo && !g_hash_table_lookup (is->cinfo->auth_types, mechanism)) {
+               if (is->priv->cinfo && !g_hash_table_lookup (is->priv->cinfo->auth_types, mechanism)) {
                        g_set_error (
                                error, CAMEL_SERVICE_ERROR,
                                CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -4857,8 +2915,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
        }
 
        if (sasl != NULL) {
-               ic = camel_imapx_command_new (
-                       is, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_AUTHENTICATE, "AUTHENTICATE %A", sasl);
        } else {
                const gchar *password;
 
@@ -4882,11 +2939,10 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
                        goto exit;
                }
 
-               ic = camel_imapx_command_new (
-                       is, "LOGIN", NULL, "LOGIN %s %s", user, password);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LOGIN, "LOGIN %s %s", user, password);
        }
 
-       if (!imapx_command_run (is, ic, cancellable, error))
+       if (!camel_imapx_server_process_command_sync (is, ic, _("Failed to authenticate"), cancellable, 
error))
                result = CAMEL_AUTHENTICATION_ERROR;
        else if (ic->status->result == IMAPX_OK)
                result = CAMEL_AUTHENTICATION_ACCEPTED;
@@ -4927,15 +2983,15 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
 
        /* Forget old capabilities after login. */
        if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
-               if (is->cinfo) {
-                       imapx_free_capability (is->cinfo);
-                       is->cinfo = NULL;
+               if (is->priv->cinfo) {
+                       imapx_free_capability (is->priv->cinfo);
+                       is->priv->cinfo = NULL;
                }
 
                if (ic->status->condition == IMAPX_CAPABILITY) {
-                       is->cinfo = ic->status->u.cinfo;
+                       is->priv->cinfo = ic->status->u.cinfo;
                        ic->status->u.cinfo = NULL;
-                       c (is->tagprefix, "got capability flags %08x\n", is->cinfo ? is->cinfo->capa : 
0xFFFFFFFF);
+                       c (is->priv->tagprefix, "got capability flags %08x\n", is->priv->cinfo ? 
is->priv->cinfo->capa : 0xFFFFFFFF);
                        imapx_server_stash_command_arguments (is);
                }
        }
@@ -4986,7 +3042,7 @@ imapx_reconnect (CamelIMAPXServer *is,
        if (!imapx_connect_to_server (is, cancellable, error))
                goto exception;
 
-       if (is->state == IMAPX_AUTHENTICATED)
+       if (is->priv->state == IMAPX_AUTHENTICATED)
                goto preauthed;
 
        if (!camel_session_authenticate_sync (
@@ -4994,12 +3050,11 @@ imapx_reconnect (CamelIMAPXServer *is,
                goto exception;
 
        /* After login we re-capa unless the server already told us. */
-       if (is->cinfo == NULL) {
+       if (is->priv->cinfo == NULL) {
                GError *local_error = NULL;
 
-               ic = camel_imapx_command_new (
-                       is, "CAPABILITY", NULL, "CAPABILITY");
-               imapx_command_run (is, ic, cancellable, &local_error);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CAPABILITY, "CAPABILITY");
+               camel_imapx_server_process_command_sync (is, ic, _("Failed to get capabilities"), 
cancellable, &local_error);
                camel_imapx_command_unref (ic);
 
                if (local_error != NULL) {
@@ -5008,16 +3063,15 @@ imapx_reconnect (CamelIMAPXServer *is,
                }
        }
 
-       is->state = IMAPX_AUTHENTICATED;
+       is->priv->state = IMAPX_AUTHENTICATED;
 
 preauthed:
        /* Fetch namespaces (if supported). */
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NAMESPACE)) {
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
                GError *local_error = NULL;
 
-               ic = camel_imapx_command_new (
-                       is, "NAMESPACE", NULL, "NAMESPACE");
-               imapx_command_run (is, ic, cancellable, &local_error);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NAMESPACE, "NAMESPACE");
+               camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NAMESPACE"), cancellable, 
&local_error);
                camel_imapx_command_unref (ic);
 
                if (local_error != NULL) {
@@ -5027,12 +3081,11 @@ preauthed:
        }
 
        /* Enable quick mailbox resynchronization (if supported). */
-       if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, QRESYNC)) {
+       if (use_qresync && CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, QRESYNC)) {
                GError *local_error = NULL;
 
-               ic = camel_imapx_command_new (
-                       is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
-               imapx_command_run (is, ic, cancellable, &local_error);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_ENABLE, "ENABLE CONDSTORE QRESYNC");
+               camel_imapx_server_process_command_sync (is, ic, _("Failed to enable QResync"), cancellable, 
&local_error);
                camel_imapx_command_unref (ic);
 
                if (local_error != NULL) {
@@ -5040,18 +3093,17 @@ preauthed:
                        goto exception;
                }
 
-               is->use_qresync = TRUE;
+               is->priv->use_qresync = TRUE;
        } else {
-               is->use_qresync = FALSE;
+               is->priv->use_qresync = FALSE;
        }
 
        /* Set NOTIFY options after enabling QRESYNC (if supported). */
-       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, NOTIFY)) {
+       if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, NOTIFY)) {
                GError *local_error = NULL;
 
                /* XXX The list of FETCH attributes is negotiable. */
-               ic = camel_imapx_command_new (
-                       is, "NOTIFY", NULL, "NOTIFY SET "
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOTIFY, "NOTIFY SET "
                        "(selected "
                        "(MessageNew (UID RFC822.SIZE RFC822.HEADER FLAGS)"
                        " MessageExpunge"
@@ -5061,7 +3113,7 @@ preauthed:
                        " MessageExpunge"
                        " MailboxName"
                        " SubscriptionChange))");
-               imapx_command_run (is, ic, cancellable, &local_error);
+               camel_imapx_server_process_command_sync (is, ic, _("Failed to issue NOTIFY"), cancellable, 
&local_error);
                camel_imapx_command_unref (ic);
 
                if (local_error != NULL) {
@@ -5070,7 +3122,7 @@ preauthed:
                }
        }
 
-       is->state = IMAPX_INITIALISED;
+       is->priv->state = IMAPX_INITIALISED;
 
        success = TRUE;
 
@@ -5079,9 +3131,9 @@ preauthed:
 exception:
        imapx_disconnect (is);
 
-       if (is->cinfo) {
-               imapx_free_capability (is->cinfo);
-               is->cinfo = NULL;
+       if (is->priv->cinfo) {
+               imapx_free_capability (is->priv->cinfo);
+               is->priv->cinfo = NULL;
        }
 
 exit:
@@ -5095,2318 +3147,6 @@ exit:
 
 /* ********************************************************************** */
 
-static void
-imapx_command_fetch_message_done (CamelIMAPXServer *is,
-                                  CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GetMessageData *data;
-       CamelIMAPXMailbox *mailbox;
-       GCancellable *cancellable;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       /* This is only for pushing status messages. */
-       cancellable = camel_imapx_job_get_cancellable (job);
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       /* We either have more to fetch (partial mode?), we are complete,
-        * or we failed.  Failure is handled in the fetch code, so
-        * we just return the job, or keep it alive with more requests */
-
-       g_atomic_int_add (&job->commands, -1);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching message"));
-
-       } else if (data->use_multi_fetch) {
-               gsize really_fetched = g_seekable_tell (G_SEEKABLE (data->stream));
-               /* Don't automatically stop when we reach the reported message
-                * size -- some crappy servers (like Microsoft Exchange) have
-                * a tendency to lie about it. Keep going (one request at a
-                * time) until the data actually stop coming. */
-               if (data->fetch_offset < data->size ||
-                   data->fetch_offset == really_fetched) {
-                       CamelIMAPXCommand *new_ic;
-
-                       camel_operation_progress (
-                               cancellable,
-                               (data->fetch_offset *100) / data->size);
-
-                       new_ic = camel_imapx_command_new (
-                               is, "FETCH", mailbox,
-                               "UID FETCH %t (BODY.PEEK[]",
-                               data->uid);
-                       camel_imapx_command_add (new_ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
-                       camel_imapx_command_add (new_ic, ")");
-                       new_ic->complete = imapx_command_fetch_message_done;
-                       camel_imapx_command_set_job (new_ic, job);
-                       new_ic->pri = job->pri - 1;
-                       data->fetch_offset += MULTI_SIZE;
-                       g_atomic_int_add (&job->commands, 1);
-
-                       imapx_command_queue (is, new_ic);
-
-                       camel_imapx_command_unref (new_ic);
-
-                       goto exit;
-               }
-       }
-
-       /* If we have more messages to fetch, skip the rest. */
-       if (g_atomic_int_get (&job->commands) > 0) {
-               /* Make sure no command will starve in a queue */
-               QUEUE_LOCK (is);
-               imapx_command_start_next (is);
-               QUEUE_UNLOCK (is);
-
-               goto exit;
-       }
-
-       /* No more messages to fetch, let's wrap things up. */
-
-       if (local_error == NULL) {
-               g_io_stream_close (data->stream, cancellable, &local_error);
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Failed to close the tmp stream"));
-       }
-
-       if (local_error == NULL &&
-           g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching message"));
-       }
-
-       if (local_error == NULL) {
-               gchar *cur_filename;
-               gchar *tmp_filename;
-               gchar *dirname;
-
-               cur_filename = camel_data_cache_get_filename (
-                       data->message_cache, "cur", data->uid);
-
-               tmp_filename = camel_data_cache_get_filename (
-                       data->message_cache, "tmp", data->uid);
-
-               dirname = g_path_get_dirname (cur_filename);
-               g_mkdir_with_parents (dirname, 0700);
-               g_free (dirname);
-
-               if (g_rename (tmp_filename, cur_filename) == 0) {
-                       /* Exchange the "tmp" stream for the "cur" stream. */
-                       g_clear_object (&data->stream);
-                       data->stream = camel_data_cache_get (
-                               data->message_cache, "cur",
-                               data->uid, &local_error);
-               } else {
-                       g_set_error (
-                               &local_error, G_FILE_ERROR,
-                               g_file_error_from_errno (errno),
-                               "%s: %s",
-                               _("Failed to copy the tmp file"),
-                               g_strerror (errno));
-               }
-
-               g_free (cur_filename);
-               g_free (tmp_filename);
-       }
-
-       /* Delete the 'tmp' file only if the operation succeeded. It's because
-          cancelled operations end before they are properly finished (IMAP-protocol speaking),
-          thus if any other GET_MESSAGE operation was waiting for this job, then it
-          realized that the message was not downloaded and opened its own "tmp" file, but
-          of the same name, thus this remove would drop file which could be used
-          by a different GET_MESSAGE job. */
-       if (!local_error && !g_cancellable_is_cancelled (cancellable))
-               camel_data_cache_remove (data->message_cache, "tmp", data->uid, NULL);
-
-       /* Avoid possible use-after-free when the imapx_unregister_job() can
-          also free the 'job' structure. */
-       camel_imapx_job_ref (job);
-
-       imapx_unregister_job (is, job);
-
-       if (local_error != NULL) {
-               CamelIMAPXJob *pending_job;
-
-               /* Give a chance to other threads. */
-               g_thread_yield ();
-
-               pending_job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, data->uid);
-               if (pending_job != NULL) {
-                       GIOStream *cache_stream;
-
-                       /* Wait for the job to finish. */
-                       camel_imapx_job_wait (pending_job, NULL);
-                       camel_imapx_job_unref (pending_job);
-
-                       /* Disregard errors here.  If we failed to retrieve the
-                        * message from cache (implying the job we were waiting
-                        * on failed or got cancelled), we'll just re-fetch it. */
-                       cache_stream = camel_data_cache_get (data->message_cache, "cur", data->uid, NULL);
-                       if (cache_stream != NULL) {
-                               g_clear_error (&local_error);
-
-                               g_clear_object (&data->stream);
-                               data->stream = cache_stream;
-                       }
-               }
-
-               if (local_error) {
-                       camel_imapx_job_take_error (job, local_error);
-                       local_error = NULL;
-               }
-       }
-
-       camel_imapx_job_unref (job);
-
-exit:
-       if (local_error != NULL)
-               camel_imapx_job_take_error (job, local_error);
-
-       g_object_unref (mailbox);
-}
-
-static gboolean
-imapx_job_get_message_start (CamelIMAPXJob *job,
-                             CamelIMAPXServer *is,
-                             GCancellable *cancellable,
-                             GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-       GetMessageData *data;
-       gint i;
-       gboolean success = TRUE;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       if (data->use_multi_fetch) {
-               for (i = 0; i < 3 && data->fetch_offset < data->size; i++) {
-                       ic = camel_imapx_command_new (
-                               is, "FETCH", mailbox,
-                               "UID FETCH %t (BODY.PEEK[]",
-                               data->uid);
-                       camel_imapx_command_add (ic, "<%u.%u>", data->fetch_offset, MULTI_SIZE);
-                       camel_imapx_command_add (ic, ")");
-                       ic->complete = imapx_command_fetch_message_done;
-                       camel_imapx_command_set_job (ic, job);
-                       ic->pri = job->pri;
-                       data->fetch_offset += MULTI_SIZE;
-                       g_atomic_int_add (&job->commands, 1);
-
-                       imapx_command_queue (is, ic);
-
-                       camel_imapx_command_unref (ic);
-               }
-       } else {
-               ic = camel_imapx_command_new (
-                       is, "FETCH", mailbox,
-                       "UID FETCH %t (BODY.PEEK[])",
-                       data->uid);
-               ic->complete = imapx_command_fetch_message_done;
-               camel_imapx_command_set_job (ic, job);
-               ic->pri = job->pri;
-               g_atomic_int_add (&job->commands, 1);
-
-               imapx_command_queue (is, ic);
-
-               camel_imapx_command_unref (ic);
-       }
-
-       g_object_unref (mailbox);
-
-       return success;
-}
-
-static gboolean
-imapx_job_get_message_matches (CamelIMAPXJob *job,
-                               CamelIMAPXMailbox *mailbox,
-                               const gchar *uid)
-{
-       GetMessageData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       if (!camel_imapx_job_has_mailbox (job, mailbox))
-               return FALSE;
-
-       if (g_strcmp0 (uid, data->uid) != 0)
-               return FALSE;
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
-                                       CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelFolder *folder;
-       CamelIMAPXMailbox *mailbox;
-       CopyMessagesData *data;
-       GPtrArray *uids;
-       gint i;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       uids = data->uids;
-       i = data->index;
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               if (data->use_move_command)
-                       g_prefix_error (
-                               &local_error, "%s: ",
-                               _("Error moving messages"));
-               else
-                       g_prefix_error (
-                               &local_error, "%s: ",
-                               _("Error copying messages"));
-               camel_imapx_job_take_error (job, local_error);
-               goto exit;
-       }
-
-       if (ic->status && ic->status->u.copyuid.uids && ic->status->u.copyuid.copied_uids &&
-           ic->status->u.copyuid.uids->len == ic->status->u.copyuid.copied_uids->len) {
-               CamelFolder *destination;
-
-               destination = imapx_server_ref_folder (is, data->destination);
-               if (destination) {
-                       CamelMessageInfo *source_info, *destination_info;
-                       CamelFolderChangeInfo *changes;
-                       gint ii;
-
-                       changes = camel_folder_change_info_new ();
-
-                       for (ii = 0; ii < ic->status->u.copyuid.uids->len; ii++) {
-                               gchar *uid;
-                               gboolean is_new = FALSE;
-
-                               uid = g_strdup_printf ("%d", g_array_index (ic->status->u.copyuid.uids, 
guint32, ii));
-                               source_info = camel_folder_summary_get (folder->summary, uid);
-                               g_free (uid);
-
-                               if (!source_info)
-                                       continue;
-
-                               uid = g_strdup_printf ("%d", g_array_index 
(ic->status->u.copyuid.copied_uids, guint32, ii));
-                               destination_info = camel_folder_summary_get (folder->summary, uid);
-
-                               if (!destination_info) {
-                                       is_new = TRUE;
-                                       destination_info = camel_message_info_clone (source_info);
-                                       destination_info->summary = destination->summary;
-                                       camel_pstring_free (destination_info->uid);
-                                       destination_info->uid = camel_pstring_strdup (uid);
-                               }
-
-                               g_free (uid);
-
-                               imapx_set_message_info_flags_for_new_message (
-                                       destination_info,
-                                       ((CamelMessageInfoBase *) source_info)->flags,
-                                       ((CamelMessageInfoBase *) source_info)->user_flags,
-                                       TRUE,
-                                       ((CamelMessageInfoBase *) source_info)->user_tags,
-                                       camel_imapx_mailbox_get_permanentflags (data->destination));
-                               if (data->remove_deleted_flags)
-                                       camel_message_info_set_flags (destination_info, 
CAMEL_MESSAGE_DELETED, 0);
-                               if (is_new)
-                                       camel_folder_summary_add (destination->summary, destination_info);
-                               camel_folder_change_info_add_uid (changes, destination_info->uid);
-
-                               camel_message_info_unref (source_info);
-                               if (!is_new)
-                                       camel_message_info_unref (destination_info);
-                       }
-
-                       if (camel_folder_change_info_changed (changes)) {
-                               camel_folder_summary_touch (destination->summary);
-                               camel_folder_summary_save_to_db (destination->summary, NULL);
-                               camel_folder_changed (destination, changes);
-                       }
-
-                       camel_folder_change_info_free (changes);
-                       g_object_unref (destination);
-               }
-       }
-
-       if (data->delete_originals || data->use_move_command) {
-               CamelFolderChangeInfo *changes = NULL;
-               gint j;
-
-               camel_folder_freeze (folder);
-
-               for (j = data->last_index; j < i; j++) {
-                       const gchar *uid = uids->pdata[j];
-
-                       if (data->delete_originals) {
-                               camel_folder_delete_message (folder, uid);
-                       } else {
-                               if (camel_folder_summary_remove_uid (folder->summary, uid)) {
-                                       if (!changes)
-                                               changes = camel_folder_change_info_new ();
-
-                                       camel_folder_change_info_remove_uid (changes, uid);
-                               }
-                       }
-               }
-
-               if (changes && camel_folder_change_info_changed (changes)) {
-                       camel_folder_summary_touch (folder->summary);
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
-                       camel_folder_changed (folder, changes);
-               }
-
-               camel_folder_thaw (folder);
-
-               if (changes)
-                       camel_folder_change_info_free (changes);
-       }
-
-       if (i < uids->len) {
-               imapx_command_copy_messages_step_start (
-                       is, job, i, &local_error);
-
-               if (local_error != NULL)
-                       camel_imapx_job_take_error (job, local_error);
-       }
-
-exit:
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
-                                        CamelIMAPXJob *job,
-                                        gint index,
-                                        GError **error)
-{
-       CamelIMAPXMailbox *mailbox;
-       CamelIMAPXCommand *ic;
-       CopyMessagesData *data;
-       GPtrArray *uids;
-       gint i = index;
-       gboolean success = TRUE;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       uids = data->uids;
-
-       if (data->use_move_command)
-               ic = camel_imapx_command_new (is, "MOVE", mailbox, "UID MOVE ");
-       else
-               ic = camel_imapx_command_new (is, "COPY", mailbox, "UID COPY ");
-       ic->complete = imapx_command_copy_messages_step_done;
-       camel_imapx_command_set_job (ic, job);
-       ic->pri = job->pri;
-       data->last_index = i;
-
-       g_object_unref (mailbox);
-
-       for (; i < uids->len; i++) {
-               gint res;
-               const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
-
-               res = imapx_uidset_add (&data->uidset, ic, uid);
-               if (res == 1) {
-                       camel_imapx_command_add (ic, " %M", data->destination);
-                       data->index = i + 1;
-                       imapx_command_queue (is, ic);
-                       goto exit;
-               }
-       }
-
-       data->index = i;
-       if (imapx_uidset_done (&data->uidset, ic)) {
-               camel_imapx_command_add (ic, " %M", data->destination);
-               imapx_command_queue (is, ic);
-               goto exit;
-       }
-
-exit:
-       camel_imapx_command_unref (ic);
-
-       return success;
-}
-
-static gboolean
-imapx_job_copy_messages_start (CamelIMAPXJob *job,
-                               CamelIMAPXServer *is,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-       CamelIMAPXMailbox *mailbox;
-       CopyMessagesData *data;
-       gboolean success;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       success = imapx_server_sync_changes (
-               is, mailbox, job->type, job->pri, cancellable, error);
-       if (!success)
-               imapx_unregister_job (is, job);
-
-       /* XXX Should we still do this even if a failure occurred? */
-       g_ptr_array_sort (data->uids, (GCompareFunc) imapx_uids_array_cmp);
-       imapx_uidset_init (&data->uidset, 0, MAX_COMMAND_LEN);
-
-       g_object_unref (mailbox);
-
-       return imapx_command_copy_messages_step_start (is, job, 0, error);
-}
-
-static gboolean
-imapx_job_copy_messages_matches (CamelIMAPXJob *job,
-                                CamelIMAPXMailbox *mailbox,
-                                const gchar *uid)
-{
-       return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_append_message_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXFolder *ifolder;
-       CamelIMAPXMailbox *mailbox;
-       CamelFolder *folder;
-       CamelMessageInfo *mi;
-       AppendMessageData *data;
-       gchar *cur, *old_uid;
-       guint32 uidvalidity;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
-
-       ifolder = CAMEL_IMAPX_FOLDER (folder);
-
-       /* Append done.  If we the server supports UIDPLUS we will get
-        * an APPENDUID response with the new uid.  This lets us move the
-        * message we have directly to the cache and also create a correctly
-        * numbered MessageInfo, without losing any information.  Otherwise
-        * we have to wait for the server to let us know it was appended. */
-
-       mi = camel_message_info_clone (data->info);
-       old_uid = g_strdup (data->info->uid);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error appending message"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
-               c (is->tagprefix, "Got appenduid %d %d\n", (gint) ic->status->u.appenduid.uidvalidity, (gint) 
ic->status->u.appenduid.uid);
-               if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
-                       CamelFolderChangeInfo *changes;
-
-                       data->appended_uid = g_strdup_printf ("%u", (guint) ic->status->u.appenduid.uid);
-                       mi->uid = camel_pstring_add (data->appended_uid, FALSE);
-
-                       cur = camel_data_cache_get_filename  (ifolder->cache, "cur", mi->uid);
-                       if (g_rename (data->path, cur) == -1 && errno != ENOENT) {
-                               g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, data->path, 
cur, g_strerror (errno));
-                       }
-
-                       imapx_set_message_info_flags_for_new_message (
-                               mi,
-                               ((CamelMessageInfoBase *) data->info)->flags,
-                               ((CamelMessageInfoBase *) data->info)->user_flags,
-                               TRUE,
-                               ((CamelMessageInfoBase *) data->info)->user_tags,
-                               camel_imapx_mailbox_get_permanentflags (mailbox));
-                       camel_folder_summary_add (folder->summary, mi);
-                       changes = camel_folder_change_info_new ();
-                       camel_folder_change_info_add_uid (changes, mi->uid);
-                       camel_folder_changed (folder, changes);
-                       camel_folder_change_info_free (changes);
-
-                       g_free (cur);
-               } else {
-                       c (is->tagprefix, "but uidvalidity changed \n");
-               }
-       }
-
-       camel_data_cache_remove (ifolder->cache, "new", old_uid, NULL);
-       g_free (old_uid);
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static const gchar *
-get_month_str (gint month)
-{
-       static const gchar tm_months[][4] = {
-               "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-       };
-
-       if (month < 1 || month > 12)
-               return NULL;
-
-       return tm_months[month - 1];
-}
-
-static gboolean
-imapx_job_append_message_start (CamelIMAPXJob *job,
-                                CamelIMAPXServer *is,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       CamelIMAPXMailbox *mailbox;
-       CamelIMAPXCommand *ic;
-       AppendMessageData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       if (data->date_time > 0) {
-               gchar *date_time;
-               struct tm stm;
-
-               gmtime_r (&data->date_time, &stm);
-
-               /* Store always in UTC */
-               date_time = g_strdup_printf (
-                       "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
-                       stm.tm_mday,
-                       get_month_str (stm.tm_mon + 1),
-                       stm.tm_year + 1900,
-                       stm.tm_hour,
-                       stm.tm_min,
-                       stm.tm_sec);
-
-               ic = camel_imapx_command_new (
-                       is, "APPEND", NULL,
-                       "APPEND %M %F %t %P", mailbox,
-                       ((CamelMessageInfoBase *) data->info)->flags,
-                       ((CamelMessageInfoBase *) data->info)->user_flags,
-                       date_time,
-                       data->path);
-
-               g_free (date_time);
-       } else {
-               ic = camel_imapx_command_new (
-                       is, "APPEND", NULL,
-                       "APPEND %M %F %P", mailbox,
-                       ((CamelMessageInfoBase *) data->info)->flags,
-                       ((CamelMessageInfoBase *) data->info)->user_flags,
-                       data->path);
-       }
-
-       ic->complete = imapx_command_append_message_done;
-       camel_imapx_command_set_job (ic, job);
-       ic->pri = job->pri;
-       g_atomic_int_add (&job->commands, 1);
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_object_unref (mailbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static gint
-imapx_refresh_info_uid_cmp (gconstpointer ap,
-                            gconstpointer bp,
-                            gboolean ascending)
-{
-       guint av, bv;
-
-       av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
-       bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
-
-       if (av < bv)
-               return ascending ? -1 : 1;
-       else if (av > bv)
-               return ascending ? 1 : -1;
-       else
-               return 0;
-}
-
-static gint
-imapx_uids_array_cmp (gconstpointer ap,
-                      gconstpointer bp)
-{
-       const gchar **a = (const gchar **) ap;
-       const gchar **b = (const gchar **) bp;
-
-       return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp (gconstpointer ap,
-                        gconstpointer bp)
-{
-       const struct _refresh_info *a = ap;
-       const struct _refresh_info *b = bp;
-
-       return imapx_refresh_info_uid_cmp (a->uid, b->uid, TRUE);
-}
-
-static gint
-imapx_refresh_info_cmp_descending (gconstpointer ap,
-                                   gconstpointer bp)
-{
-       const struct _refresh_info *a = ap;
-       const struct _refresh_info *b = bp;
-
-       return imapx_refresh_info_uid_cmp (a->uid, b->uid, FALSE);
-
-}
-
-/* skips over non-server uids (pending appends) */
-static guint
-imapx_index_next (GPtrArray *uids,
-                  CamelFolderSummary *s,
-                  guint index)
-{
-
-       while (index < uids->len) {
-               CamelMessageInfo *info;
-
-               index++;
-               if (index >= uids->len)
-                       break;
-
-               info = camel_folder_summary_get (s, g_ptr_array_index (uids, index));
-               if (!info)
-                       continue;
-
-               if (info && (strchr (camel_message_info_uid (info), '-') != NULL)) {
-                       camel_message_info_unref (info);
-                       e ('?', "Ignoring offline uid '%s'\n", camel_message_info_uid (info));
-               } else {
-                       camel_message_info_unref (info);
-                       break;
-               }
-       }
-
-       return index;
-}
-
-static void
-imapx_command_step_fetch_done (CamelIMAPXServer *is,
-                               CamelIMAPXCommand *ic)
-{
-       CamelIMAPXMailbox *mailbox;
-       CamelIMAPXSummary *isum;
-       CamelIMAPXJob *job;
-       CamelFolder *folder;
-       RefreshInfoData *data;
-       gint i;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       data->scan_changes = FALSE;
-
-       isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
-       i = data->index;
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching message headers"));
-               camel_imapx_job_take_error (job, local_error);
-               goto exit;
-       }
-
-       if (camel_folder_change_info_changed (data->changes)) {
-               imapx_update_store_summary (folder);
-               camel_folder_summary_save_to_db (folder->summary, NULL);
-               camel_folder_changed (folder, data->changes);
-       }
-
-       camel_folder_change_info_clear (data->changes);
-
-       if (i < data->infos->len) {
-               ic = camel_imapx_command_new (
-                       is, "FETCH", mailbox, "UID FETCH ");
-               ic->complete = imapx_command_step_fetch_done;
-               camel_imapx_command_set_job (ic, job);
-               ic->pri = job->pri - 1;
-
-               data->last_index = i;
-
-               for (; i < data->infos->len; i++) {
-                       gint res;
-                       struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
-                       if (!r->exists) {
-                               res = imapx_uidset_add (&data->uidset, ic, r->uid);
-                               if (res == 1) {
-                                       camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
-                                       data->index = i + 1;
-
-                                       imapx_command_queue (is, ic);
-
-                                       camel_imapx_command_unref (ic);
-
-                                       g_object_unref (folder);
-                                       g_object_unref (mailbox);
-
-                                       return;
-                               }
-                       }
-               }
-
-               data->index = data->infos->len;
-               if (imapx_uidset_done (&data->uidset, ic)) {
-                       camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
-
-                       imapx_command_queue (is, ic);
-
-                       camel_imapx_command_unref (ic);
-
-                       g_object_unref (folder);
-                       g_object_unref (mailbox);
-
-                       return;
-               }
-
-               /* XXX What fate for our newly-created but unsubmitted
-                *     CamelIMAPXCommand if we get here?  I guess just
-                *     discard it and move on?  Also warn so I know if
-                *     we're actually taking this branch for real. */
-               camel_imapx_command_unref (ic);
-               g_warn_if_reached ();
-       }
-
-       if (camel_folder_summary_count (folder->summary)) {
-               gchar *uid;
-               guint32 uidl;
-               guint32 uidnext;
-
-               uid = camel_imapx_dup_uid_from_summary_index (
-                       folder,
-                       camel_folder_summary_count (folder->summary) - 1);
-               if (uid) {
-                       uidl = (guint32) strtoull (uid, NULL, 10);
-                       g_free (uid);
-
-                       uidl++;
-
-                       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-                       if (uidl > uidnext) {
-                               c (
-                                       is->tagprefix,
-                                       "Updating uidnext for '%s' to %ul\n",
-                                       camel_imapx_mailbox_get_name (mailbox),
-                                       uidl);
-                               camel_imapx_mailbox_set_uidnext (mailbox, uidl);
-                       }
-               }
-       }
-
-       isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
-       refresh_info_data_infos_free (data);
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static gint
-imapx_uid_cmp (gconstpointer ap,
-               gconstpointer bp,
-               gpointer data)
-{
-       const gchar *a = ap, *b = bp;
-       gchar *ae, *be;
-       gulong av, bv;
-
-       av = strtoul (a, &ae, 10);
-       bv = strtoul (b, &be, 10);
-
-       if (av < bv)
-               return -1;
-       else if (av > bv)
-               return 1;
-
-       if (*ae == '-')
-               ae++;
-       if (*be == '-')
-               be++;
-
-       return strcmp (ae, be);
-}
-
-static void
-imapx_job_scan_changes_done (CamelIMAPXServer *is,
-                             CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXMailbox *mailbox;
-       CamelIMAPXSettings *settings;
-       CamelFolder *folder;
-       RefreshInfoData *data;
-       GCancellable *cancellable;
-       guint uidset_size;
-       guint32 unseen;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       /* This is only for pushing status messages. */
-       cancellable = camel_imapx_job_get_cancellable (job);
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       data->scan_changes = FALSE;
-
-       settings = camel_imapx_server_ref_settings (is);
-       uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
-       g_object_unref (settings);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error retrieving message"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               GCompareDataFunc uid_cmp = imapx_uid_cmp;
-               CamelMessageInfo *s_minfo = NULL;
-               CamelIMAPXMessageInfo *info;
-               CamelFolderSummary *s = folder->summary;
-               GList *removed = NULL, *l;
-               gboolean fetch_new = FALSE;
-               gint i;
-               guint j = 0;
-               GPtrArray *uids;
-
-               /* Actually we wanted to do this after the SELECT but before the
-                * FETCH command was issued. But this should suffice. */
-               ((CamelIMAPXSummary *) s)->uidnext =
-                       camel_imapx_mailbox_get_uidnext (mailbox);
-               ((CamelIMAPXSummary *) s)->modseq =
-                       camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-               /* Here we do the typical sort/iterate/merge loop.
-                * If the server flags dont match what we had, we modify our
-                * flags to pick up what the server now has - but we merge
-                * not overwrite */
-
-               /* FIXME: We also have to check the offline directory for
-                * anything missing in our summary, and also queue up jobs
-                * for all outstanding messages to be uploaded */
-
-               camel_folder_summary_lock (s);
-
-               /* obtain a copy to be thread safe */
-               uids = camel_folder_summary_get_array (s);
-
-               qsort (data->infos->data, data->infos->len, sizeof (struct _refresh_info), 
imapx_refresh_info_cmp);
-               g_ptr_array_sort (uids, (GCompareFunc) imapx_uids_array_cmp);
-
-               if (uids->len)
-                       s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, 0));
-
-               for (i = 0; i < data->infos->len; i++) {
-                       struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
-
-                       while (s_minfo && uid_cmp (camel_message_info_uid (s_minfo), r->uid, s) < 0) {
-                               const gchar *uid = camel_message_info_uid (s_minfo);
-
-                               camel_folder_change_info_remove_uid (data->changes, uid);
-                               removed = g_list_prepend (removed, (gpointer ) g_strdup (uid));
-                               camel_message_info_unref (s_minfo);
-                               s_minfo = NULL;
-
-                               j = imapx_index_next (uids, s, j);
-                               if (j < uids->len)
-                                       s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
-                       }
-
-                       info = NULL;
-                       if (s_minfo && uid_cmp (s_minfo->uid, r->uid, s) == 0) {
-                               info = (CamelIMAPXMessageInfo *) s_minfo;
-
-                               if (imapx_update_message_info_flags (
-                                               (CamelMessageInfo *) info,
-                                               r->server_flags,
-                                               r->server_user_flags,
-                                               camel_imapx_mailbox_get_permanentflags (mailbox),
-                                               folder, FALSE))
-                                       camel_folder_change_info_change_uid (
-                                               data->changes,
-                                               camel_message_info_uid (s_minfo));
-                               r->exists = TRUE;
-                       } else
-                               fetch_new = TRUE;
-
-                       if (s_minfo) {
-                               camel_message_info_unref (s_minfo);
-                               s_minfo = NULL;
-                       }
-
-                       if (j >= uids->len)
-                               break;
-
-                       j = imapx_index_next (uids, s, j);
-                       if (j < uids->len)
-                               s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
-               }
-
-               if (s_minfo)
-                       camel_message_info_unref (s_minfo);
-
-               while (j < uids->len) {
-                       s_minfo = camel_folder_summary_get (s, g_ptr_array_index (uids, j));
-
-                       if (!s_minfo) {
-                               j++;
-                               continue;
-                       }
-
-                       e (is->tagprefix, "Message %s vanished\n", s_minfo->uid);
-                       removed = g_list_prepend (removed, (gpointer) g_strdup (s_minfo->uid));
-                       camel_message_info_unref (s_minfo);
-                       j++;
-               }
-
-               for (l = removed; l != NULL; l = g_list_next (l)) {
-                       gchar *uid = (gchar *) l->data;
-
-                       camel_folder_change_info_remove_uid (data->changes, uid);
-               }
-
-               if (removed != NULL) {
-                       camel_folder_summary_remove_uids (s, removed);
-                       camel_folder_summary_touch (s);
-
-                       g_list_free_full (removed, (GDestroyNotify) g_free);
-               }
-
-               camel_folder_summary_save_to_db (s, NULL);
-               imapx_update_store_summary (folder);
-
-               camel_folder_summary_unlock (s);
-
-               if (camel_folder_change_info_changed (data->changes))
-                       camel_folder_changed (folder, data->changes);
-               camel_folder_change_info_clear (data->changes);
-
-               camel_folder_summary_free_array (uids);
-
-               /* If we have any new messages, download their headers, but only a few (100?) at a time */
-               if (fetch_new) {
-                       job->pop_operation_msg = TRUE;
-
-                       camel_operation_push_message (
-                               cancellable,
-                               _("Fetching summary information for new messages in '%s'"),
-                               camel_folder_get_display_name (folder));
-
-                       imapx_uidset_init (&data->uidset, uidset_size, 0);
-                       /* These are new messages which arrived since we last knew the unseen count;
-                        * update it as they arrive. */
-                       data->update_unseen = TRUE;
-
-                       g_object_unref (folder);
-                       g_object_unref (mailbox);
-
-                       return imapx_command_step_fetch_done (is, ic);
-               }
-       }
-
-       refresh_info_data_infos_free (data);
-
-       /* There's no sane way to get the server-side unseen count
-        * on the select mailbox, so just work it out from the flags. */
-       unseen = camel_folder_summary_get_unread_count (folder->summary);
-       camel_imapx_mailbox_set_unseen (mailbox, unseen);
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_scan_changes_start (CamelIMAPXJob *job,
-                              CamelIMAPXServer *is,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-       CamelFolder *folder;
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-       RefreshInfoData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_val_if_fail (folder != NULL, FALSE);
-
-       job->pop_operation_msg = TRUE;
-
-       camel_operation_push_message (
-               cancellable,
-               _("Scanning for changed messages in '%s'"),
-               camel_folder_get_display_name (folder));
-
-       ic = camel_imapx_command_new (
-               is, "FETCH", mailbox,
-               "UID FETCH 1:* (UID FLAGS)");
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_job_scan_changes_done;
-
-       data->scan_changes = TRUE;
-       ic->pri = job->pri;
-       refresh_info_data_infos_free (data);
-       data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       return TRUE;
-}
-
-static void
-imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
-                                       CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXSummary *isum;
-       CamelIMAPXMailbox *mailbox;
-       CamelFolder *folder;
-       RefreshInfoData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching new messages"));
-               camel_imapx_job_take_error (job, local_error);
-               goto exit;
-       }
-
-       if (camel_folder_change_info_changed (data->changes)) {
-               camel_folder_summary_save_to_db (folder->summary, NULL);
-               imapx_update_store_summary (folder);
-               camel_folder_changed (folder, data->changes);
-               camel_folder_change_info_clear (data->changes);
-       }
-
-       if (camel_folder_summary_count (folder->summary)) {
-               gchar *uid;
-               guint32 uidl;
-               guint32 uidnext;
-
-               uid = camel_imapx_dup_uid_from_summary_index (
-                       folder,
-                       camel_folder_summary_count (folder->summary) - 1);
-               if (uid) {
-                       uidl = (guint32) strtoull (uid, NULL, 10);
-                       g_free (uid);
-
-                       uidl++;
-
-                       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-                       if (uidl > uidnext) {
-                               c (
-                                       is->tagprefix,
-                                       "Updating uidnext for '%s' to %ul\n",
-                                       camel_imapx_mailbox_get_name (mailbox),
-                                       uidl);
-                               camel_imapx_mailbox_set_uidnext (mailbox, uidl);
-                       }
-               }
-       }
-
-       isum->uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-
-exit:
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static void
-imapx_command_fetch_new_uids_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       RefreshInfoData *data;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       data->scan_changes = FALSE;
-
-       qsort (
-               data->infos->data,
-               data->infos->len,
-               sizeof (struct _refresh_info),
-               imapx_refresh_info_cmp_descending);
-
-       imapx_command_step_fetch_done (is, ic);
-}
-
-static gboolean
-imapx_job_fetch_new_messages_start (CamelIMAPXJob *job,
-                                    CamelIMAPXServer *is,
-                                    GCancellable *cancellable,
-                                    GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelFolder *folder;
-       CamelIMAPXMailbox *mailbox;
-       CamelIMAPXSettings *settings;
-       CamelSortType fetch_order;
-       RefreshInfoData *data;
-       guint32 total, diff;
-       guint32 messages;
-       guint uidset_size;
-       gchar *uid = NULL;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_val_if_fail (folder != NULL, FALSE);
-
-       settings = camel_imapx_server_ref_settings (is);
-       fetch_order = camel_imapx_settings_get_fetch_order (settings);
-       uidset_size = camel_imapx_settings_get_batch_fetch_count (settings);
-       g_object_unref (settings);
-
-       messages = camel_imapx_mailbox_get_messages (mailbox);
-
-       total = camel_folder_summary_count (folder->summary);
-       diff = messages - total;
-
-       if (total > 0) {
-               guint64 uidl;
-               uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
-               if (uid) {
-                       uidl = strtoull (uid, NULL, 10);
-                       g_free (uid);
-                       uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uidl + 1);
-               } else {
-                       uid = g_strdup ("1");
-               }
-       } else
-               uid = g_strdup ("1");
-
-       job->pop_operation_msg = TRUE;
-
-       camel_operation_push_message (
-               cancellable,
-               _("Fetching summary information for new messages in '%s'"),
-               camel_folder_get_display_name (folder));
-
-       if (diff > uidset_size || fetch_order == CAMEL_SORT_DESCENDING) {
-               ic = camel_imapx_command_new (
-                       is, "FETCH", mailbox,
-                       "UID FETCH %s:* (UID FLAGS)", uid);
-               imapx_uidset_init (&data->uidset, uidset_size, 0);
-               refresh_info_data_infos_free (data);
-               data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
-               ic->pri = job->pri;
-
-               data->scan_changes = TRUE;
-
-               if (fetch_order == CAMEL_SORT_DESCENDING)
-                       ic->complete = imapx_command_fetch_new_uids_done;
-               else
-                       ic->complete = imapx_command_step_fetch_done;
-       } else {
-               ic = camel_imapx_command_new (
-                       is, "FETCH", mailbox,
-                       "UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
-               ic->pri = job->pri;
-               ic->complete = imapx_command_fetch_new_messages_done;
-       }
-
-       camel_imapx_command_set_job (ic, job);
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_free (uid);
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       return TRUE;
-}
-
-static gboolean
-imapx_job_refresh_info_start (CamelIMAPXJob *job,
-                              CamelIMAPXServer *is,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-       CamelIMAPXSummary *isum;
-       CamelFolder *folder;
-       CamelIMAPXMailbox *mailbox;
-       const gchar *full_name;
-       gboolean need_rescan = FALSE;
-       gboolean is_selected = FALSE;
-       gboolean can_qresync = FALSE;
-       gboolean success;
-       guint32 messages;
-       guint32 unseen;
-       guint32 uidnext;
-       guint32 uidvalidity;
-       guint64 highestmodseq;
-       guint32 total;
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_val_if_fail (folder != NULL, FALSE);
-
-       isum = CAMEL_IMAPX_SUMMARY (folder->summary);
-
-       full_name = camel_folder_get_full_name (folder);
-
-       /* Sync changes first, else unread count will not
-        * match. Need to think about better ways for this */
-       success = imapx_server_sync_changes (
-               is, mailbox, job->type, job->pri, cancellable, error);
-       if (!success)
-               goto done;
-
-       messages = camel_imapx_mailbox_get_messages (mailbox);
-       unseen = camel_imapx_mailbox_get_unseen (mailbox);
-       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-       uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
-       highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-#if 0  /* There are issues with this still; continue with the buggy
-        * behaviour where we issue STATUS on the current folder, for now. */
-       if (is->priv->select_folder == folder)
-               is_selected = TRUE;
-#endif
-       total = camel_folder_summary_count (folder->summary);
-
-       if (uidvalidity > 0 && uidvalidity != isum->validity)
-               need_rescan = TRUE;
-
-       /* We don't have valid unread count or modseq for currently-selected server
-        * (unless we want to re-SELECT it). We fake unread count when fetching
-        * message flags, but don't depend on modseq for the selected folder */
-       if (total != messages ||
-           isum->uidnext != uidnext ||
-           camel_folder_summary_get_unread_count (folder->summary) != unseen ||
-           (!is_selected && isum->modseq != highestmodseq))
-               need_rescan = TRUE;
-
-       /* This is probably the first check of this folder after startup;
-        * use STATUS to check whether the cached summary is valid, rather
-        * than blindly updating. Only for servers which support CONDSTORE
-        * though. */
-       if (isum->modseq > 0 && highestmodseq == 0)
-               need_rescan = FALSE;
-
-       /* If we don't think there's anything to do, poke it to check */
-       if (!need_rescan) {
-               CamelIMAPXCommand *ic;
-
-               #if 0  /* see comment for disabled bits above */
-               if (is_selected) {
-                       /* We may not issue STATUS on the current folder. Use SELECT or NOOP instead. */
-                       if (0 /* server needs SELECT not just NOOP */) {
-                               if (imapx_in_idle (is))
-                                       if (!imapx_stop_idle (is, error))
-                                               goto done;
-                               /* This doesn't work -- this is an immediate command, not queued */
-                               imapx_maybe_select (is, folder)
-                       } else {
-                               /* Or maybe just NOOP, unless we're in IDLE in which case do nothing */
-                               if (!imapx_in_idle (is)) {
-                                       if (!camel_imapx_server_noop (is, folder, cancellable, error))
-                                               goto done;
-                               }
-                       }
-               } else
-               #endif
-               {
-                       ic = camel_imapx_command_new (
-                               is, "STATUS", NULL, "STATUS %M (%t)",
-                               mailbox, is->priv->status_data_items);
-
-                       camel_imapx_command_set_job (ic, job);
-                       ic->pri = job->pri;
-
-                       success = imapx_command_run_sync (
-                               is, ic, cancellable, error);
-
-                       camel_imapx_command_unref (ic);
-
-                       if (!success) {
-                               g_prefix_error (
-                                       error, "%s: ",
-                                       _("Error refreshing folder"));
-                               goto done;
-                       }
-               }
-
-               /* Recalulate need_rescan */
-
-               messages = camel_imapx_mailbox_get_messages (mailbox);
-               unseen = camel_imapx_mailbox_get_unseen (mailbox);
-               uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-               highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-               if (total != messages ||
-                   isum->uidnext != uidnext ||
-                   camel_folder_summary_get_unread_count (folder->summary) != unseen ||
-                   (!is_selected && isum->modseq != highestmodseq))
-                       need_rescan = TRUE;
-       }
-
-       messages = camel_imapx_mailbox_get_messages (mailbox);
-       unseen = camel_imapx_mailbox_get_unseen (mailbox);
-       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
-       uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
-       highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-       if (is->use_qresync && isum->modseq > 0 && uidvalidity > 0)
-               can_qresync = TRUE;
-
-       e (
-               is->tagprefix,
-               "folder %s is %sselected, "
-               "total %u / %u, unread %u / %u, modseq %"
-               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT
-               ", uidnext %u / %u: will %srescan\n",
-               full_name,
-               is_selected ? "" : "not ",
-               total,
-               messages,
-               camel_folder_summary_get_unread_count (folder->summary),
-               unseen,
-               isum->modseq,
-               highestmodseq,
-               isum->uidnext,
-               uidnext,
-               need_rescan ? "" : "not ");
-
-       /* Fetch new messages first, so that they appear to the user ASAP */
-       if (messages > total || uidnext > isum->uidnext) {
-               if (!total)
-                       need_rescan = FALSE;
-
-               success = imapx_server_fetch_new_messages (
-                       is, mailbox, FALSE, FALSE, cancellable, error);
-               if (!success)
-                       goto done;
-
-               /* If QRESYNC-capable we'll have got all flags changes in SELECT */
-               if (can_qresync)
-                       goto qresync_done;
-       }
-
-       if (!need_rescan)
-               goto done;
-
-       if (can_qresync) {
-               /* Actually we only want to select it; no need for the NOOP */
-               success = camel_imapx_server_noop (
-                       is, mailbox, cancellable, error);
-               if (!success)
-                       goto done;
-       qresync_done:
-               messages = camel_imapx_mailbox_get_messages (mailbox);
-               unseen = camel_imapx_mailbox_get_unseen (mailbox);
-               highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
-
-               isum->modseq = highestmodseq;
-               total = camel_folder_summary_count (folder->summary);
-               if (total != messages ||
-                   camel_folder_summary_get_unread_count (folder->summary) != unseen ||
-                   (isum->modseq != highestmodseq)) {
-                       c (
-                               is->tagprefix,
-                               "Eep, after QRESYNC we're out of sync. "
-                               "total %u / %u, unread %u / %u, modseq %"
-                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
-                               total, messages,
-                               camel_folder_summary_get_unread_count (folder->summary),
-                               unseen,
-                               isum->modseq,
-                               highestmodseq);
-               } else {
-                       c (
-                               is->tagprefix,
-                               "OK, after QRESYNC we're still in sync. "
-                               "total %u / %u, unread %u / %u, modseq %"
-                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
-                               total, messages,
-                               camel_folder_summary_get_unread_count (folder->summary),
-                               unseen,
-                               isum->modseq,
-                               highestmodseq);
-                       goto done;
-               }
-       }
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       return imapx_job_scan_changes_start (job, is, cancellable, error);
-
-done:
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-
-       return success;
-}
-
-static gboolean
-imapx_job_refresh_info_matches (CamelIMAPXJob *job,
-                                CamelIMAPXMailbox *mailbox,
-                                const gchar *uid)
-{
-       return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_expunge_done (CamelIMAPXServer *is,
-                            CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXMailbox *mailbox;
-       CamelFolder *folder;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error expunging message"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               GPtrArray *uids;
-               CamelStore *parent_store;
-               const gchar *full_name;
-
-               full_name = camel_folder_get_full_name (folder);
-               parent_store = camel_folder_get_parent_store (folder);
-
-               camel_folder_summary_lock (folder->summary);
-
-               camel_folder_summary_save_to_db (folder->summary, NULL);
-               uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
-
-               if (uids && uids->len) {
-                       CamelFolderChangeInfo *changes;
-                       GList *removed = NULL;
-                       gint i;
-
-                       changes = camel_folder_change_info_new ();
-                       for (i = 0; i < uids->len; i++) {
-                               camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
-                               removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
-                       }
-
-                       camel_folder_summary_remove_uids (folder->summary, removed);
-                       camel_folder_summary_save_to_db (folder->summary, NULL);
-
-                       camel_folder_changed (folder, changes);
-                       camel_folder_change_info_free (changes);
-
-                       g_list_free (removed);
-                       g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
-               }
-
-               if (uids)
-                       g_ptr_array_free (uids, TRUE);
-
-               camel_folder_summary_unlock (folder->summary);
-       }
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_expunge_start (CamelIMAPXJob *job,
-                         CamelIMAPXServer *is,
-                         GCancellable *cancellable,
-                         GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-       gboolean success;
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       success = imapx_server_sync_changes (
-               is, mailbox, job->type, job->pri, cancellable, error);
-
-       if (success) {
-               /* TODO handle UIDPLUS capability */
-               ic = camel_imapx_command_new (
-                       is, "EXPUNGE", mailbox, "EXPUNGE");
-               camel_imapx_command_set_job (ic, job);
-               ic->pri = job->pri;
-               ic->complete = imapx_command_expunge_done;
-
-               imapx_command_queue (is, ic);
-
-               camel_imapx_command_unref (ic);
-       }
-
-       g_object_unref (mailbox);
-
-       return success;
-}
-
-static gboolean
-imapx_job_expunge_matches (CamelIMAPXJob *job,
-                           CamelIMAPXMailbox *mailbox,
-                           const gchar *uid)
-{
-       return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_list_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching folders"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       e (is->tagprefix, "==== list or lsub completed ==== \n");
-       imapx_unregister_job (is, job);
-}
-
-static void
-imapx_command_list_lsub (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       ListData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error fetching folders"));
-               camel_imapx_job_take_error (job, local_error);
-               imapx_unregister_job (is, job);
-
-       } else {
-               ic = camel_imapx_command_new (
-                       is, "LIST", NULL,
-                       "LSUB \"\" %s",
-                       data->pattern);
-
-               ic->pri = job->pri;
-               camel_imapx_command_set_job (ic, job);
-               ic->complete = imapx_command_list_done;
-
-               imapx_command_queue (is, ic);
-
-               camel_imapx_command_unref (ic);
-       }
-}
-
-static gboolean
-imapx_job_list_start (CamelIMAPXJob *job,
-                      CamelIMAPXServer *is,
-                      GCancellable *cancellable,
-                      GError **error)
-{
-       CamelIMAPXCommand *ic;
-       ListData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       if (is->priv->list_return_opts != NULL) {
-               ic = camel_imapx_command_new (
-                       is, "LIST", NULL,
-                       "LIST \"\" %s RETURN (%t)",
-                       data->pattern,
-                       is->priv->list_return_opts);
-               ic->complete = imapx_command_list_done;
-       } else {
-               ic = camel_imapx_command_new (
-                       is, "LIST", NULL,
-                       "LIST \"\" %s",
-                       data->pattern);
-               ic->complete = imapx_command_list_lsub;
-       }
-
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       return TRUE;
-}
-
-static gboolean
-imapx_job_list_matches (CamelIMAPXJob *job,
-                        CamelIMAPXMailbox *mailbox,
-                        const gchar *uid)
-{
-       return TRUE;  /* matches everything */
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_create_mailbox_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error creating folder"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_create_mailbox_start (CamelIMAPXJob *job,
-                                CamelIMAPXServer *is,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       CamelIMAPXCommand *ic;
-       MailboxData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "CREATE", NULL, "CREATE %m",
-               data->mailbox_name);
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_create_mailbox_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_delete_mailbox_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       MailboxData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error deleting folder"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               CamelIMAPXStore *imapx_store;
-
-               /* Perform the same processing as imapx_untagged_list()
-                * would if the server notified us of a deleted mailbox. */
-
-               imapx_store = camel_imapx_server_ref_store (is);
-
-               camel_imapx_mailbox_deleted (data->mailbox);
-               camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
-               g_clear_object (&imapx_store);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_delete_mailbox_start (CamelIMAPXJob *job,
-                                CamelIMAPXServer *is,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       CamelIMAPXStore *imapx_store;
-       CamelIMAPXCommand *ic;
-       MailboxData *data;
-       CamelIMAPXMailbox *inbox;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       imapx_store = camel_imapx_server_ref_store (is);
-       /* Keep going, even if this returns NULL. */
-       inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
-       g_clear_object (&imapx_store);
-
-       /* Make sure the to-be-deleted folder is not
-        * selected by selecting INBOX for this operation. */
-       ic = camel_imapx_command_new (
-               is, "DELETE", inbox,
-               "DELETE %M", data->mailbox);
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_delete_mailbox_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_clear_object (&inbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_rename_mailbox_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       MailboxData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error renaming folder"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               CamelIMAPXStore *imapx_store;
-
-               /* Perform the same processing as imapx_untagged_list()
-                * would if the server notified us of a renamed mailbox. */
-
-               imapx_store = camel_imapx_server_ref_store (is);
-               camel_imapx_store_handle_mailbox_rename (imapx_store, data->mailbox, data->mailbox_name);
-
-               g_clear_object (&imapx_store);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_rename_mailbox_start (CamelIMAPXJob *job,
-                                CamelIMAPXServer *is,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXStore *imapx_store;
-       CamelIMAPXMailbox *inbox;
-       MailboxData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       imapx_store = camel_imapx_server_ref_store (is);
-       inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
-       g_clear_object (&imapx_store);
-       g_return_val_if_fail (inbox != NULL, FALSE);
-
-       camel_imapx_job_set_mailbox (job, inbox);
-
-       ic = camel_imapx_command_new (
-               is, "RENAME", inbox, "RENAME %M %m",
-               data->mailbox, data->mailbox_name);
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_rename_mailbox_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_object_unref (inbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_subscribe_mailbox_done (CamelIMAPXServer *is,
-                                      CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       MailboxData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error subscribing to folder"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               CamelIMAPXStore *imapx_store;
-
-               /* Perform the same processing as imapx_untagged_list()
-                * would if the server notified us of a subscription. */
-
-               imapx_store = camel_imapx_server_ref_store (is);
-
-               camel_imapx_mailbox_subscribed (data->mailbox);
-               camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
-               g_clear_object (&imapx_store);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_subscribe_mailbox_start (CamelIMAPXJob *job,
-                                   CamelIMAPXServer *is,
-                                   GCancellable *cancellable,
-                                   GError **error)
-{
-       CamelIMAPXCommand *ic;
-       MailboxData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "SUBSCRIBE", NULL,
-               "SUBSCRIBE %M", data->mailbox);
-
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_subscribe_mailbox_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_unsubscribe_mailbox_done (CamelIMAPXServer *is,
-                                        CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       MailboxData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error unsubscribing from folder"));
-               camel_imapx_job_take_error (job, local_error);
-
-       } else {
-               CamelIMAPXStore *imapx_store;
-
-               /* Perform the same processing as imapx_untagged_list()
-                * would if the server notified us of an unsubscription. */
-
-               imapx_store = camel_imapx_server_ref_store (is);
-
-               camel_imapx_mailbox_unsubscribed (data->mailbox);
-               camel_imapx_store_emit_mailbox_updated (imapx_store, data->mailbox);
-
-               g_clear_object (&imapx_store);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_unsubscribe_mailbox_start (CamelIMAPXJob *job,
-                                     CamelIMAPXServer *is,
-                                     GCancellable *cancellable,
-                                     GError **error)
-{
-       CamelIMAPXCommand *ic;
-       MailboxData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "UNSUBSCRIBE", NULL,
-               "UNSUBSCRIBE %M", data->mailbox);
-
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_unsubscribe_mailbox_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_update_quota_info_done (CamelIMAPXServer *is,
-                                      CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error retrieving quota information"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_update_quota_info_start (CamelIMAPXJob *job,
-                                   CamelIMAPXServer *is,
-                                   GCancellable *cancellable,
-                                   GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "GETQUOTAROOT", NULL,
-               "GETQUOTAROOT %M", mailbox);
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_update_quota_info_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_clear_object (&mailbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_uid_search_done (CamelIMAPXServer *is,
-                               CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       SearchData *data;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (&local_error, "%s: ", _("Search failed"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       /* Don't worry about the success state and presence of search
-        * results not agreeing here.  camel_imapx_server_uid_search()
-        * will disregard the search results if an error occurred. */
-       g_mutex_lock (&is->priv->search_results_lock);
-       data->results = is->priv->search_results;
-       is->priv->search_results = NULL;
-       g_mutex_unlock (&is->priv->search_results_lock);
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_uid_search_start (CamelIMAPXJob *job,
-                            CamelIMAPXServer *is,
-                            GCancellable *cancellable,
-                            GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-       SearchData *data;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       ic = camel_imapx_command_new (
-               is, "UID SEARCH", mailbox,
-               "UID SEARCH %t", data->criteria);
-       ic->pri = job->pri;
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_uid_search_done;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_object_unref (mailbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-imapx_command_noop_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error performing NOOP"));
-               camel_imapx_job_take_error (job, local_error);
-       }
-
-       imapx_unregister_job (is, job);
-}
-
-static gboolean
-imapx_job_noop_start (CamelIMAPXJob *job,
-                      CamelIMAPXServer *is,
-                      GCancellable *cancellable,
-                      GError **error)
-{
-       CamelIMAPXCommand *ic;
-       CamelIMAPXMailbox *mailbox;
-
-       /* This may be NULL. */
-       mailbox = camel_imapx_job_ref_mailbox (job);
-
-       ic = camel_imapx_command_new (
-               is, "NOOP", mailbox, "NOOP");
-
-       camel_imapx_command_set_job (ic, job);
-       ic->complete = imapx_command_noop_done;
-       if (mailbox != NULL)
-               ic->pri = IMAPX_PRIORITY_REFRESH_INFO;
-       else
-               ic->pri = IMAPX_PRIORITY_NOOP;
-
-       imapx_command_queue (is, ic);
-
-       camel_imapx_command_unref (ic);
-
-       g_clear_object (&mailbox);
-
-       return TRUE;
-}
-
-/* ********************************************************************** */
-
 /* FIXME: this is basically a copy of the same in camel-imapx-utils.c */
 static struct {
        const gchar *name;
@@ -7422,531 +3162,6 @@ static struct {
        { "NOTJUNK", CAMEL_MESSAGE_NOTJUNK }
 };
 
-/*
- *  flags 00101000
- * sflags 01001000
- * ^      01100000
- * ~flags 11010111
- * &      01000000
- *
- * &flags 00100000
- */
-
-static void
-imapx_command_sync_changes_done (CamelIMAPXServer *is,
-                                 CamelIMAPXCommand *ic)
-{
-       CamelIMAPXJob *job;
-       CamelIMAPXMailbox *mailbox;
-       CamelFolder *folder;
-       CamelStore *parent_store;
-       SyncChangesData *data;
-       const gchar *full_name;
-       GError *local_error = NULL;
-
-       job = camel_imapx_command_get_job (ic);
-       g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
-
-       data = camel_imapx_job_get_data (job);
-       g_return_if_fail (data != NULL);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       g_atomic_int_add (&job->commands, -1);
-
-       full_name = camel_folder_get_full_name (folder);
-       parent_store = camel_folder_get_parent_store (folder);
-
-       /* If this worked, we should really just update the changes that we
-        * sucessfully stored, so we dont have to worry about sending them
-        * again ...
-        * But then we'd have to track which uid's we actually updated, so
-        * its easier just to refresh all of the ones we got.
-        *
-        * Not that ... given all the asynchronicity going on, we're guaranteed
-        * that what we just set is actually what is on the server now .. but
-        * if it isn't, i guess we'll fix up next refresh */
-
-       if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
-               g_prefix_error (
-                       &local_error, "%s: ",
-                       _("Error syncing changes"));
-               camel_imapx_job_take_error (job, local_error);
-               imapx_unregister_job (is, job);
-               goto exit;
-
-       /* lock cache ? */
-       } else {
-               guint32 unseen, permanentflags;
-               gint i;
-
-               permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
-
-               for (i = 0; i < data->changed_uids->len; i++) {
-                       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get 
(folder->summary,
-                                       data->changed_uids->pdata[i]);
-
-                       if (!xinfo)
-                               continue;
-
-                       xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
-                       if (!data->remove_deleted_flags ||
-                           !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
-                               xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
-                       } else {
-                               /* to stare back the \Deleted flag */
-                               xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
-                               xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
-                       }
-                       xinfo->info.dirty = TRUE;
-                       if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
-                           camel_flag_list_size (&xinfo->server_user_flags) == 0)
-                               camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
-
-                       camel_folder_summary_touch (folder->summary);
-                       camel_message_info_unref (xinfo);
-               }
-
-               /* Apply the changes to server-side unread count; it won't tell
-                * us of these changes, of course. */
-               unseen = camel_imapx_mailbox_get_unseen (mailbox);
-               unseen += data->unread_change;
-               camel_imapx_mailbox_set_unseen (mailbox, unseen);
-       }
-
-       if (g_atomic_int_get (&job->commands) == 0) {
-               if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
-                       CamelStoreInfo *si;
-
-                       /* ... and store's summary when folder's summary is dirty */
-                       si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, full_name);
-                       if (si) {
-                               if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
-                                   si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
-                                       si->total = camel_folder_summary_get_saved_count (folder->summary);
-                                       si->unread = camel_folder_summary_get_unread_count (folder->summary);
-                                       camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
-                               }
-
-                               camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary, 
si);
-                       }
-               }
-
-               camel_folder_summary_save_to_db (folder->summary, NULL);
-               camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
-
-               imapx_unregister_job (is, job);
-       } else {
-               /* Make sure no command will starve in a queue */
-               QUEUE_LOCK (is);
-               imapx_command_start_next (is);
-               QUEUE_UNLOCK (is);
-       }
-
-exit:
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-}
-
-static gboolean
-imapx_job_sync_changes_start (CamelIMAPXJob *job,
-                              CamelIMAPXServer *is,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-       SyncChangesData *data;
-       CamelFolder *folder;
-       CamelIMAPXMailbox *mailbox;
-       guint32 i, j, permanentflags;
-       struct _uidset_state ss;
-       GPtrArray *uids;
-       gint on;
-
-       data = camel_imapx_job_get_data (job);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       mailbox = camel_imapx_job_ref_mailbox (job);
-       g_return_val_if_fail (mailbox != NULL, FALSE);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_val_if_fail (folder != NULL, FALSE);
-
-       permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
-       uids = data->changed_uids;
-
-       for (on = 0; on < 2; on++) {
-               guint32 orset = on ? data->on_set : data->off_set;
-               GArray *user_set = on ? data->on_user : data->off_user;
-
-               for (j = 0; j < G_N_ELEMENTS (flags_table); j++) {
-                       guint32 flag = flags_table[j].flag;
-                       CamelIMAPXCommand *ic = NULL;
-
-                       if ((orset & flag) == 0)
-                               continue;
-
-                       c (is->tagprefix, "checking/storing %s flags '%s'\n", on?"on":"off", 
flags_table[j].name);
-                       imapx_uidset_init (&ss, 0, 100);
-                       for (i = 0; i < uids->len; i++) {
-                               CamelIMAPXMessageInfo *info;
-                               gboolean remove_deleted_flag;
-                               guint32 flags;
-                               guint32 sflags;
-                               gint send;
-
-                               info = (CamelIMAPXMessageInfo *)
-                                       camel_folder_summary_get (
-                                               folder->summary,
-                                               uids->pdata[i]);
-
-                               if (info == NULL)
-                                       continue;
-
-                               flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
-                               sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
-                               send = 0;
-
-                               remove_deleted_flag =
-                                       data->remove_deleted_flags &&
-                                       (flags & CAMEL_MESSAGE_DELETED);
-
-                               if (remove_deleted_flag) {
-                                       /* Remove the DELETED flag so the
-                                        * message appears normally in the
-                                        * real Trash folder when copied. */
-                                       flags &= ~CAMEL_MESSAGE_DELETED;
-                               }
-
-                               if ( (on && (((flags ^ sflags) & flags) & flag))
-                                    || (!on && (((flags ^ sflags) & ~flags) & flag))) {
-                                       if (ic == NULL) {
-                                               ic = camel_imapx_command_new (
-                                                       is, "STORE", mailbox,
-                                                       "UID STORE ");
-                                               ic->complete = imapx_command_sync_changes_done;
-                                               camel_imapx_command_set_job (ic, job);
-                                               ic->pri = job->pri;
-                                       }
-                                       send = imapx_uidset_add (&ss, ic, camel_message_info_uid (info));
-                               }
-                               if (send == 1 || (i == uids->len - 1 && ic && imapx_uidset_done (&ss, ic))) {
-                                       g_atomic_int_add (&job->commands, 1);
-                                       camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", 
flags_table[j].name);
-                                       imapx_command_queue (is, ic);
-                                       camel_imapx_command_unref (ic);
-                                       ic = NULL;
-                               }
-                               if (flag == CAMEL_MESSAGE_SEEN) {
-                                       /* Remember how the server's unread count will change if this
-                                        * command succeeds */
-                                       if (on)
-                                               data->unread_change--;
-                                       else
-                                               data->unread_change++;
-                               }
-
-                               /* The second round and the server doesn't support saving user flags,
-                                  thus store them at least locally */
-                               if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
-                                       camel_flag_list_copy (&info->server_user_flags, 
&info->info.user_flags);
-                               }
-
-                               camel_message_info_unref (info);
-                       }
-
-                       g_warn_if_fail (ic == NULL);
-               }
-
-               if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
-                       CamelIMAPXCommand *ic = NULL;
-
-                       for (j = 0; j < user_set->len; j++) {
-                               struct _imapx_flag_change *c = &g_array_index (user_set, struct 
_imapx_flag_change, j);
-
-                               imapx_uidset_init (&ss, 0, 100);
-                               for (i = 0; i < c->infos->len; i++) {
-                                       CamelIMAPXMessageInfo *info = c->infos->pdata[i];
-
-                                       if (ic == NULL) {
-                                               ic = camel_imapx_command_new (
-                                                       is, "STORE", mailbox,
-                                                       "UID STORE ");
-                                               ic->complete = imapx_command_sync_changes_done;
-                                               camel_imapx_command_set_job (ic, job);
-                                               ic->pri = job->pri;
-                                       }
-
-                                       if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info)) == 1
-                                           || (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
-                                               g_atomic_int_add (&job->commands, 1);
-                                               camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", 
on?"+":"-", c->name);
-                                               imapx_command_queue (is, ic);
-                                               camel_imapx_command_unref (ic);
-                                               ic = NULL;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-
-       if (g_atomic_int_get (&job->commands) == 0) {
-               imapx_unregister_job (is, job);
-       } else {
-               /* Make sure no command will starve in a queue */
-               QUEUE_LOCK (is);
-               imapx_command_start_next (is);
-               QUEUE_UNLOCK (is);
-       }
-
-       return TRUE;
-}
-
-static gboolean
-imapx_job_sync_changes_matches (CamelIMAPXJob *job,
-                                CamelIMAPXMailbox *mailbox,
-                                const gchar *uid)
-{
-       return camel_imapx_job_has_mailbox (job, mailbox);
-}
-
-static void
-imapx_abort_all_commands (CamelIMAPXServer *is,
-                          const GError *error)
-{
-       CamelIMAPXCommandQueue *queue;
-       GList *head, *link;
-
-       /* Transfer all pending and active commands to a separate
-        * command queue to complete them without holding QUEUE_LOCK. */
-
-       queue = camel_imapx_command_queue_new ();
-
-       imapx_server_set_shutdown_error (is, error);
-
-       QUEUE_LOCK (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);
-
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               CamelIMAPXCommand *ic = link->data;
-
-               /* Sanity check the CamelIMAPXCommand before proceeding.
-                * XXX We are actually getting reports of crashes here...
-                *     not sure how this is happening but it's happening. */
-               if (ic == NULL)
-                       continue;
-
-               /* Insert an error into the CamelIMAPXCommand to be
-                * propagated when the completion callback function
-                * calls camel_imapx_command_set_error_if_failed(). */
-               camel_imapx_command_failed (ic, error);
-
-               /* Invoke the completion callback function so it can
-                * perform any cleanup processing and unregister its
-                * CamelIMAPXJob. */
-               ic->complete (is, ic);
-       }
-
-       camel_imapx_command_queue_free (queue);
-
-       QUEUE_LOCK (is);
-
-       /* Abort also any pending jobs which are not in the command queues yet */
-       if (!g_queue_is_empty (&is->jobs)) {
-               GList *jobs, *iter;
-
-               jobs = g_list_copy (g_queue_peek_head_link (&is->jobs));
-               g_list_foreach (jobs, (GFunc) camel_imapx_job_ref, NULL);
-
-               for (iter = jobs; iter != NULL; iter = g_list_next (iter)) {
-                       CamelIMAPXJob *job = iter->data;
-
-                       camel_imapx_job_take_error (job, g_error_copy (error));
-                       camel_imapx_job_done (job);
-               }
-
-               g_list_free_full (jobs, (GDestroyNotify) camel_imapx_job_unref);
-       }
-
-       QUEUE_UNLOCK (is);
-}
-
-/* ********************************************************************** */
-
-static gboolean
-imapx_ready_to_read (GInputStream *input_stream,
-                     CamelIMAPXServer *is)
-{
-       GOutputStream *output_stream;
-       GCancellable *cancellable;
-       GError *local_error = NULL;
-
-       /* XXX Don't use the passed in GInputStream because that's
-        *     the CamelIMAPXInputStream base stream.  We need the
-        *     CamelIMAPXInputStream itself. */
-
-       input_stream = camel_imapx_server_ref_input_stream (is);
-       output_stream = camel_imapx_server_ref_output_stream (is);
-
-       cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
-       while (imapx_step (is, input_stream, cancellable, &local_error)) {
-               gint bytes_buffered;
-
-               bytes_buffered = camel_imapx_input_stream_buffered (
-                       CAMEL_IMAPX_INPUT_STREAM (input_stream));
-               if (bytes_buffered == 0)
-                       break;
-       }
-
-       if (g_cancellable_is_cancelled (cancellable)) {
-               gboolean active_queue_is_empty, is_shutdown_request;
-
-               QUEUE_LOCK (is);
-               active_queue_is_empty =
-                       camel_imapx_command_queue_is_empty (is->active);
-               is_shutdown_request = is->state == IMAPX_SHUTDOWN;
-               QUEUE_UNLOCK (is);
-
-               if (!is_shutdown_request && (active_queue_is_empty || imapx_in_idle (is))) {
-                       g_cancellable_reset (cancellable);
-                       g_clear_error (&local_error);
-               } else {
-                       /* Cancelled error should be set. */
-                       g_warn_if_fail (local_error != NULL);
-               }
-       }
-
-       g_clear_object (&input_stream);
-       g_clear_object (&output_stream);
-       g_clear_object (&cancellable);
-
-       if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
-               QUEUE_LOCK (is);
-               if (camel_imapx_command_queue_is_empty (is->active) && is->state != IMAPX_SHUTDOWN) {
-                       camel_imapx_debug (io, is->tagprefix, "Ignoring timeout error, nothing was waiting 
(original error: %s)\n", local_error->message);
-                       g_clear_error (&local_error);
-               }
-               QUEUE_UNLOCK (is);
-       }
-
-       if (local_error != NULL) {
-               camel_imapx_debug (io, is->tagprefix, "Data read failed with error '%s'\n", 
local_error->message);
-
-               /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error;
-                  since GLib 2.44 is used G_IO_ERROR_CONNECTION_CLOSED, which is the same as 
G_IO_ERROR_BROKEN_PIPE */
-               if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
-                   g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) ||
-                   g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
-                       local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
-                       local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
-               }
-
-               imapx_server_set_shutdown_error (is, local_error);
-
-               /* Call the signal early, certain thread interleaving can cause the closed connection
-                  being reused on the following reconnect attempt. There is also re-setting
-                  the shutdown_error above, because the signal handler in connection manager
-                  also calls camel_imapx_server_shutdown(), but without the error, while we want
-                  to have there propagated the "try reconnect" error instead. As there is no
-                  guarantee that it'll be called, then we also quit the parser's mainloop and
-                  call the imapx_abort_all_commands() below - just in case. */
-               g_signal_emit (is, signals[SHUTDOWN], 0, local_error);
-
-               g_main_loop_quit (is->priv->parser_main_loop);
-               imapx_abort_all_commands (is, local_error);
-               g_clear_error (&local_error);
-               return G_SOURCE_REMOVE;
-       }
-
-       return G_SOURCE_CONTINUE;
-}
-
-/*
- * The main processing (reading) loop.
- *
- * Main area of locking required is command_queue
- * and command_start_next, the 'literal' command,
- * the jobs queue, the active queue, the queue
- * queue. */
-static gpointer
-imapx_parser_thread (gpointer user_data)
-{
-       CamelIMAPXServer *is;
-       GInputStream *input_stream;
-       GCancellable *cancellable;
-       GSource *pollable_source;
-       GError *shutdown_error;
-
-       is = CAMEL_IMAPX_SERVER (user_data);
-
-       /* Do not use CamelOperation here, because it can be cancelled at
-        * an application end with camel_operation_cancel_all() call, which
-        * is done too early, before any pending jobs are properly finished
-        * (it can be IDLE job, or save of folder changes back to the server).
-        */
-       cancellable = g_cancellable_new ();
-       g_weak_ref_set (&is->priv->parser_cancellable, cancellable);
-
-       input_stream = camel_imapx_server_ref_input_stream (is);
-       g_return_val_if_fail (input_stream != NULL, NULL);
-
-       g_main_context_push_thread_default (is->priv->parser_main_context);
-
-       pollable_source = g_pollable_input_stream_create_source (
-               G_POLLABLE_INPUT_STREAM (input_stream), cancellable);
-       g_source_set_callback (
-               pollable_source,
-               (GSourceFunc) imapx_ready_to_read,
-               g_object_ref (is),
-               (GDestroyNotify) g_object_unref);
-       g_source_attach (
-               pollable_source,
-               is->priv->parser_main_context);
-       g_source_unref (pollable_source);
-
-       g_clear_object (&cancellable);
-       g_clear_object (&input_stream);
-
-       g_main_loop_run (is->priv->parser_main_loop);
-
-       QUEUE_LOCK (is);
-       is->state = IMAPX_SHUTDOWN;
-       QUEUE_UNLOCK (is);
-
-       g_main_context_pop_thread_default (is->priv->parser_main_context);
-
-       shutdown_error = imapx_server_dup_shutdown_error (is);
-
-       g_signal_emit (is, signals[SHUTDOWN], 0, shutdown_error);
-
-       g_clear_error (&shutdown_error);
-
-       g_object_unref (is);
-
-       return NULL;
-}
-
 static void
 imapx_server_set_store (CamelIMAPXServer *server,
                         CamelIMAPXStore *store)
@@ -7996,21 +3211,13 @@ imapx_server_dispose (GObject *object)
 {
        CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (object);
        gboolean idle_main_loop_is_running;
-       gboolean parser_main_loop_is_running;
-
-       /* Server should be shut down already.  Warn if
-        * the idle or parser threads are still running. */
-       idle_main_loop_is_running =
-               g_main_loop_is_running (server->priv->idle_main_loop);
-       parser_main_loop_is_running =
-               g_main_loop_is_running (server->priv->parser_main_loop);
-       g_warn_if_fail (!idle_main_loop_is_running);
-       g_warn_if_fail (!parser_main_loop_is_running);
 
-       if (server->priv->parser_thread != NULL) {
-               g_thread_unref (server->priv->parser_thread);
-               server->priv->parser_thread = NULL;
-       }
+       g_cancellable_cancel (server->priv->cancellable);
+
+       /* Server should be shut down already. Warn if
+        * the idle thread is still running. */
+       idle_main_loop_is_running = g_main_loop_is_running (server->priv->idle_main_loop);
+       g_warn_if_fail (!idle_main_loop_is_running);
 
        if (server->priv->idle_thread != NULL) {
                g_thread_unref (server->priv->idle_thread);
@@ -8023,6 +3230,18 @@ imapx_server_dispose (GObject *object)
 
        g_clear_object (&server->priv->subprocess);
 
+       g_rec_mutex_lock (&server->priv->idle_lock);
+       g_clear_object (&server->priv->idle_cancellable);
+       g_clear_object (&server->priv->idle_mailbox);
+       if (server->priv->idle_pending) {
+               g_source_destroy (server->priv->idle_pending);
+               g_source_unref (server->priv->idle_pending);
+               server->priv->idle_pending = NULL;
+       }
+       g_rec_mutex_unlock (&server->priv->idle_lock);
+
+       g_clear_object (&server->priv->subprocess);
+
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (camel_imapx_server_parent_class)->dispose (object);
 }
@@ -8033,21 +3252,8 @@ imapx_server_finalize (GObject *object)
        CamelIMAPXServer *is = CAMEL_IMAPX_SERVER (object);
 
        g_mutex_clear (&is->priv->stream_lock);
-
-       camel_imapx_command_queue_free (is->queue);
-       camel_imapx_command_queue_free (is->active);
-       camel_imapx_command_queue_free (is->done);
-
-       is->queue = NULL;
-       is->active = NULL;
-       is->done = NULL;
-
-       g_rec_mutex_clear (&is->queue_lock);
        g_mutex_clear (&is->priv->select_lock);
 
-       g_main_loop_unref (is->priv->parser_main_loop);
-       g_main_context_unref (is->priv->parser_main_context);
-
        camel_folder_change_info_free (is->priv->changes);
 
        g_free (is->priv->context);
@@ -8071,16 +3277,10 @@ 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);
-
-       g_mutex_clear (&is->priv->shutdown_error_lock);
-       g_clear_error (&is->priv->shutdown_error);
+       g_rec_mutex_clear (&is->priv->command_lock);
 
        g_weak_ref_clear (&is->priv->store);
-       g_weak_ref_clear (&is->priv->parser_cancellable);
        g_weak_ref_clear (&is->priv->select_mailbox);
-       g_weak_ref_clear (&is->priv->select_closing);
        g_weak_ref_clear (&is->priv->select_pending);
 
        /* Chain up to parent's finalize() method. */
@@ -8096,33 +3296,7 @@ imapx_server_constructed (GObject *object)
        G_OBJECT_CLASS (camel_imapx_server_parent_class)->constructed (object);
 
        server = CAMEL_IMAPX_SERVER (object);
-       server->tagprefix = 'Z';
-}
-
-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",
-               G_OBJECT_TYPE_NAME (is),
-               camel_imapx_mailbox_get_name (mailbox));
-}
-
-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",
-               G_OBJECT_TYPE_NAME (is),
-               camel_imapx_mailbox_get_name (mailbox));
+       server->priv->tagprefix = 'Z';
 }
 
 static void
@@ -8139,9 +3313,6 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
        object_class->dispose = imapx_server_dispose;
        object_class->constructed = imapx_server_constructed;
 
-       class->mailbox_select = imapx_server_mailbox_select;
-       class->mailbox_closed = imapx_server_mailbox_closed;
-
        g_object_class_install_property (
                object_class,
                PROP_STORE,
@@ -8154,37 +3325,14 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
                        G_PARAM_CONSTRUCT_ONLY |
                        G_PARAM_STATIC_STRINGS));
 
-       signals[MAILBOX_SELECT] = g_signal_new (
-               "mailbox-select",
-               G_OBJECT_CLASS_TYPE (class),
-               G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_select),
-               NULL, NULL, NULL,
-               G_TYPE_NONE, 1,
-               CAMEL_TYPE_IMAPX_MAILBOX);
-
-       signals[MAILBOX_CLOSED] = g_signal_new (
-               "mailbox-closed",
+       signals[REFRESH_MAILBOX] = g_signal_new (
+               "refresh-mailbox",
                G_OBJECT_CLASS_TYPE (class),
                G_SIGNAL_RUN_LAST,
-               G_STRUCT_OFFSET (CamelIMAPXServerClass, mailbox_closed),
+               G_STRUCT_OFFSET (CamelIMAPXServerClass, refresh_mailbox),
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
                CAMEL_TYPE_IMAPX_MAILBOX);
-
-       /**
-        * CamelIMAPXServer::shutdown
-        * @server: the #CamelIMAPXServer which emitted the signal
-        * @error: a #GError, which caused the shutdown; can be %NULL
-        **/
-       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__BOXED,
-               G_TYPE_NONE, 1, G_TYPE_ERROR);
 }
 
 static void
@@ -8201,28 +3349,14 @@ 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);
-       g_mutex_init (&is->priv->shutdown_error_lock);
 
        g_weak_ref_init (&is->priv->store, NULL);
-       g_weak_ref_init (&is->priv->parser_cancellable, NULL);
        g_weak_ref_init (&is->priv->select_mailbox, NULL);
-       g_weak_ref_init (&is->priv->select_closing, NULL);
        g_weak_ref_init (&is->priv->select_pending, NULL);
 
-       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->priv->cancellable = g_cancellable_new ();
 
-       is->queue = camel_imapx_command_queue_new ();
-       is->active = camel_imapx_command_queue_new ();
-       is->done = camel_imapx_command_queue_new ();
-
-       g_queue_init (&is->jobs);
-
-       g_rec_mutex_init (&is->queue_lock);
-
-       is->state = IMAPX_DISCONNECTED;
+       is->priv->state = IMAPX_DISCONNECTED;
        is->priv->is_cyrus = FALSE;
 
        is->priv->changes = camel_folder_change_info_new ();
@@ -8233,16 +3367,6 @@ camel_imapx_server_init (CamelIMAPXServer *is)
                (GDestroyNotify) g_free,
                (GDestroyNotify) NULL);
 
-       /* Initialize parser thread structs. */
-
-       main_context = g_main_context_new ();
-
-       is->priv->parser_main_loop = g_main_loop_new (main_context, FALSE);
-       is->priv->parser_main_context = g_main_context_ref (main_context);
-       is->priv->shutdown_error = NULL;
-
-       g_main_context_unref (main_context);
-
        /* Initialize IDLE thread structs. */
 
        main_context = g_main_context_new ();
@@ -8252,6 +3376,8 @@ camel_imapx_server_init (CamelIMAPXServer *is)
        is->priv->idle_main_context = g_main_context_ref (main_context);
 
        g_main_context_unref (main_context);
+
+       g_rec_mutex_init (&is->priv->command_lock);
 }
 
 CamelIMAPXServer *
@@ -8378,8 +3504,6 @@ camel_imapx_server_ref_selected (CamelIMAPXServer *is)
 
        mailbox = g_weak_ref_get (&is->priv->select_mailbox);
        if (mailbox == NULL)
-               mailbox = g_weak_ref_get (&is->priv->select_closing);
-       if (mailbox == NULL)
                mailbox = g_weak_ref_get (&is->priv->select_pending);
 
        g_mutex_unlock (&is->priv->select_lock);
@@ -8401,19 +3525,251 @@ camel_imapx_server_ref_pending_or_selected (CamelIMAPXServer *is)
        mailbox = g_weak_ref_get (&is->priv->select_pending);
        if (mailbox == NULL)
                mailbox = g_weak_ref_get (&is->priv->select_mailbox);
-       if (mailbox == NULL)
-               mailbox = g_weak_ref_get (&is->priv->select_closing);
 
        g_mutex_unlock (&is->priv->select_lock);
 
        return mailbox;
 }
 
+gboolean
+camel_imapx_server_mailbox_selected (CamelIMAPXServer *is,
+                                    CamelIMAPXMailbox *mailbox)
+{
+       CamelIMAPXMailbox *selected_mailbox;
+       gboolean res;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       g_mutex_lock (&is->priv->select_lock);
+       selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+       res = selected_mailbox == mailbox;
+       g_clear_object (&selected_mailbox);
+       g_mutex_unlock (&is->priv->select_lock);
+
+       return res;
+}
+
+gboolean
+camel_imapx_server_ensure_selected_sync (CamelIMAPXServer *is,
+                                        CamelIMAPXMailbox *mailbox,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+       CamelIMAPXCommand *ic;
+       CamelIMAPXMailbox *selected_mailbox;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       g_mutex_lock (&is->priv->select_lock);
+       selected_mailbox = g_weak_ref_get (&is->priv->select_mailbox);
+       if (selected_mailbox == mailbox) {
+               g_mutex_unlock (&is->priv->select_lock);
+               g_clear_object (&selected_mailbox);
+               return TRUE;
+       }
+
+       g_clear_object (&selected_mailbox);
+
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SELECT, "SELECT %M", mailbox);
+
+       if (is->priv->use_qresync) {
+               CamelFolder *folder;
+
+               folder = imapx_server_ref_folder (is, mailbox);
+               camel_imapx_command_add_qresync_parameter (ic, folder);
+               g_clear_object (&folder);
+       }
+
+       g_weak_ref_set (&is->priv->select_pending, mailbox);
+       g_mutex_unlock (&is->priv->select_lock);
+
+       success = camel_imapx_server_process_command_sync (is, ic, _("Failed to select mailbox"), 
cancellable, error);
+
+       camel_imapx_command_unref (ic);
+
+       g_mutex_lock (&is->priv->select_lock);
+
+       g_weak_ref_set (&is->priv->select_pending, NULL);
+
+       if (success) {
+               is->priv->state = IMAPX_SELECTED;
+               g_weak_ref_set (&is->priv->select_mailbox, mailbox);
+       }
+
+       g_mutex_unlock (&is->priv->select_lock);
+
+       return success;
+}
+
+gboolean
+camel_imapx_server_process_command_sync (CamelIMAPXServer *is,
+                                        CamelIMAPXCommand *ic,
+                                        const gchar *error_prefix,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+       CamelIMAPXCommandPart *cp;
+       GInputStream *input_stream = NULL;
+       GOutputStream *output_stream = NULL;
+       gboolean cp_literal_plus;
+       GList *head;
+       gchar *string;
+       gboolean success = FALSE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
+
+       camel_imapx_command_close (ic);
+       if (ic->status) {
+               imapx_free_status (ic->status);
+               ic->status = NULL;
+       }
+       ic->completed = FALSE;
+
+       head = g_queue_peek_head_link (&ic->parts);
+       g_return_val_if_fail (head != NULL, FALSE);
+       cp = (CamelIMAPXCommandPart *) head->data;
+       ic->current_part = head;
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+               if (error_prefix && local_error)
+                       g_prefix_error (&local_error, "%s: ", error_prefix);
+
+               if (local_error)
+                       g_propagate_error (error, local_error);
+
+               return FALSE;
+       }
+
+       cp_literal_plus = ((cp->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) != 0);
+
+       COMMAND_LOCK (is);
+
+       g_warn_if_fail (is->priv->current_command == NULL);
+
+       c (is->priv->tagprefix, "%s: %p ~> %p\n", G_STRFUNC, is->priv->current_command, ic);
+
+       is->priv->current_command = ic;
+       is->priv->continuation_command = ic;
+
+       COMMAND_UNLOCK (is);
+
+       input_stream = camel_imapx_server_ref_input_stream (is);
+       output_stream = camel_imapx_server_ref_output_stream (is);
+
+       if (output_stream == NULL) {
+               local_error = g_error_new_literal (
+                       CAMEL_IMAPX_ERROR, 1,
+                       _("Cannot issue command, no stream available"));
+               goto exit;
+       }
+
+       c (
+               is->priv->tagprefix,
+               "Starting command (%s) %c%05u %s\r\n",
+               is->priv->current_command ? " literal" : "",
+               is->priv->tagprefix,
+               ic->tag,
+               cp->data && g_str_has_prefix (cp->data, "LOGIN") ?
+                       "LOGIN..." : cp->data);
+
+       if (ic->job_kind == CAMEL_IMAPX_JOB_DONE)
+               string = g_strdup_printf ("%s\r\n", cp->data);
+       else
+               string = g_strdup_printf ("%c%05u %s\r\n", is->priv->tagprefix, ic->tag, cp->data);
+       g_mutex_lock (&is->priv->stream_lock);
+       success = g_output_stream_write_all (
+               output_stream, string, strlen (string),
+               NULL, cancellable, &local_error);
+       g_mutex_unlock (&is->priv->stream_lock);
+       g_free (string);
+
+       if (local_error != NULL || !success)
+               goto exit;
+
+       while (is->priv->continuation_command == ic && cp_literal_plus) {
+               /* Sent LITERAL+ continuation immediately */
+               imapx_continuation (
+                       is, input_stream, output_stream,
+                       TRUE, cancellable, &local_error);
+               if (local_error != NULL)
+                       goto exit;
+       }
+
+       while (success && !ic->completed)
+               success = imapx_step (is, input_stream, cancellable, &local_error);
+
+       imapx_server_reset_inactivity_timer (is);
+
+ exit:
+
+       COMMAND_LOCK (is);
+
+       if (is->priv->current_command == ic) {
+               c (is->priv->tagprefix, "%s: %p ~> %p; success:%d local-error:%s result:%s 
status-text:'%s'\n", G_STRFUNC,
+                       is->priv->current_command, NULL, success, local_error ? local_error->message : 
"[null]",
+                       ic->status ? (
+                               ic->status->result == IMAPX_OK ? "OK" :
+                               ic->status->result == IMAPX_NO ? "NO" :
+                               ic->status->result == IMAPX_BAD ? "BAD" :
+                               ic->status->result == IMAPX_PREAUTH ? "PREAUTH" :
+                               ic->status->result == IMAPX_BYE ? "BYE" : "???") : "[null]",
+                       ic->status ? ic->status->text : "[null]");
+
+               is->priv->current_command = NULL;
+               is->priv->continuation_command = NULL;
+       }
+
+       COMMAND_UNLOCK (is);
+
+       /* Server reported error. */
+       if (success && ic->status && ic->status->result != IMAPX_OK) {
+               g_set_error (
+                       &local_error, CAMEL_ERROR,
+                       CAMEL_ERROR_GENERIC,
+                       "%s", ic->status->text);
+       }
+
+       if (local_error) {
+               /* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error;
+                  since GLib 2.44 is used G_IO_ERROR_CONNECTION_CLOSED, which is the same as 
G_IO_ERROR_BROKEN_PIPE */
+               if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
+                   g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) ||
+                   g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
+                       local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
+                       local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
+               }
+
+               if (error_prefix && local_error)
+                       g_prefix_error (&local_error, "%s: ", error_prefix);
+
+               g_propagate_error (error, local_error);
+
+               success = FALSE;
+       }
+
+       g_clear_object (&input_stream);
+       g_clear_object (&output_stream);
+
+       return success;
+}
+
 static void
 imapx_disconnect (CamelIMAPXServer *is)
 {
+       g_cancellable_cancel (is->priv->cancellable);
+
        g_mutex_lock (&is->priv->stream_lock);
 
+       if (is->priv->connection) {
+               /* No need to wait for close for too long */
+               imapx_server_set_connection_timeout (is->priv->connection, 3);
+       }
+
        g_clear_object (&is->priv->input_stream);
        g_clear_object (&is->priv->output_stream);
        g_clear_object (&is->priv->connection);
@@ -8423,28 +3779,27 @@ imapx_disconnect (CamelIMAPXServer *is)
 
        g_mutex_lock (&is->priv->select_lock);
        g_weak_ref_set (&is->priv->select_mailbox, NULL);
-       g_weak_ref_set (&is->priv->select_closing, NULL);
        g_weak_ref_set (&is->priv->select_pending, NULL);
        g_mutex_unlock (&is->priv->select_lock);
 
-       if (is->cinfo) {
-               imapx_free_capability (is->cinfo);
-               is->cinfo = NULL;
+       if (is->priv->cinfo) {
+               imapx_free_capability (is->priv->cinfo);
+               is->priv->cinfo = NULL;
        }
 
        is->priv->is_cyrus = FALSE;
-       is->state = IMAPX_DISCONNECTED;
+       is->priv->state = IMAPX_DISCONNECTED;
 }
 
 /* Client commands */
 gboolean
-camel_imapx_server_connect (CamelIMAPXServer *is,
-                            GCancellable *cancellable,
-                            GError **error)
+camel_imapx_server_connect_sync (CamelIMAPXServer *is,
+                                GCancellable *cancellable,
+                                GError **error)
 {
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       if (is->state == IMAPX_SHUTDOWN) {
+       if (is->priv->state == IMAPX_SHUTDOWN) {
                g_set_error (
                        error, CAMEL_SERVICE_ERROR,
                        CAMEL_SERVICE_ERROR_UNAVAILABLE,
@@ -8452,7 +3807,7 @@ camel_imapx_server_connect (CamelIMAPXServer *is,
                return FALSE;
        }
 
-       if (is->state >= IMAPX_INITIALISED)
+       if (is->priv->state >= IMAPX_INITIALISED)
                return TRUE;
 
        is->priv->is_cyrus = FALSE;
@@ -8460,70 +3815,90 @@ camel_imapx_server_connect (CamelIMAPXServer *is,
        if (!imapx_reconnect (is, cancellable, error))
                return FALSE;
 
-       is->priv->parser_thread = g_thread_new (
-               NULL, imapx_parser_thread, g_object_ref (is));
-
-       if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, NAMESPACE)) {
+       if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, NAMESPACE)) {
                /* This also creates a needed faux NAMESPACE */
-               if (!camel_imapx_server_list (is, "INBOX", 0, cancellable, error))
+               if (!camel_imapx_server_list_sync (is, "INBOX", 0, cancellable, error))
                        return FALSE;
        }
 
        return TRUE;
 }
 
-static CamelStream *
-imapx_server_get_message (CamelIMAPXServer *is,
-                          CamelIMAPXMailbox *mailbox,
-                          CamelFolderSummary *summary,
-                          CamelDataCache *message_cache,
-                          const gchar *message_uid,
-                          gint pri,
-                          GCancellable *cancellable,
-                          GError **error)
+gboolean
+camel_imapx_server_disconnect_sync (CamelIMAPXServer *is,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
-       CamelStream *stream = NULL;
-       CamelIMAPXJob *job;
-       CamelMessageInfo *mi;
-       GIOStream *cache_stream;
-       GetMessageData *data;
-       gboolean registered;
-
-       while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_GET_MESSAGE, message_uid), job != NULL) {
-               /* Promote the existing GET_MESSAGE
-                * job's priority if ours is higher. */
-               if (pri > job->pri)
-                       job->pri = pri;
-
-               /* Wait for the job to finish. */
-               camel_imapx_job_wait (job, NULL);
-               camel_imapx_job_unref (job);
-
-               /* Disregard errors here.  If we failed to retreive the
-                * message from cache (implying the job we were waiting
-                * on failed or got cancelled), we'll just re-fetch it. */
-               cache_stream = camel_data_cache_get (
-                       message_cache, "cur", message_uid, NULL);
-               if (cache_stream != NULL) {
-                       /* Return new file stream, instead of a DataCache's to not fight
-                          on its content and position with other jobs, if any. */
-                       gchar *filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
-                       stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
-                       g_free (filename);
-                       g_object_unref (cache_stream);
-
-                       if (stream)
-                               return stream;
-               }
+       GCancellable *idle_cancellable;
+       gboolean success = TRUE;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+       g_rec_mutex_lock (&is->priv->idle_lock);
+       idle_cancellable = is->priv->idle_cancellable;
+       if (idle_cancellable)
+               g_object_ref (idle_cancellable);
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       if (idle_cancellable)
+               g_cancellable_cancel (idle_cancellable);
+       g_clear_object (&idle_cancellable);
+
+       g_mutex_lock (&is->priv->stream_lock);
+       if (is->priv->connection) {
+               /* No need to wait for close for too long */
+               imapx_server_set_connection_timeout (is->priv->connection, 3);
        }
+       g_mutex_unlock (&is->priv->stream_lock);
 
-       QUEUE_LOCK (is);
+       /* Ignore errors here. */
+       camel_imapx_server_stop_idle_sync (is, cancellable, NULL);
 
-       if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
-               QUEUE_UNLOCK (is);
+       g_mutex_lock (&is->priv->stream_lock);
+       if (is->priv->connection)
+               success = g_io_stream_close (is->priv->connection, cancellable, error);
+       g_mutex_unlock (&is->priv->stream_lock);
 
+       imapx_disconnect (is);
+
+       return success;
+}
+
+gboolean
+camel_imapx_server_query_auth_types_sync (CamelIMAPXServer *is,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+       return imapx_connect_to_server (is, cancellable, error);
+}
+
+CamelStream *
+camel_imapx_server_get_message_sync (CamelIMAPXServer *is,
+                                    CamelIMAPXMailbox *mailbox,
+                                    CamelFolderSummary *summary,
+                                    CamelDataCache *message_cache,
+                                    const gchar *message_uid,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+       CamelMessageInfo *mi;
+       CamelStream *result_stream = NULL;
+       GIOStream *cache_stream;
+       gsize data_size;
+       gboolean use_multi_fetch;
+       gboolean success;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+       g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
+       g_return_val_if_fail (message_uid != NULL, NULL);
+
+       if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
                return NULL;
-       }
 
        mi = camel_folder_summary_get (summary, message_uid);
        if (mi == NULL) {
@@ -8532,7 +3907,6 @@ imapx_server_get_message (CamelIMAPXServer *is,
                        CAMEL_FOLDER_ERROR_INVALID_UID,
                        _("Cannot get message with message ID %s: %s"),
                        message_uid, _("No such message available."));
-               QUEUE_UNLOCK (is);
                return NULL;
        }
 
@@ -8544,76 +3918,133 @@ imapx_server_get_message (CamelIMAPXServer *is,
        cache_stream = camel_data_cache_add (message_cache, "tmp", message_uid, error);
        if (cache_stream == NULL) {
                camel_message_info_unref (mi);
-               QUEUE_UNLOCK (is);
                return NULL;
        }
 
-       data = g_slice_new0 (GetMessageData);
-       data->uid = g_strdup (message_uid);
-       data->message_cache = g_object_ref (message_cache);
-       data->stream = g_object_ref (cache_stream);
-       data->size = ((CamelMessageInfoBase *) mi)->size;
-       if (data->size > MULTI_SIZE)
-               data->use_multi_fetch = TRUE;
+       data_size = ((CamelMessageInfoBase *) mi)->size;
+       use_multi_fetch = data_size > MULTI_SIZE;
 
-       job = camel_imapx_job_new (cancellable);
-       job->pri = pri;
-       job->type = IMAPX_JOB_GET_MESSAGE;
-       job->start = imapx_job_get_message_start;
-       job->matches = imapx_job_get_message_matches;
+       g_warn_if_fail (is->priv->get_message_stream == NULL);
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+       is->priv->get_message_stream = cache_stream;
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) get_message_data_free);
+       if (use_multi_fetch) {
+               CamelIMAPXCommand *ic;
+               gsize fetch_offset = 0;
 
-       g_clear_object (&cache_stream);
-       camel_message_info_unref (mi);
+               do {
+                       camel_operation_progress (cancellable, fetch_offset * 100 / data_size);
 
-       registered = imapx_register_job (is, job, error);
+                       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t 
(BODY.PEEK[]", message_uid);
+                       camel_imapx_command_add (ic, "<%u.%u>", fetch_offset, MULTI_SIZE);
+                       camel_imapx_command_add (ic, ")");
+                       fetch_offset += MULTI_SIZE;
 
-       QUEUE_UNLOCK (is);
+                       success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching 
message"), cancellable, &local_error);
 
-       if (registered && camel_imapx_job_run (job, is, error))
-               stream = camel_stream_new (data->stream);
-       else if (registered)
-               imapx_unregister_job (is, job);
+                       camel_imapx_command_unref (ic);
+                       ic = NULL;
 
-       camel_imapx_job_unref (job);
+                       if (success) {
+                               gsize really_fetched = g_seekable_tell (G_SEEKABLE 
(is->priv->get_message_stream));
+
+                               /* Don't automatically stop when we reach the reported message
+                                * size -- some crappy servers (like Microsoft Exchange) have
+                                * a tendency to lie about it. Keep going (one request at a
+                                * time) until the data actually stop coming. */
+                               if (fetch_offset < data_size ||
+                                   fetch_offset == really_fetched) {
+                                       /* just continue */
+                               } else {
+                                       break;
+                               }
+                       }
+               } while (success);
+       } else {
+               CamelIMAPXCommand *ic;
 
-       return stream;
-}
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_GET_MESSAGE, "UID FETCH %t (BODY.PEEK[])", 
message_uid);
 
-CamelStream *
-camel_imapx_server_get_message (CamelIMAPXServer *is,
-                                CamelIMAPXMailbox *mailbox,
-                                CamelFolderSummary *summary,
-                                CamelDataCache *message_cache,
-                                const gchar *message_uid,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
-       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
-       g_return_val_if_fail (CAMEL_IS_DATA_CACHE (message_cache), NULL);
-       g_return_val_if_fail (message_uid != NULL, NULL);
+               success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching message"), 
cancellable, &local_error);
 
-       return imapx_server_get_message (
-               is, mailbox, summary,
-               message_cache, message_uid,
-               IMAPX_PRIORITY_GET_MESSAGE,
-               cancellable, error);
+               camel_imapx_command_unref (ic);
+       }
+
+       is->priv->get_message_stream = NULL;
+
+       if (success) {
+               if (local_error == NULL) {
+                       g_io_stream_close (cache_stream, cancellable, &local_error);
+                       g_prefix_error (
+                               &local_error, "%s: ",
+                               _("Failed to close the tmp stream"));
+               }
+
+               if (local_error == NULL &&
+                   g_cancellable_set_error_if_cancelled (cancellable, &local_error)) {
+                       g_prefix_error (
+                               &local_error, "%s: ",
+                               _("Error fetching message"));
+               }
+
+               if (local_error == NULL) {
+                       gchar *cur_filename;
+                       gchar *tmp_filename;
+                       gchar *dirname;
+
+                       cur_filename = camel_data_cache_get_filename (message_cache, "cur", message_uid);
+                       tmp_filename = camel_data_cache_get_filename (message_cache, "tmp", message_uid);
+
+                       dirname = g_path_get_dirname (cur_filename);
+                       g_mkdir_with_parents (dirname, 0700);
+                       g_free (dirname);
+
+                       if (g_rename (tmp_filename, cur_filename) == 0) {
+                               /* Exchange the "tmp" stream for the "cur" stream. */
+                               g_clear_object (&cache_stream);
+                               cache_stream = camel_data_cache_get (message_cache, "cur", message_uid, 
&local_error);
+                       } else {
+                               g_set_error (
+                                       &local_error, G_FILE_ERROR,
+                                       g_file_error_from_errno (errno),
+                                       "%s: %s",
+                                       _("Failed to copy the tmp file"),
+                                       g_strerror (errno));
+                       }
+
+                       g_free (cur_filename);
+                       g_free (tmp_filename);
+               }
+
+               /* Delete the 'tmp' file only if the operation succeeded. It's because
+                  cancelled operations end before they are properly finished (IMAP-protocol speaking),
+                  thus if any other GET_MESSAGE operation was waiting for this job, then it
+                  realized that the message was not downloaded and opened its own "tmp" file, but
+                  of the same name, thus this remove would drop file which could be used
+                  by a different GET_MESSAGE job. */
+               if (!local_error && !g_cancellable_is_cancelled (cancellable))
+                       camel_data_cache_remove (message_cache, "tmp", message_uid, NULL);
+       }
+
+       if (!local_error) {
+               result_stream = camel_stream_new (cache_stream);
+       } else {
+               g_propagate_error (error, local_error);
+       }
+
+       g_object_unref (cache_stream);
+
+       return result_stream;
 }
 
 gboolean
-camel_imapx_server_sync_message (CamelIMAPXServer *is,
-                                 CamelIMAPXMailbox *mailbox,
-                                 CamelFolderSummary *summary,
-                                 CamelDataCache *message_cache,
-                                 const gchar *message_uid,
-                                 GCancellable *cancellable,
-                                 GError **error)
+camel_imapx_server_sync_message_sync (CamelIMAPXServer *is,
+                                     CamelIMAPXMailbox *mailbox,
+                                     CamelFolderSummary *summary,
+                                     CamelDataCache *message_cache,
+                                     const gchar *message_uid,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
        gchar *cache_file = NULL;
        gboolean is_cached;
@@ -8627,18 +4058,16 @@ camel_imapx_server_sync_message (CamelIMAPXServer *is,
        g_return_val_if_fail (message_uid != NULL, FALSE);
 
        /* Check if the cache file already exists and is non-empty. */
-       cache_file = camel_data_cache_get_filename (
-               message_cache, "cur", message_uid);
+       cache_file = camel_data_cache_get_filename (message_cache, "cur", message_uid);
        is_cached = (g_stat (cache_file, &st) == 0 && st.st_size > 0);
        g_free (cache_file);
 
        if (!is_cached) {
                CamelStream *stream;
 
-               stream = imapx_server_get_message (
+               stream = camel_imapx_server_get_message_sync (
                        is, mailbox, summary,
                        message_cache, message_uid,
-                       IMAPX_PRIORITY_SYNC_MESSAGE,
                        cancellable, error);
 
                success = (stream != NULL);
@@ -8650,86 +4079,227 @@ camel_imapx_server_sync_message (CamelIMAPXServer *is,
 }
 
 gboolean
-camel_imapx_server_copy_message (CamelIMAPXServer *is,
-                                 CamelIMAPXMailbox *mailbox,
-                                 CamelIMAPXMailbox *destination,
-                                 GPtrArray *uids,
-                                 gboolean delete_originals,
-                                gboolean remove_deleted_flags,
-                                 GCancellable *cancellable,
-                                 GError **error)
-{
-       CamelIMAPXJob *job;
-       CopyMessagesData *data;
+camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
+                                     CamelIMAPXMailbox *mailbox,
+                                     CamelIMAPXMailbox *destination,
+                                     GPtrArray *uids,
+                                     gboolean delete_originals,
+                                     gboolean remove_deleted_flags,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       GPtrArray *data_uids;
        gint ii;
-       gboolean success;
+       gboolean use_move_command = FALSE;
+       CamelIMAPXCommand *ic;
+       CamelFolder *folder;
+       gboolean success = TRUE;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (destination), FALSE);
        g_return_val_if_fail (uids != NULL, FALSE);
 
-       /* That's okay if the "SELECT" fails here, as it can be due to
-          the folder being write-only; just ignore the error and continue. */
-       imapx_ensure_mailbox_permanentflags (is, destination, cancellable, NULL);
+       /* To get permanent flags. That's okay if the "SELECT" fails here, as it can be
+          due to the folder being write-only; just ignore the error and continue. */
+       camel_imapx_server_ensure_selected_sync (is, destination, cancellable, NULL);
 
        if (g_cancellable_set_error_if_cancelled (cancellable, error))
                return FALSE;
 
-       data = g_slice_new0 (CopyMessagesData);
-       data->destination = g_object_ref (destination);
-       data->uids = g_ptr_array_new ();
-       data->delete_originals = delete_originals;
-       data->remove_deleted_flags = remove_deleted_flags;
+       if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error))
+               return FALSE;
+
+       folder = imapx_server_ref_folder (is, mailbox);
+       g_return_val_if_fail (folder != NULL, FALSE);
 
        /* If we're moving messages, prefer "UID MOVE" if supported. */
-       if (data->delete_originals) {
-               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->cinfo, MOVE)) {
-                       data->delete_originals = FALSE;
-                       data->use_move_command = TRUE;
+       if (delete_originals) {
+               if (CAMEL_IMAPX_HAVE_CAPABILITY (is->priv->cinfo, MOVE)) {
+                       delete_originals = FALSE;
+                       use_move_command = TRUE;
                }
        }
 
-       for (ii = 0; ii < uids->len; ii++)
-               g_ptr_array_add (data->uids, g_strdup (uids->pdata[ii]));
+       data_uids = g_ptr_array_new ();
 
-       job = camel_imapx_job_new (cancellable);
-       job->pri = IMAPX_PRIORITY_COPY_MESSAGE;
-       job->type = IMAPX_JOB_COPY_MESSAGE;
-       job->start = imapx_job_copy_messages_start;
-       job->matches = imapx_job_copy_messages_matches;
+       for (ii = 0; ii < uids->len; ii++) {
+               g_ptr_array_add (data_uids, (gpointer) camel_pstring_strdup (uids->pdata[ii]));
+       }
+
+       g_ptr_array_sort (data_uids, (GCompareFunc) imapx_uids_array_cmp);
+
+       ii = 0;
+       while (ii < data_uids->len && success) {
+               struct _uidset_state uidset;
+               gint last_index = ii;
+
+               imapx_uidset_init (&uidset, 0, MAX_COMMAND_LEN);
+
+               if (use_move_command)
+                       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_MOVE_MESSAGE, "UID MOVE ");
+               else
+                       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_COPY_MESSAGE, "UID COPY ");
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+               while (ii < data_uids->len) {
+                       const gchar *uid = (gchar *) g_ptr_array_index (data_uids, ii);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) copy_messages_data_free);
+                       ii++;
 
-       success = imapx_submit_job (is, job, error);
+                       if (imapx_uidset_add (&uidset, ic, uid) == 1)
+                               break;
+               }
 
-       camel_imapx_job_unref (job);
+               imapx_uidset_done (&uidset, ic);
+
+               camel_imapx_command_add (ic, " %M", destination);
+
+               success = camel_imapx_server_process_command_sync (is, ic,
+                       use_move_command ? _("Error moving messages") : _("Error copying messages"),
+                       cancellable, error);
+
+               if (success) {
+                       if (ic->status && ic->status->u.copyuid.uids && ic->status->u.copyuid.copied_uids &&
+                           ic->status->u.copyuid.uids->len == ic->status->u.copyuid.copied_uids->len) {
+                               CamelFolder *destination_folder;
+
+                               destination_folder = imapx_server_ref_folder (is, destination);
+                               if (destination_folder) {
+                                       CamelMessageInfo *source_info, *destination_info;
+                                       CamelFolderChangeInfo *changes;
+                                       gint ii;
+
+                                       changes = camel_folder_change_info_new ();
+
+                                       for (ii = 0; ii < ic->status->u.copyuid.uids->len; ii++) {
+                                               gchar *uid;
+                                               gboolean is_new = FALSE;
+
+                                               uid = g_strdup_printf ("%d", g_array_index 
(ic->status->u.copyuid.uids, guint32, ii));
+                                               source_info = camel_folder_summary_get (folder->summary, uid);
+                                               g_free (uid);
+
+                                               if (!source_info)
+                                                       continue;
+
+                                               uid = g_strdup_printf ("%d", g_array_index 
(ic->status->u.copyuid.copied_uids, guint32, ii));
+                                               destination_info = camel_folder_summary_get (folder->summary, 
uid);
+
+                                               if (!destination_info) {
+                                                       is_new = TRUE;
+                                                       destination_info = camel_message_info_clone 
(source_info);
+                                                       destination_info->summary = 
destination_folder->summary;
+                                                       camel_pstring_free (destination_info->uid);
+                                                       destination_info->uid = camel_pstring_strdup (uid);
+                                               }
+
+                                               g_free (uid);
+
+                                               imapx_set_message_info_flags_for_new_message (
+                                                       destination_info,
+                                                       ((CamelMessageInfoBase *) source_info)->flags,
+                                                       ((CamelMessageInfoBase *) source_info)->user_flags,
+                                                       TRUE,
+                                                       ((CamelMessageInfoBase *) source_info)->user_tags,
+                                                       camel_imapx_mailbox_get_permanentflags (destination));
+                                               if (remove_deleted_flags)
+                                                       camel_message_info_set_flags (destination_info, 
CAMEL_MESSAGE_DELETED, 0);
+                                               if (is_new)
+                                                       camel_folder_summary_add 
(destination_folder->summary, destination_info);
+                                               camel_folder_change_info_add_uid (changes, 
destination_info->uid);
+
+                                               camel_message_info_unref (source_info);
+                                               if (!is_new)
+                                                       camel_message_info_unref (destination_info);
+                                       }
+
+                                       if (camel_folder_change_info_changed (changes)) {
+                                               camel_folder_summary_touch (destination_folder->summary);
+                                               camel_folder_summary_save_to_db (destination_folder->summary, 
NULL);
+                                               camel_folder_changed (destination_folder, changes);
+                                       }
+
+                                       camel_folder_change_info_free (changes);
+                                       g_object_unref (destination_folder);
+                               }
+                       }
+
+                       if (delete_originals || use_move_command) {
+                               CamelFolderChangeInfo *changes = NULL;
+                               gint jj;
+
+                               camel_folder_freeze (folder);
+
+                               for (jj = last_index; jj < ii; jj++) {
+                                       const gchar *uid = uids->pdata[jj];
+
+                                       if (delete_originals) {
+                                               camel_folder_delete_message (folder, uid);
+                                       } else {
+                                               if (camel_folder_summary_remove_uid (folder->summary, uid)) {
+                                                       if (!changes)
+                                                               changes = camel_folder_change_info_new ();
+
+                                                       camel_folder_change_info_remove_uid (changes, uid);
+                                               }
+                                       }
+                               }
+
+                               if (changes && camel_folder_change_info_changed (changes)) {
+                                       camel_folder_summary_touch (folder->summary);
+                                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                                       camel_folder_changed (folder, changes);
+                               }
+
+                               camel_folder_thaw (folder);
+
+                               if (changes)
+                                       camel_folder_change_info_free (changes);
+                       }
+               }
+
+               camel_imapx_command_unref (ic);
+       }
+
+       g_ptr_array_foreach (data_uids, (GFunc) camel_pstring_free, NULL);
+       g_ptr_array_free (data_uids, TRUE);
+       g_object_unref (folder);
 
        return success;
 }
 
+static const gchar *
+get_month_str (gint month)
+{
+       static const gchar tm_months[][4] = {
+               "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+       };
+
+       if (month < 1 || month > 12)
+               return NULL;
+
+       return tm_months[month - 1];
+}
+
 gboolean
-camel_imapx_server_append_message (CamelIMAPXServer *is,
-                                   CamelIMAPXMailbox *mailbox,
-                                   CamelFolderSummary *summary,
-                                   CamelDataCache *message_cache,
-                                   CamelMimeMessage *message,
-                                   const CamelMessageInfo *mi,
-                                   gchar **appended_uid,
-                                   GCancellable *cancellable,
-                                   GError **error)
+camel_imapx_server_append_message_sync (CamelIMAPXServer *is,
+                                       CamelIMAPXMailbox *mailbox,
+                                       CamelFolderSummary *summary,
+                                       CamelDataCache *message_cache,
+                                       CamelMimeMessage *message,
+                                       const CamelMessageInfo *mi,
+                                       gchar **appended_uid,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
        gchar *uid = NULL, *path = NULL;
        CamelMimeFilter *filter;
-       CamelIMAPXJob *job;
+       CamelIMAPXCommand *ic;
        CamelMessageInfo *info;
        GIOStream *base_stream;
        GOutputStream *output_stream;
        GOutputStream *filter_stream;
-       AppendMessageData *data;
        gint res;
        time_t date_time;
        gboolean success;
@@ -8743,7 +4313,7 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 
        /* That's okay if the "SELECT" fails here, as it can be due to
           the folder being write-only; just ignore the error and continue. */
-       imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, NULL);
+       camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, NULL);
 
        if (g_cancellable_set_error_if_cancelled (cancellable, error))
                return FALSE;
@@ -8787,9 +4357,9 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 
        date_time = camel_mime_message_get_date (message, NULL);
        path = camel_data_cache_get_filename (message_cache, "new", uid);
-       info = camel_folder_summary_info_new_from_message (
-               summary, message, NULL);
+       info = camel_folder_summary_info_new_from_message (summary, message, NULL);
        info->uid = camel_pstring_strdup (uid);
+
        if (mi != NULL) {
                struct icaltimetype icaltime;
                CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
@@ -8838,145 +4408,511 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
        if (camel_mime_message_has_attachment (message))
                ((CamelMessageInfoBase *) info)->flags |= CAMEL_MESSAGE_ATTACHMENTS;
 
-       /* So, we actually just want to let the server loop that
-        * messages need appending, i think.  This is so the same
-        * mechanism is used for normal uploading as well as
-        * offline re-syncing when we go back online */
+       if (date_time > 0) {
+               gchar *date_time_str;
+               struct tm stm;
+
+               gmtime_r (&date_time, &stm);
+
+               /* Store always in UTC */
+               date_time_str = g_strdup_printf (
+                       "\"%02d-%s-%04d %02d:%02d:%02d +0000\"",
+                       stm.tm_mday,
+                       get_month_str (stm.tm_mon + 1),
+                       stm.tm_year + 1900,
+                       stm.tm_hour,
+                       stm.tm_min,
+                       stm.tm_sec);
+
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %t %P",
+                       mailbox,
+                       ((CamelMessageInfoBase *) info)->flags,
+                       ((CamelMessageInfoBase *) info)->user_flags,
+                       date_time_str,
+                       path);
+
+               g_free (date_time_str);
+       } else {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_APPEND_MESSAGE, "APPEND %M %F %P",
+                       mailbox,
+                       ((CamelMessageInfoBase *) info)->flags,
+                       ((CamelMessageInfoBase *) info)->user_flags,
+                       path);
+       }
+
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error appending message"), cancellable, 
error);
+
+       if (success) {
+               CamelIMAPXFolder *imapx_folder;
+               CamelFolder *folder;
+               CamelMessageInfo *mi;
+               gchar *cur, *old_uid;
+               guint32 uidvalidity;
+
+               folder = imapx_server_ref_folder (is, mailbox);
+               g_return_val_if_fail (folder != NULL, FALSE);
+
+               uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
 
-       data = g_slice_new0 (AppendMessageData);
-       data->info = info;  /* takes ownership */
-       data->path = path;  /* takes ownership */
-       data->date_time = date_time;
-       data->appended_uid = NULL;
+               imapx_folder = CAMEL_IMAPX_FOLDER (folder);
 
-       job = camel_imapx_job_new (cancellable);
-       job->pri = IMAPX_PRIORITY_APPEND_MESSAGE;
-       job->type = IMAPX_JOB_APPEND_MESSAGE;
-       job->start = imapx_job_append_message_start;
-       job->noreply = FALSE;
+               /* Append done.  If we the server supports UIDPLUS we will get
+                * an APPENDUID response with the new uid.  This lets us move the
+                * message we have directly to the cache and also create a correctly
+                * numbered MessageInfo, without losing any information.  Otherwise
+                * we have to wait for the server to let us know it was appended. */
+
+               mi = camel_message_info_clone (info);
+               old_uid = g_strdup (info->uid);
+
+               if (ic->status && ic->status->condition == IMAPX_APPENDUID) {
+                       c (is->priv->tagprefix, "Got appenduid %d %d\n", (gint) 
ic->status->u.appenduid.uidvalidity, (gint) ic->status->u.appenduid.uid);
+                       if (ic->status->u.appenduid.uidvalidity == uidvalidity) {
+                               if (appended_uid)
+                                       *appended_uid = g_strdup_printf ("%u", (guint) 
ic->status->u.appenduid.uid);
+                               mi->uid = camel_pstring_add (g_strdup_printf ("%u", (guint) 
ic->status->u.appenduid.uid), TRUE);
+
+                               cur = camel_data_cache_get_filename  (imapx_folder->cache, "cur", mi->uid);
+                               if (g_rename (path, cur) == -1 && errno != ENOENT) {
+                                       g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC, path, 
cur, g_strerror (errno));
+                               }
+
+                               imapx_set_message_info_flags_for_new_message (
+                                       mi,
+                                       ((CamelMessageInfoBase *) info)->flags,
+                                       ((CamelMessageInfoBase *) info)->user_flags,
+                                       TRUE,
+                                       ((CamelMessageInfoBase *) info)->user_tags,
+                                       camel_imapx_mailbox_get_permanentflags (mailbox));
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+                               camel_folder_summary_add (folder->summary, mi);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) append_message_data_free);
+                               camel_folder_change_info_add_uid (is->priv->changes, mi->uid);
 
-       success = imapx_submit_job (is, job, error);
+                               mi = NULL;
 
-       if (appended_uid != NULL) {
-               *appended_uid = data->appended_uid;
-               data->appended_uid = NULL;
+                               g_free (cur);
+                       } else {
+                               c (is->priv->tagprefix, "but uidvalidity changed \n");
+                       }
+               }
+
+               camel_data_cache_remove (imapx_folder->cache, "new", old_uid, NULL);
+               g_free (old_uid);
+
+               camel_imapx_command_unref (ic);
+               if (mi)
+                       camel_message_info_unref (mi);
+               g_object_unref (folder);
        }
 
-       camel_imapx_job_unref (job);
+       g_free (path);
 
        return success;
 }
 
 gboolean
-camel_imapx_server_noop (CamelIMAPXServer *is,
-                         CamelIMAPXMailbox *mailbox,
-                         GCancellable *cancellable,
-                         GError **error)
+camel_imapx_server_noop_sync (CamelIMAPXServer *is,
+                             CamelIMAPXMailbox *mailbox,
+                             GCancellable *cancellable,
+                             GError **error)
 {
-       CamelIMAPXJob *job;
-       gboolean success;
+       gboolean success = TRUE;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        /* Mailbox may be NULL. */
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_NOOP;
-       job->start = imapx_job_noop_start;
-       job->pri = IMAPX_PRIORITY_NOOP;
+       if (mailbox)
+               success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+       if (success) {
+               CamelIMAPXCommand *ic;
 
-       success = imapx_submit_job (is, job, error);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_NOOP, "NOOP");
 
-       camel_imapx_job_unref (job);
+               success = camel_imapx_server_process_command_sync (is, ic, _("Error performing NOOP"), 
cancellable, error);
+
+               camel_imapx_command_unref (ic);
+       }
 
        return success;
 }
 
-CamelFolderChangeInfo *
-camel_imapx_server_refresh_info (CamelIMAPXServer *is,
-                                 CamelIMAPXMailbox *mailbox,
-                                 GCancellable *cancellable,
-                                 GError **error)
+/* ********************************************************************** */
+
+static gint
+imapx_refresh_info_uid_cmp (gconstpointer ap,
+                            gconstpointer bp,
+                            gboolean ascending)
 {
-       CamelIMAPXJob *job;
-       RefreshInfoData *data;
-       CamelFolderChangeInfo *changes = NULL;
-       gboolean registered = TRUE;
-       const gchar *mailbox_name;
+       guint av, bv;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
-       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
+       av = g_ascii_strtoull ((const gchar *) ap, NULL, 10);
+       bv = g_ascii_strtoull ((const gchar *) bp, NULL, 10);
+
+       if (av < bv)
+               return ascending ? -1 : 1;
+       else if (av > bv)
+               return ascending ? 1 : -1;
+       else
+               return 0;
+}
+
+static gint
+imapx_uids_array_cmp (gconstpointer ap,
+                      gconstpointer bp)
+{
+       const gchar **a = (const gchar **) ap;
+       const gchar **b = (const gchar **) bp;
+
+       return imapx_refresh_info_uid_cmp (*a, *b, TRUE);
+}
+
+static gint
+imapx_uids_desc_cmp (gconstpointer ap,
+                    gconstpointer bp)
+{
+       const gchar *a = (const gchar *) ap;
+       const gchar *b = (const gchar *) bp;
+
+       return imapx_refresh_info_uid_cmp (a, b, FALSE);
+}
+
+static void
+imapx_server_process_fetch_changes_infos (CamelIMAPXServer *is,
+                                         CamelIMAPXMailbox *mailbox,
+                                         CamelFolder *folder,
+                                         GHashTable *infos,
+                                         GHashTable *known_uids,
+                                         GSList **out_fetch_summary_uids,
+                                         guint64 from_uidl,
+                                         guint64 to_uidl)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+       CamelFolderSummary *summary;
+
+       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+       g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+       g_return_if_fail (infos != NULL);
+
+       if (out_fetch_summary_uids)
+               g_return_if_fail (*out_fetch_summary_uids == NULL);
+
+       summary = folder->summary;
 
-       /* Don't run concurrent refreshes on the same mailbox.
-        * If a refresh is already in progress, let it finish
-        * and return no changes for this refresh request. */
-       job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_REFRESH_INFO, NULL);
+       g_hash_table_iter_init (&iter, infos);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               const gchar *uid = key;
+               FetchChangesInfo *nfo = value;
+               CamelMessageInfo *minfo;
 
-       if (job != NULL) {
-               camel_imapx_job_unref (job);
-               return camel_folder_change_info_new ();
+               if (!uid || !nfo)
+                       continue;
+
+               if (known_uids)
+                       g_hash_table_insert (known_uids, (gpointer) camel_pstring_strdup (uid), 
GINT_TO_POINTER (1));
+
+               if (!camel_folder_summary_check_uid (summary, uid) ||
+                   !(minfo = camel_folder_summary_get (summary, uid))) {
+                       if (out_fetch_summary_uids) {
+                               *out_fetch_summary_uids = g_slist_prepend (*out_fetch_summary_uids,
+                                       (gpointer) camel_pstring_strdup (uid));
+                       }
+
+                       continue;
+               }
+
+               if (imapx_update_message_info_flags (
+                       minfo,
+                       nfo->server_flags,
+                       nfo->server_user_flags,
+                       camel_imapx_mailbox_get_permanentflags (mailbox),
+                       folder, FALSE)) {
+                       camel_folder_change_info_change_uid (is->priv->changes, camel_message_info_uid 
(minfo));
+               }
+
+               camel_message_info_unref (minfo);
        }
+}
 
-       if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
-               return NULL;
+static gboolean
+imapx_server_fetch_changes (CamelIMAPXServer *is,
+                           CamelIMAPXMailbox *mailbox,
+                           CamelFolder *folder,
+                           GHashTable *known_uids,
+                           guint64 from_uidl,
+                           guint64 to_uidl,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+       GSList *fetch_summary_uids = NULL;
+       GHashTable *infos; /* uid ~> FetchChangesInfo */
+       CamelIMAPXCommand *ic;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
 
-       /* Wait for any SyncChanges jobs to finish before running the refresh */
-       while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL), job != NULL) {
-               /* Promote the existing job's priority if ours is higher. */
-               if (IMAPX_PRIORITY_REFRESH_INFO > job->pri)
-                       job->pri = IMAPX_PRIORITY_REFRESH_INFO;
+       if (!from_uidl)
+               from_uidl = 1;
 
-               /* Wait for the job to finish. */
-               camel_imapx_job_wait (job, NULL);
-               camel_imapx_job_unref (job);
+       if (to_uidl > 0) {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:%lld (UID 
FLAGS)", from_uidl, to_uidl);
+       } else {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH %lld:* (UID 
FLAGS)", from_uidl);
        }
 
-       QUEUE_LOCK (is);
+       g_return_val_if_fail (is->priv->fetch_changes_mailbox == NULL, FALSE);
+       g_return_val_if_fail (is->priv->fetch_changes_folder == NULL, FALSE);
+       g_return_val_if_fail (is->priv->fetch_changes_infos == NULL, FALSE);
 
-       data = g_slice_new0 (RefreshInfoData);
-       data->changes = camel_folder_change_info_new ();
+       infos = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, 
fetch_changes_info_free);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_REFRESH_INFO;
-       job->start = imapx_job_refresh_info_start;
-       job->matches = imapx_job_refresh_info_matches;
-       job->pri = IMAPX_PRIORITY_REFRESH_INFO;
+       is->priv->fetch_changes_mailbox = mailbox;
+       is->priv->fetch_changes_folder = folder;
+       is->priv->fetch_changes_infos = infos;
+       is->priv->fetch_changes_last_progress = 0;
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+       camel_operation_push_message (cancellable,
+               _("Scanning for changed messages in '%s'"),
+               camel_folder_get_display_name (folder));
 
-       mailbox_name = camel_imapx_mailbox_get_name (mailbox);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error scanning changes"), cancellable, 
error);
 
-       if (camel_imapx_mailbox_is_inbox (mailbox_name))
-               job->pri += 10;
+       camel_operation_pop_message (cancellable);
+       camel_imapx_command_unref (ic);
+
+       /* It can partly succeed. */
+       imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, known_uids, 
&fetch_summary_uids, from_uidl, to_uidl);
+
+       g_hash_table_remove_all (infos);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) refresh_info_data_free);
+       if (success && fetch_summary_uids) {
+               struct _uidset_state uidset;
+               GSList *link;
 
-       registered = imapx_register_job (is, job, error);
+               ic = NULL;
+               imapx_uidset_init (&uidset, 0, 100);
+
+               camel_operation_push_message (cancellable,
+                       _("Fetching summary information for new messages in '%s'"),
+                       camel_folder_get_display_name (folder));
+
+               fetch_summary_uids = g_slist_sort (fetch_summary_uids, imapx_uids_desc_cmp);
+
+               for (link = fetch_summary_uids; link; link = g_slist_next (link)) {
+                       const gchar *uid = link->data;
+
+                       if (!uid)
+                               continue;
+
+                       if (!ic)
+                               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_REFRESH_INFO, "UID FETCH ");
+
+                       if (imapx_uidset_add (&uidset, ic, uid) == 1 || (!link->next && ic && 
imapx_uidset_done (&uidset, ic))) {
+                               camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER FLAGS)");
+
+                               success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching 
message info"), cancellable, error);
+
+                               camel_imapx_command_unref (ic);
+                               ic = NULL;
+
+                               if (!success)
+                                       break;
+
+                               imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL, 
NULL, 0, 0);
+                               g_hash_table_remove_all (infos);
+                       }
+               }
 
-       QUEUE_UNLOCK (is);
+               camel_operation_pop_message (cancellable);
 
-       if (registered) {
-               camel_imapx_mailbox_inc_update_count (mailbox, 1);
-               camel_imapx_job_inc_update_locked (job, mailbox);
+               imapx_server_process_fetch_changes_infos (is, mailbox, folder, infos, NULL, NULL, 0, 0);
        }
 
-       if (registered && camel_imapx_job_run (job, is, error)) {
-               changes = data->changes;
-               data->changes = NULL;
-       } else if (registered) {
-               imapx_unregister_job (is, job);
+       g_return_val_if_fail (is->priv->fetch_changes_mailbox == mailbox, FALSE);
+       g_return_val_if_fail (is->priv->fetch_changes_folder == folder, FALSE);
+       g_return_val_if_fail (is->priv->fetch_changes_infos == infos, FALSE);
+
+       is->priv->fetch_changes_mailbox = NULL;
+       is->priv->fetch_changes_folder = NULL;
+       is->priv->fetch_changes_infos = NULL;
+
+       g_slist_free_full (fetch_summary_uids, (GDestroyNotify) camel_pstring_free);
+       g_hash_table_destroy (infos);
+
+       return success;
+}
+
+gboolean
+camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
+                                     CamelIMAPXMailbox *mailbox,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       CamelIMAPXCommand *ic;
+       CamelIMAPXMailbox *selected_mailbox;
+       CamelIMAPXSummary *imapx_summary;
+       CamelFolder *folder;
+       GHashTable *known_uids;
+       guint32 messages;
+       guint32 unseen;
+       guint32 uidnext;
+       guint32 uidvalidity;
+       guint64 highestmodseq;
+       guint32 total;
+       guint64 uidl;
+       gboolean need_rescan;
+       gboolean success;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
+
+       selected_mailbox = camel_imapx_server_ref_pending_or_selected (is);
+       if (selected_mailbox == mailbox) {
+               success = camel_imapx_server_noop_sync (is, mailbox, cancellable, error);
+       } else {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_STATUS, "STATUS %M (%t)", mailbox, 
is->priv->status_data_items);
+
+               success = camel_imapx_server_process_command_sync (is, ic, _("Error running STATUS"), 
cancellable, error);
+
+               camel_imapx_command_unref (ic);
        }
+       g_clear_object (&selected_mailbox);
 
-       camel_imapx_job_unref (job);
+       if (!success)
+               return FALSE;
 
-       return changes;
+       folder = imapx_server_ref_folder (is, mailbox);
+       g_return_val_if_fail (folder != NULL, FALSE);
+
+       imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+
+       messages = camel_imapx_mailbox_get_messages (mailbox);
+       unseen = camel_imapx_mailbox_get_unseen (mailbox);
+       uidnext = camel_imapx_mailbox_get_uidnext (mailbox);
+       uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
+       highestmodseq = camel_imapx_mailbox_get_highestmodseq (mailbox);
+       total = camel_folder_summary_count (folder->summary);
+
+       need_rescan =
+               (uidvalidity > 0 && uidvalidity != imapx_summary->validity) ||
+               total != messages ||
+               imapx_summary->uidnext != uidnext ||
+               camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+               imapx_summary->modseq != highestmodseq;
+
+       if (!need_rescan) {
+               g_object_unref (folder);
+               return TRUE;
+       }
+
+       if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+               g_object_unref (folder);
+               return FALSE;
+       }
+
+       if (is->priv->use_qresync && imapx_summary->modseq > 0 && uidvalidity > 0) {
+               imapx_summary->modseq = highestmodseq;
+               if (total != messages ||
+                   camel_folder_summary_get_unread_count (folder->summary) != unseen ||
+                   imapx_summary->modseq != highestmodseq) {
+                       c (
+                               is->priv->tagprefix,
+                               "Eep, after QRESYNC we're out of sync. "
+                               "total %u / %u, unread %u / %u, modseq %"
+                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+                               total, messages,
+                               camel_folder_summary_get_unread_count (folder->summary),
+                               unseen,
+                               imapx_summary->modseq,
+                               highestmodseq);
+               } else {
+                       c (
+                               is->priv->tagprefix,
+                               "OK, after QRESYNC we're still in sync. "
+                               "total %u / %u, unread %u / %u, modseq %"
+                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+                               total, messages,
+                               camel_folder_summary_get_unread_count (folder->summary),
+                               unseen,
+                               imapx_summary->modseq,
+                               highestmodseq);
+                       g_object_unref (folder);
+                       return TRUE;
+               }
+       }
+
+       if (total > 0) {
+               gchar *uid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
+               if (uid) {
+                       uidl = g_ascii_strtoull (uid, NULL, 10);
+                       g_free (uid);
+                       uidl++;
+               } else {
+                       uidl = 1;
+               }
+       } else {
+               uidl = 1;
+       }
+
+       known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, 
NULL);
+
+       success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, uidl, 0, cancellable, error);
+       if (success && uidl != 1)
+               success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, 0, uidl, cancellable, 
error);
+
+       if (success && g_hash_table_size (known_uids) > 0) {
+               CamelFolderChangeInfo *changes;
+               GList *removed = NULL;
+               GPtrArray *array;
+               gint ii;
+
+               camel_folder_summary_lock (folder->summary);
+
+               changes = camel_folder_change_info_new ();
+
+               array = camel_folder_summary_get_array (folder->summary);
+               for (ii = 0; array && ii < array->len; ii++) {
+                       const gchar *uid = array->pdata[ii];
+
+                       if (!uid)
+                               continue;
+
+                       if (!g_hash_table_contains (known_uids, uid)) {
+                               removed = g_list_prepend (removed, (gpointer) uid);
+                               camel_folder_change_info_remove_uid (changes, uid);
+                       }
+               }
+
+               camel_folder_summary_unlock (folder->summary);
+
+               if (removed != NULL) {
+                       camel_folder_summary_remove_uids (folder->summary, removed);
+                       camel_folder_summary_touch (folder->summary);
+
+                       /* Shares UIDs with the 'array'. */
+                       g_list_free (removed);
+               }
+
+               if (camel_folder_change_info_changed (changes)) {
+                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                       imapx_update_store_summary (folder);
+                       camel_folder_changed (folder, changes);
+               }
+
+               camel_folder_change_info_free (changes);
+               camel_folder_summary_free_array (array);
+       }
+
+       g_hash_table_destroy (known_uids);
+       g_object_unref (folder);
+
+       return success;
 }
 
 static void
@@ -9040,35 +4976,30 @@ imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
 }
 
 static gboolean
-imapx_server_sync_changes (CamelIMAPXServer *is,
-                           CamelIMAPXMailbox *mailbox,
-                           guint32 job_type,
-                           gint pri,
-                           GCancellable *cancellable,
-                           GError **error)
+imapx_server_sync_changes_sync (CamelIMAPXServer *is,
+                               CamelIMAPXMailbox *mailbox,
+                               gboolean is_expunge,
+                               GCancellable *cancellable,
+                               GError **error)
 {
-       guint i, on_orset, off_orset;
+       guint i, jj, on, on_orset, off_orset;
        GPtrArray *changed_uids;
        GArray *on_user = NULL, *off_user = NULL;
        CamelFolder *folder;
        CamelIMAPXMessageInfo *info;
-       CamelIMAPXJob *job;
        CamelIMAPXSettings *settings;
-       SyncChangesData *data;
+       guint32 permanentflags;
+       struct _uidset_state uidset;
+       gint unread_change = 0;
        gboolean use_real_junk_path;
        gboolean use_real_trash_path;
        gboolean remove_deleted_flags;
        gboolean nothing_to_do;
-       gboolean registered;
-       gboolean own_allocated_changed_uids = FALSE;
-       gboolean success = TRUE;
+       gboolean success;
 
        folder = imapx_server_ref_folder (is, mailbox);
        g_return_val_if_fail (folder != NULL, FALSE);
 
-       if (!imapx_ensure_mailbox_permanentflags (is, mailbox, cancellable, error))
-               return FALSE;
-
        /* We calculate two masks, a mask of all flags which have been
         * turned off and a mask of all flags which have been turned
         * on. If either of these aren't 0, then we have work to do,
@@ -9088,13 +5019,11 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
        }
 
        settings = camel_imapx_server_ref_settings (is);
-       use_real_junk_path =
-               camel_imapx_settings_get_use_real_junk_path (settings);
-       use_real_trash_path =
-               camel_imapx_settings_get_use_real_trash_path (settings);
+       use_real_junk_path = camel_imapx_settings_get_use_real_junk_path (settings);
+       use_real_trash_path = camel_imapx_settings_get_use_real_trash_path (settings);
        g_object_unref (settings);
 
-       remove_deleted_flags = use_real_trash_path && job_type != IMAPX_JOB_EXPUNGE;
+       remove_deleted_flags = use_real_trash_path && is_expunge;
 
        off_orset = on_orset = 0;
        for (i = 0; i < changed_uids->len; i++) {
@@ -9216,245 +5145,340 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
                return TRUE;
        }
 
-       /* TODO above code should go into changes_start */
+       if (!camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error)) {
+               imapx_sync_free_user (on_user);
+               imapx_sync_free_user (off_user);
+               imapx_unset_folder_flagged_flag (folder->summary, changed_uids, remove_deleted_flags);
+               camel_folder_free_uids (folder, changed_uids);
+               g_object_unref (folder);
+               return FALSE;
+       }
 
-       job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_SYNC_CHANGES, NULL);
+       permanentflags = camel_imapx_mailbox_get_permanentflags (mailbox);
 
-       if (job != NULL) {
-               GPtrArray *new_changed_uids;
-               GHashTable *known_uids;
-               GHashTableIter iter;
-               gpointer key, value;
-               gint ii;
+       success = TRUE;
+       for (on = 0; on < 2 && success; on++) {
+               guint32 orset = on ? on_orset : off_orset;
+               GArray *user_set = on ? on_user : off_user;
 
-               known_uids = g_hash_table_new (g_str_hash, g_str_equal);
-               data = camel_imapx_job_get_data (job);
+               for (jj = 0; jj < G_N_ELEMENTS (flags_table) && success; jj++) {
+                       guint32 flag = flags_table[jj].flag;
+                       CamelIMAPXCommand *ic = NULL;
 
-               if (data && data->changed_uids) {
-                       for (ii = 0; ii < changed_uids->len; ii++) {
-                               g_hash_table_insert (known_uids, changed_uids->pdata[ii], GINT_TO_POINTER 
(1));
-                       }
+                       if ((orset & flag) == 0)
+                               continue;
 
-                       for (ii = 0; ii < data->changed_uids->len; ii++) {
-                               g_hash_table_remove (known_uids, data->changed_uids->pdata[ii]);
-                       }
-               }
+                       c (is->priv->tagprefix, "checking/storing %s flags '%s'\n", on ? "on" : "off", 
flags_table[jj].name);
+                       imapx_uidset_init (&uidset, 0, 100);
+                       for (i = 0; i < changed_uids->len && success; i++) {
+                               CamelIMAPXMessageInfo *info;
+                               gboolean remove_deleted_flag;
+                               guint32 flags;
+                               guint32 sflags;
+                               gint send;
 
-               if (g_hash_table_size (known_uids) == 0) {
-                       /* The pending job stores changes for the same UIDs */
-                       if (pri > job->pri)
-                               job->pri = pri;
+                               info = (CamelIMAPXMessageInfo *)
+                                       camel_folder_summary_get (
+                                               folder->summary,
+                                               changed_uids->pdata[i]);
 
-                       camel_imapx_job_unref (job);
+                               if (info == NULL)
+                                       continue;
 
-                       imapx_sync_free_user (on_user);
-                       imapx_sync_free_user (off_user);
-                       camel_folder_free_uids (folder, changed_uids);
-                       g_object_unref (folder);
-                       g_hash_table_destroy (known_uids);
-                       return TRUE;
-               }
+                               flags = (info->info.flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+                               sflags = (info->server_flags & CAMEL_IMAPX_SERVER_FLAGS) & permanentflags;
+                               send = 0;
+
+                               remove_deleted_flag =
+                                       remove_deleted_flags &&
+                                       (flags & CAMEL_MESSAGE_DELETED);
+
+                               if (remove_deleted_flag) {
+                                       /* Remove the DELETED flag so the
+                                        * message appears normally in the
+                                        * real Trash folder when copied. */
+                                       flags &= ~CAMEL_MESSAGE_DELETED;
+                               }
+
+                               if ( (on && (((flags ^ sflags) & flags) & flag))
+                                    || (!on && (((flags ^ sflags) & ~flags) & flag))) {
+                                       if (ic == NULL) {
+                                               ic = camel_imapx_command_new (is, 
CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
+                                       }
+                                       send = imapx_uidset_add (&uidset, ic, camel_message_info_uid (info));
+                               }
+                               if (send == 1 || (i == changed_uids->len - 1 && ic && imapx_uidset_done 
(&uidset, ic))) {
+                                       camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+" : "-", 
flags_table[jj].name);
+
+                                       success = camel_imapx_server_process_command_sync (is, ic, _("Error 
syncing changes"), cancellable, error);
+
+                                       camel_imapx_command_unref (ic);
+                                       ic = NULL;
 
-               new_changed_uids = g_ptr_array_sized_new (g_hash_table_size (known_uids));
+                                       if (!success)
+                                               break;
+                               }
+                               if (flag == CAMEL_MESSAGE_SEEN) {
+                                       /* Remember how the server's unread count will change if this
+                                        * command succeeds */
+                                       if (on)
+                                               unread_change--;
+                                       else
+                                               unread_change++;
+                               }
 
-               /* What left in known_uids are message info changes which are not being
-                  saved in the pending job */
+                               /* The second round and the server doesn't support saving user flags,
+                                  thus store them at least locally */
+                               if (on && (permanentflags & CAMEL_MESSAGE_USER) == 0) {
+                                       camel_flag_list_copy (&info->server_user_flags, 
&info->info.user_flags);
+                               }
 
-               g_hash_table_iter_init (&iter, known_uids);
-               while (g_hash_table_iter_next (&iter, &key, &value)) {
-                       g_ptr_array_add (new_changed_uids, (gpointer) camel_pstring_strdup (key));
+                               camel_message_info_unref (info);
+                       }
+
+                       g_warn_if_fail (ic == NULL);
                }
 
-               g_hash_table_destroy (known_uids);
+               if (user_set && (permanentflags & CAMEL_MESSAGE_USER) != 0) {
+                       CamelIMAPXCommand *ic = NULL;
 
-               camel_folder_free_uids (folder, changed_uids);
-               changed_uids = new_changed_uids;
+                       for (jj = 0; jj < user_set->len; jj++) {
+                               struct _imapx_flag_change *c = &g_array_index (user_set, struct 
_imapx_flag_change, jj);
 
-               /* Why would anyone define a virtual function for the free on the folder? */
-               own_allocated_changed_uids = TRUE;
-       }
+                               imapx_uidset_init (&uidset, 0, 100);
+                               for (i = 0; i < c->infos->len; i++) {
+                                       CamelIMAPXMessageInfo *info = c->infos->pdata[i];
+
+                                       if (ic == NULL)
+                                               ic = camel_imapx_command_new (is, 
CAMEL_IMAPX_JOB_SYNC_CHANGES, "UID STORE ");
 
-       if (job_type == IMAPX_JOB_SYNC_CHANGES) {
-               /* Wait for any RefreshInfo jobs to finish before running the sync */
-               while (job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_REFRESH_INFO, NULL), job != NULL) {
-                       /* Promote the existing job's priority if ours is higher. */
-                       if (pri > job->pri)
-                               job->pri = pri;
+                                       if (imapx_uidset_add (&uidset, ic, camel_message_info_uid (info)) == 1
+                                           || (i == c->infos->len - 1 && imapx_uidset_done (&uidset, ic))) {
+                                               camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on ? "+" 
: "-", c->name);
 
-                       /* Wait for the job to finish. */
-                       camel_imapx_job_wait (job, NULL);
-                       camel_imapx_job_unref (job);
+                                               success = camel_imapx_server_process_command_sync (is, ic, 
_("Error syncing changes"), cancellable, error);
+
+                                               camel_imapx_command_unref (ic);
+                                               ic = NULL;
+
+                                               if (!success)
+                                                       break;
+                                       }
+                               }
+                       }
                }
        }
 
-       QUEUE_LOCK (is);
+       if (success) {
+               CamelStore *parent_store;
+               guint32 unseen;
 
-       data = g_slice_new0 (SyncChangesData);
-       data->folder = g_object_ref (folder);
-       data->changed_uids = changed_uids;  /* takes ownership */
-       data->own_allocated_changed_uids = own_allocated_changed_uids;
-       data->on_set = on_orset;
-       data->off_set = off_orset;
-       data->on_user = on_user;  /* takes ownership */
-       data->off_user = off_user;  /* takes ownership */
-       data->remove_deleted_flags = remove_deleted_flags;
+               parent_store = camel_folder_get_parent_store (folder);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_SYNC_CHANGES;
-       job->start = imapx_job_sync_changes_start;
-       job->matches = imapx_job_sync_changes_matches;
-       job->pri = pri;
+               for (i = 0; i < changed_uids->len; i++) {
+                       CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get 
(folder->summary,
+                                       changed_uids->pdata[i]);
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+                       if (!xinfo)
+                               continue;
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) sync_changes_data_free);
+                       xinfo->server_flags = xinfo->info.flags & CAMEL_IMAPX_SERVER_FLAGS;
+                       if (!remove_deleted_flags ||
+                           !(xinfo->info.flags & CAMEL_MESSAGE_DELETED)) {
+                               xinfo->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+                       } else {
+                               /* to stare back the \Deleted flag */
+                               xinfo->server_flags &= ~CAMEL_MESSAGE_DELETED;
+                               xinfo->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+                       }
+                       xinfo->info.dirty = TRUE;
+                       if ((permanentflags & CAMEL_MESSAGE_USER) != 0 ||
+                           camel_flag_list_size (&xinfo->server_user_flags) == 0)
+                               camel_flag_list_copy (&xinfo->server_user_flags, &xinfo->info.user_flags);
 
-       registered = imapx_register_job (is, job, error);
+                       camel_folder_summary_touch (folder->summary);
+                       camel_message_info_unref (xinfo);
+               }
 
-       QUEUE_UNLOCK (is);
+               /* Apply the changes to server-side unread count; it won't tell
+                * us of these changes, of course. */
+               unseen = camel_imapx_mailbox_get_unseen (mailbox);
+               unseen += unread_change;
+               camel_imapx_mailbox_set_unseen (mailbox, unseen);
 
-       if (job_type == IMAPX_JOB_SYNC_CHANGES && registered) {
-               camel_imapx_mailbox_inc_update_count (mailbox, 1);
-               camel_imapx_job_inc_update_locked (job, mailbox);
-       }
+               if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
+                       CamelStoreInfo *si;
 
-       success = registered && camel_imapx_job_run (job, is, error);
+                       /* ... and store's summary when folder's summary is dirty */
+                       si = camel_store_summary_path (CAMEL_IMAPX_STORE (parent_store)->summary, 
camel_folder_get_full_name (folder));
+                       if (si) {
+                               if (si->total != camel_folder_summary_get_saved_count (folder->summary) ||
+                                   si->unread != camel_folder_summary_get_unread_count (folder->summary)) {
+                                       si->total = camel_folder_summary_get_saved_count (folder->summary);
+                                       si->unread = camel_folder_summary_get_unread_count (folder->summary);
+                                       camel_store_summary_touch (CAMEL_IMAPX_STORE (parent_store)->summary);
+                               }
 
-       if (!success && registered)
-               imapx_unregister_job (is, job);
+                               camel_store_summary_info_unref (CAMEL_IMAPX_STORE (parent_store)->summary, 
si);
+                       }
+               }
 
-       camel_imapx_job_unref (job);
+               camel_folder_summary_save_to_db (folder->summary, NULL);
+               camel_store_summary_save (CAMEL_IMAPX_STORE (parent_store)->summary);
+       }
 
+       imapx_sync_free_user (on_user);
+       imapx_sync_free_user (off_user);
+       camel_folder_free_uids (folder, changed_uids);
        g_object_unref (folder);
 
        return success;
 }
 
 gboolean
-camel_imapx_server_sync_changes (CamelIMAPXServer *is,
-                                 CamelIMAPXMailbox *mailbox,
-                                 GCancellable *cancellable,
-                                 GError **error)
+camel_imapx_server_sync_changes_sync (CamelIMAPXServer *is,
+                                     CamelIMAPXMailbox *mailbox,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       return imapx_server_sync_changes (
-               is, mailbox,
-               IMAPX_JOB_SYNC_CHANGES,
-               IMAPX_PRIORITY_SYNC_CHANGES,
-               cancellable, error);
+       return imapx_server_sync_changes_sync (is, mailbox, FALSE, cancellable, error);
 }
 
 /* expunge-uids? */
 gboolean
-camel_imapx_server_expunge (CamelIMAPXServer *is,
-                            CamelIMAPXMailbox *mailbox,
-                            GCancellable *cancellable,
-                            GError **error)
+camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
+                                CamelIMAPXMailbox *mailbox,
+                                GCancellable *cancellable,
+                                GError **error)
 {
-       CamelIMAPXJob *job;
-       gboolean registered;
+       CamelFolder *folder;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       /* Do we really care to wait for this one to finish? */
-       job = imapx_server_ref_job (is, mailbox, IMAPX_JOB_EXPUNGE, NULL);
+       folder = imapx_server_ref_folder (is, mailbox);
+       g_return_val_if_fail (folder != NULL, FALSE);
 
-       if (job != NULL) {
-               camel_imapx_job_unref (job);
-               return TRUE;
-       }
+       success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
 
-       QUEUE_LOCK (is);
+       if (success)
+               success = imapx_server_sync_changes_sync (is, mailbox, TRUE, cancellable, error);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_EXPUNGE;
-       job->start = imapx_job_expunge_start;
-       job->matches = imapx_job_expunge_matches;
-       job->pri = IMAPX_PRIORITY_EXPUNGE;
+       if (success) {
+               CamelIMAPXCommand *ic;
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_EXPUNGE, "EXPUNGE");
 
-       registered = imapx_register_job (is, job, error);
+               success = camel_imapx_server_process_command_sync (is, ic, _("Error expunging message"), 
cancellable, error);
+               if (success) {
+                       GPtrArray *uids;
+                       CamelStore *parent_store;
+                       const gchar *full_name;
 
-       QUEUE_UNLOCK (is);
+                       full_name = camel_folder_get_full_name (folder);
+                       parent_store = camel_folder_get_parent_store (folder);
 
-       success = registered && camel_imapx_job_run (job, is, error);
+                       camel_folder_summary_lock (folder->summary);
 
-       if (!success && registered)
-               imapx_unregister_job (is, job);
+                       camel_folder_summary_save_to_db (folder->summary, NULL);
+                       uids = camel_db_get_folder_deleted_uids (parent_store->cdb_r, full_name, NULL);
+
+                       if (uids && uids->len) {
+                               CamelFolderChangeInfo *changes;
+                               GList *removed = NULL;
+                               gint i;
 
-       camel_imapx_job_unref (job);
+                               changes = camel_folder_change_info_new ();
+                               for (i = 0; i < uids->len; i++) {
+                                       camel_folder_change_info_remove_uid (changes, uids->pdata[i]);
+                                       removed = g_list_prepend (removed, (gpointer) uids->pdata[i]);
+                               }
+
+                               camel_folder_summary_remove_uids (folder->summary, removed);
+                               camel_folder_summary_save_to_db (folder->summary, NULL);
+
+                               camel_folder_changed (folder, changes);
+                               camel_folder_change_info_free (changes);
+
+                               g_list_free (removed);
+                               g_ptr_array_foreach (uids, (GFunc) camel_pstring_free, NULL);
+                       }
+
+                       if (uids)
+                               g_ptr_array_free (uids, TRUE);
+
+                       camel_folder_summary_unlock (folder->summary);
+               }
+
+               camel_imapx_command_unref (ic);
+       }
+
+       g_clear_object (&folder);
 
        return success;
 }
 
 gboolean
-camel_imapx_server_list (CamelIMAPXServer *is,
-                         const gchar *pattern,
-                         CamelStoreGetFolderInfoFlags flags,
-                         GCancellable *cancellable,
-                         GError **error)
+camel_imapx_server_list_sync (CamelIMAPXServer *is,
+                             const gchar *pattern,
+                             CamelStoreGetFolderInfoFlags flags,
+                             GCancellable *cancellable,
+                             GError **error)
 {
-       CamelIMAPXJob *job;
-       ListData *data;
+       CamelIMAPXCommand *ic;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (pattern != NULL, FALSE);
 
-       data = g_slice_new0 (ListData);
-       data->pattern = g_strdup (pattern);
+       if (is->priv->list_return_opts != NULL) {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s RETURN (%t)",
+                       pattern, is->priv->list_return_opts);
+       } else {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LIST, "LIST \"\" %s",
+                       pattern);
+       }
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_LIST;
-       job->start = imapx_job_list_start;
-       job->matches = imapx_job_list_matches;
-       job->pri = IMAPX_PRIORITY_LIST;
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching folders"), cancellable, 
error);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) list_data_free);
+       camel_imapx_command_unref (ic);
+
+       if (!success)
+               return FALSE;
 
-       /* sync operation which is triggered by user */
-       if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
-               job->pri += 300;
+       if (!is->priv->list_return_opts) {
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_LSUB, "LSUB \"\" %s",
+                       pattern);
 
-       success = imapx_submit_job (is, job, error);
+               success = camel_imapx_server_process_command_sync (is, ic, _("Error fetching subscribed 
folders"), cancellable, error);
 
-       camel_imapx_job_unref (job);
+               camel_imapx_command_unref (ic);
+       }
 
        return success;
 }
 
 gboolean
-camel_imapx_server_create_mailbox (CamelIMAPXServer *is,
-                                   const gchar *mailbox_name,
-                                   GCancellable *cancellable,
-                                   GError **error)
+camel_imapx_server_create_mailbox_sync (CamelIMAPXServer *is,
+                                       const gchar *mailbox_name,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
-       CamelIMAPXJob *job;
-       MailboxData *data;
+       CamelIMAPXCommand *ic;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (mailbox_name != NULL, FALSE);
 
-       data = g_slice_new0 (MailboxData);
-       data->mailbox_name = g_strdup (mailbox_name);
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_CREATE_MAILBOX, "CREATE %m", mailbox_name);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_CREATE_MAILBOX;
-       job->start = imapx_job_create_mailbox_start;
-       job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error creating folder"), cancellable, 
error);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) mailbox_data_free);
-
-       success = imapx_submit_job (is, job, error);
+       camel_imapx_command_unref (ic);
 
        if (success) {
                gchar *utf7_pattern;
@@ -9465,25 +5489,23 @@ camel_imapx_server_create_mailbox (CamelIMAPXServer *is,
                 * LIST handler.  This simulates being notified of
                 * a newly-created mailbox, so we can just let the
                 * callback functions handle the bookkeeping. */
-               success = camel_imapx_server_list (
-                       is, utf7_pattern, 0, cancellable, error);
+               success = camel_imapx_server_list_sync (is, utf7_pattern, 0, cancellable, error);
 
                g_free (utf7_pattern);
        }
 
-       camel_imapx_job_unref (job);
-
        return success;
 }
 
 gboolean
-camel_imapx_server_delete_mailbox (CamelIMAPXServer *is,
-                                   CamelIMAPXMailbox *mailbox,
-                                   GCancellable *cancellable,
-                                   GError **error)
+camel_imapx_server_delete_mailbox_sync (CamelIMAPXServer *is,
+                                       CamelIMAPXMailbox *mailbox,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
-       CamelIMAPXJob *job;
-       MailboxData *data;
+       CamelIMAPXCommand *ic;
+       CamelIMAPXMailbox *inbox;
+       CamelIMAPXStore *imapx_store;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
@@ -9492,268 +5514,508 @@ camel_imapx_server_delete_mailbox (CamelIMAPXServer *is,
        /* Avoid camel_imapx_job_set_mailbox() here.  We
         * don't want to select the mailbox to be deleted. */
 
-       data = g_slice_new0 (MailboxData);
-       data->mailbox = g_object_ref (mailbox);
+       imapx_store = camel_imapx_server_ref_store (is);
+       /* Keep going, even if this returns NULL. */
+       inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
+
+       /* Make sure the to-be-deleted folder is not
+        * selected by selecting INBOX for this operation. */
+       success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+       if (!success) {
+               g_clear_object (&inbox);
+               g_clear_object (&imapx_store);
+               return FALSE;
+       }
+
+       /* Just to make sure it'll not disappeare before the end of this function */
+       g_object_ref (mailbox);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_DELETE_MAILBOX;
-       job->start = imapx_job_delete_mailbox_start;
-       job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_DELETE_MAILBOX, "DELETE %M", mailbox);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) mailbox_data_free);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error deleting folder"), cancellable, 
error);
 
-       success = imapx_submit_job (is, job, error);
+       camel_imapx_command_unref (ic);
 
-       camel_imapx_job_unref (job);
+       if (success) {
+               camel_imapx_mailbox_deleted (mailbox);
+               camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
+       }
+
+       g_clear_object (&inbox);
+       g_clear_object (&imapx_store);
+       g_clear_object (&mailbox);
 
        return success;
 }
 
 gboolean
-camel_imapx_server_rename_mailbox (CamelIMAPXServer *is,
-                                   CamelIMAPXMailbox *mailbox,
-                                   const gchar *new_mailbox_name,
-                                   GCancellable *cancellable,
-                                   GError **error)
+camel_imapx_server_rename_mailbox_sync (CamelIMAPXServer *is,
+                                       CamelIMAPXMailbox *mailbox,
+                                       const gchar *new_mailbox_name,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
-       CamelIMAPXJob *job;
-       MailboxData *data;
+       CamelIMAPXCommand *ic;
+       CamelIMAPXMailbox *inbox;
+       CamelIMAPXStore *imapx_store;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
        g_return_val_if_fail (new_mailbox_name != NULL, FALSE);
 
-       /* Avoid camel_imapx_job_set_mailbox() here.  We
-        * don't want to select the mailbox to be renamed. */
+       imapx_store = camel_imapx_server_ref_store (is);
+       inbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
+       g_return_val_if_fail (inbox != NULL, FALSE);
+
+       /* We don't want to select the mailbox to be renamed. */
+       success = camel_imapx_server_ensure_selected_sync (is, inbox, cancellable, error);
+       if (!success) {
+               g_clear_object (&inbox);
+               g_clear_object (&imapx_store);
+               return FALSE;
+       }
+
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_RENAME_MAILBOX, "RENAME %M %m", mailbox, 
new_mailbox_name);
 
-       data = g_slice_new0 (MailboxData);
-       data->mailbox = g_object_ref (mailbox);
-       data->mailbox_name = g_strdup (new_mailbox_name);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error renaming folder"), cancellable, 
error);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_RENAME_MAILBOX;
-       job->start = imapx_job_rename_mailbox_start;
-       job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+       camel_imapx_command_unref (ic);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) mailbox_data_free);
+       if (success) {
+               /* Perform the same processing as imapx_untagged_list()
+                * would if the server notified us of a renamed mailbox. */
 
-       success = imapx_submit_job (is, job, error);
+               camel_imapx_store_handle_mailbox_rename (imapx_store, mailbox, new_mailbox_name);
+       }
 
-       camel_imapx_job_unref (job);
+       g_clear_object (&inbox);
+       g_clear_object (&imapx_store);
 
        return success;
 }
 
 gboolean
-camel_imapx_server_subscribe_mailbox (CamelIMAPXServer *is,
-                                      CamelIMAPXMailbox *mailbox,
-                                      GCancellable *cancellable,
-                                      GError **error)
+camel_imapx_server_subscribe_mailbox_sync (CamelIMAPXServer *is,
+                                          CamelIMAPXMailbox *mailbox,
+                                          GCancellable *cancellable,
+                                          GError **error)
 {
-       CamelIMAPXJob *job;
-       MailboxData *data;
+       CamelIMAPXCommand *ic;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       /* Avoid camel_imapx_job_set_mailbox() here.  We
-        * don't want to select the mailbox to be subscribed. */
+       /* We don't want to select the mailbox to be subscribed. */
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_SUBSCRIBE_MAILBOX, "SUBSCRIBE %M", mailbox);
 
-       data = g_slice_new0 (MailboxData);
-       data->mailbox = g_object_ref (mailbox);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error subscribing to folder"), 
cancellable, error);
+
+       camel_imapx_command_unref (ic);
+
+       if (success) {
+               CamelIMAPXStore *imapx_store;
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_SUBSCRIBE_MAILBOX;
-       job->start = imapx_job_subscribe_mailbox_start;
-       job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+               /* Perform the same processing as imapx_untagged_list()
+                * would if the server notified us of a subscription. */
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) mailbox_data_free);
+               imapx_store = camel_imapx_server_ref_store (is);
 
-       success = imapx_submit_job (is, job, error);
+               camel_imapx_mailbox_subscribed (mailbox);
+               camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
 
-       camel_imapx_job_unref (job);
+               g_clear_object (&imapx_store);
+       }
 
        return success;
 }
 
 gboolean
-camel_imapx_server_unsubscribe_mailbox (CamelIMAPXServer *is,
-                                        CamelIMAPXMailbox *mailbox,
-                                        GCancellable *cancellable,
-                                        GError **error)
+camel_imapx_server_unsubscribe_mailbox_sync (CamelIMAPXServer *is,
+                                            CamelIMAPXMailbox *mailbox,
+                                            GCancellable *cancellable,
+                                            GError **error)
 {
-       CamelIMAPXJob *job;
-       MailboxData *data;
+       CamelIMAPXCommand *ic;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       /* Avoid camel_imapx_job_set_mailbox() here.  We
-        * don't want to select the mailbox to be unsubscribed. */
+       /* We don't want to select the mailbox to be unsubscribed. */
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UNSUBSCRIBE_MAILBOX, "UNSUBSCRIBE %M", mailbox);
 
-       data = g_slice_new0 (MailboxData);
-       data->mailbox = g_object_ref (mailbox);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error unsubscribing from folder"), 
cancellable, error);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_UNSUBSCRIBE_MAILBOX;
-       job->start = imapx_job_unsubscribe_mailbox_start;
-       job->pri = IMAPX_PRIORITY_MAILBOX_MGMT;
+       camel_imapx_command_unref (ic);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) mailbox_data_free);
+       if (success) {
+               CamelIMAPXStore *imapx_store;
 
-       success = imapx_submit_job (is, job, error);
+               /* Perform the same processing as imapx_untagged_list()
+                * would if the server notified us of an unsubscription. */
 
-       camel_imapx_job_unref (job);
+               imapx_store = camel_imapx_server_ref_store (is);
+
+               camel_imapx_mailbox_unsubscribed (mailbox);
+               camel_imapx_store_emit_mailbox_updated (imapx_store, mailbox);
+
+               g_clear_object (&imapx_store);
+       }
 
        return success;
 }
 
 gboolean
-camel_imapx_server_update_quota_info (CamelIMAPXServer *is,
-                                      CamelIMAPXMailbox *mailbox,
-                                      GCancellable *cancellable,
-                                      GError **error)
+camel_imapx_server_update_quota_info_sync (CamelIMAPXServer *is,
+                                          CamelIMAPXMailbox *mailbox,
+                                          GCancellable *cancellable,
+                                          GError **error)
 {
-       CamelIMAPXJob *job;
+       CamelIMAPXCommand *ic;
        gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       if (CAMEL_IMAPX_LACK_CAPABILITY (is->cinfo, QUOTA)) {
+       if (CAMEL_IMAPX_LACK_CAPABILITY (is->priv->cinfo, QUOTA)) {
                g_set_error_literal (
                        error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                        _("IMAP server does not support quotas"));
                return FALSE;
        }
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_UPDATE_QUOTA_INFO;
-       job->start = imapx_job_update_quota_info_start;
-       job->pri = IMAPX_PRIORITY_UPDATE_QUOTA_INFO;
+       success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+       if (!success)
+               return FALSE;
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UPDATE_QUOTA_INFO, "GETQUOTAROOT %M", mailbox);
 
-       success = imapx_submit_job (is, job, error);
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error retrieving quota information"), 
cancellable, error);
 
-       camel_imapx_job_unref (job);
+       camel_imapx_command_unref (ic);
 
        return success;
 }
 
 GPtrArray *
-camel_imapx_server_uid_search (CamelIMAPXServer *is,
-                               CamelIMAPXMailbox *mailbox,
-                               const gchar *criteria,
-                               GCancellable *cancellable,
-                               GError **error)
+camel_imapx_server_uid_search_sync (CamelIMAPXServer *is,
+                                   CamelIMAPXMailbox *mailbox,
+                                   const gchar *criteria,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
-       CamelIMAPXJob *job;
-       SearchData *data;
+       CamelIMAPXCommand *ic;
+       GArray *uid_search_results;
        GPtrArray *results = NULL;
+       gboolean success;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
        g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), NULL);
        g_return_val_if_fail (criteria != NULL, NULL);
 
-       data = g_slice_new0 (SearchData);
-       data->criteria = g_strdup (criteria);
+       success = camel_imapx_server_ensure_selected_sync (is, mailbox, cancellable, error);
+       if (!success)
+               return FALSE;
+
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_UID_SEARCH, "UID SEARCH %t", criteria);
 
-       job = camel_imapx_job_new (cancellable);
-       job->type = IMAPX_JOB_UID_SEARCH;
-       job->start = imapx_job_uid_search_start;
-       job->pri = IMAPX_PRIORITY_SEARCH;
+       success = camel_imapx_server_process_command_sync (is, ic, _("Search failed"), cancellable, error);
 
-       camel_imapx_job_set_mailbox (job, mailbox);
+       camel_imapx_command_unref (ic);
 
-       camel_imapx_job_set_data (
-               job, data, (GDestroyNotify) search_data_free);
+       g_mutex_lock (&is->priv->search_results_lock);
+       uid_search_results = is->priv->search_results;
+       is->priv->search_results = NULL;
+       g_mutex_unlock (&is->priv->search_results_lock);
 
-       if (imapx_submit_job (is, job, error)) {
+       if (success) {
                guint ii;
 
                /* Convert the numeric UIDs to strings. */
 
-               g_return_val_if_fail (data->results != NULL, NULL);
+               g_return_val_if_fail (uid_search_results != NULL, NULL);
 
-               results = g_ptr_array_new_full (
-                       data->results->len,
-                       (GDestroyNotify) camel_pstring_free);
+               results = g_ptr_array_new_full (uid_search_results->len, (GDestroyNotify) camel_pstring_free);
 
-               for (ii = 0; ii < data->results->len; ii++) {
+               for (ii = 0; ii < uid_search_results->len; ii++) {
                        const gchar *pooled_uid;
                        guint64 numeric_uid;
                        gchar *alloced_uid;
 
-                       numeric_uid = g_array_index (
-                               data->results, guint64, ii);
-                       alloced_uid = g_strdup_printf (
-                               "%" G_GUINT64_FORMAT, numeric_uid);
+                       numeric_uid = g_array_index (uid_search_results, guint64, ii);
+                       alloced_uid = g_strdup_printf ("%" G_GUINT64_FORMAT, numeric_uid);
                        pooled_uid = camel_pstring_add (alloced_uid, TRUE);
                        g_ptr_array_add (results, (gpointer) pooled_uid);
                }
        }
 
-       camel_imapx_job_unref (job);
+       if (uid_search_results)
+               g_array_unref (uid_search_results);
 
        return results;
 }
 
-gboolean
-camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
-                                       const gchar *folder_path)
+static gpointer
+imapx_server_idle_thread (gpointer user_data)
 {
-       gboolean res;
+       CamelIMAPXServer *is = user_data;
+       CamelIMAPXMailbox *mailbox;
+       CamelIMAPXCommand *ic;
+       CamelIMAPXCommandPart *cp;
+       GCancellable *idle_cancellable;
+       GError *local_error = NULL;
+       gint previous_timeout = -1;
+       gboolean success = FALSE;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
-       g_return_val_if_fail (folder_path != NULL, FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+
+       g_rec_mutex_lock (&is->priv->idle_lock);
 
-       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+       if (!is->priv->idle_cancellable)
+               is->priv->idle_cancellable = g_cancellable_new ();
 
-       res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path)) 
0;
+       mailbox = is->priv->idle_mailbox;
+       idle_cancellable = is->priv->idle_cancellable;
 
-       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+       if (mailbox)
+               g_object_ref (mailbox);
+       if (idle_cancellable)
+               g_object_ref (idle_cancellable);
 
-       return res;
+       is->priv->idle_running = TRUE;
+
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       if (!mailbox)
+               mailbox = camel_imapx_server_ref_selected (is);
+
+       if (!mailbox)
+               goto exit;
+
+       success = camel_imapx_server_ensure_selected_sync (is, mailbox, idle_cancellable, &local_error);
+       if (!success)
+               goto exit;
+
+       ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_IDLE, "IDLE");
+       camel_imapx_command_close (ic);
+
+       cp = g_queue_peek_head (&ic->parts);
+       cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+
+       g_mutex_lock (&is->priv->stream_lock);
+       /* Set the connection timeout to one minute more than the inactivity timeout */
+       if (is->priv->connection)
+               previous_timeout = imapx_server_set_connection_timeout (is->priv->connection, 
INACTIVITY_TIMEOUT_SECONDS + 60);
+       g_mutex_unlock (&is->priv->stream_lock);
+
+       /* Blocks, until the DONE is issued or on inactivity timeout, error, ... */
+       success = camel_imapx_server_process_command_sync (is, ic, _("Error running IDLE"), idle_cancellable, 
&local_error);
+
+       if (previous_timeout >= 0) {
+               g_mutex_lock (&is->priv->stream_lock);
+               if (is->priv->connection)
+                       imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+               g_mutex_unlock (&is->priv->stream_lock);
+       }
+
+       camel_imapx_command_unref (ic);
+
+ exit:
+       g_rec_mutex_lock (&is->priv->idle_lock);
+       is->priv->idle_running = FALSE;
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       if (success)
+               c (camel_imapx_server_get_tagprefix (is), "IDLE finished successfully");
+       else if (local_error)
+               c (camel_imapx_server_get_tagprefix (is), "IDLE finished with error: %s", 
local_error->message);
+       else
+               c (camel_imapx_server_get_tagprefix (is), "IDLE finished without error");
+
+       g_clear_object (&mailbox);
+       g_clear_object (&idle_cancellable);
+       g_clear_object (&is);
+
+       g_clear_error (&local_error);
+
+       return NULL;
+}
+
+static gboolean
+imapx_server_run_idle_thread_cb (gpointer user_data)
+{
+       GWeakRef *is_weakref = user_data;
+       CamelIMAPXServer *is;
+
+       g_return_val_if_fail (is_weakref != NULL, FALSE);
+
+       is = g_weak_ref_get (is_weakref);
+       if (!is)
+               return FALSE;
+
+       g_rec_mutex_lock (&is->priv->idle_lock);
+
+       if (g_main_current_source () == is->priv->idle_pending) {
+               if (!g_source_is_destroyed (g_main_current_source ())) {
+                       GThread *thread;
+                       GError *local_error = NULL;
+
+                       thread = g_thread_try_new (NULL, imapx_server_idle_thread, g_object_ref (is), 
&local_error);
+                       if (thread) {
+                               is->priv->idle_thread = thread;
+                       } else {
+                               g_warning ("%s: Failed to create IDLE thread: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
+                       }
+
+                       g_clear_error (&local_error);
+               }
+
+               g_source_unref (is->priv->idle_pending);
+               is->priv->idle_pending = NULL;
+       }
+
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       return FALSE;
 }
 
 gboolean
-camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
+camel_imapx_server_schedule_idle_sync (CamelIMAPXServer *is,
+                                      CamelIMAPXMailbox *mailbox,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       gboolean res;
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+       if (mailbox)
+               g_return_val_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox), FALSE);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+       if (!camel_imapx_server_stop_idle_sync (is, cancellable, error))
+               return FALSE;
 
-       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+       if (!imapx_use_idle (is))
+               return TRUE;
 
-       res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
+       g_rec_mutex_lock (&is->priv->idle_lock);
 
-       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+       if (is->priv->idle_pending) {
+               g_source_destroy (is->priv->idle_pending);
+               g_source_unref (is->priv->idle_pending);
+       }
 
-       return res;
+       g_clear_object (&is->priv->idle_mailbox);
+       if (mailbox)
+               is->priv->idle_mailbox = g_object_ref (mailbox);
+
+       is->priv->idle_pending = g_timeout_source_new_seconds (IMAPX_IDLE_WAIT_SECONDS);
+       g_source_set_callback (
+               is->priv->idle_pending, imapx_server_run_idle_thread_cb,
+               imapx_weak_ref_new (is), (GDestroyNotify) imapx_weak_ref_free);
+       g_source_attach (is->priv->idle_pending, NULL);
+
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       return TRUE;
 }
 
-gint
-camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
+gboolean
+camel_imapx_server_stop_idle_sync (CamelIMAPXServer *is,
+                                  GCancellable *cancellable,
+                                  GError **error)
 {
-       guint32 res;
+       GThread *idle_thread;
+       GCancellable *idle_cancellable;
+       CamelIMAPXCommand *idle_command = NULL;
+       gboolean success = TRUE;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+       COMMAND_LOCK (is);
 
-       g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+       if (is->priv->current_command && is->priv->current_command->job_kind == CAMEL_IMAPX_JOB_IDLE) {
+               idle_command = camel_imapx_command_ref (is->priv->current_command);
+       }
 
-       res = imapx_server->priv->jobs_prop_command_count;
+       COMMAND_UNLOCK (is);
 
-       g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+       g_rec_mutex_lock (&is->priv->idle_lock);
 
-       return res;
+       if (is->priv->idle_pending) {
+               g_source_destroy (is->priv->idle_pending);
+               g_source_unref (is->priv->idle_pending);
+               is->priv->idle_pending = NULL;
+       }
+
+       idle_cancellable = is->priv->idle_cancellable ? g_object_ref (is->priv->idle_cancellable) : NULL;
+       idle_thread = is->priv->idle_thread;
+
+       g_clear_object (&is->priv->idle_cancellable);
+       g_clear_object (&is->priv->idle_mailbox);
+       is->priv->idle_thread = NULL;
+
+       g_rec_mutex_unlock (&is->priv->idle_lock);
+
+       if (idle_cancellable) {
+               g_cancellable_cancel (idle_cancellable);
+               g_object_unref (idle_cancellable);
+       }
+
+       if (idle_thread)
+               g_thread_join (idle_thread);
+
+       if (idle_command) {
+               CamelIMAPXCommand *ic;
+               gint previous_timeout = -1;
+               GError *local_error = NULL;
+
+               g_return_val_if_fail (is->priv->current_command == NULL, FALSE);
+
+               ic = camel_imapx_command_new (is, CAMEL_IMAPX_JOB_DONE, "DONE");
+               ic->tag = idle_command->tag;
+
+               g_mutex_lock (&is->priv->stream_lock);
+               /* Set the connection timeout to some short time, no need to wait for it for too long */
+               if (is->priv->connection)
+                       previous_timeout = imapx_server_set_connection_timeout (is->priv->connection, 15);
+               g_mutex_unlock (&is->priv->stream_lock);
+
+               success = camel_imapx_server_process_command_sync (is, ic, _("Failed to issue DONE"), 
cancellable, &local_error);
+
+               if (previous_timeout >= 0) {
+                       g_mutex_lock (&is->priv->stream_lock);
+                       if (is->priv->connection)
+                               imapx_server_set_connection_timeout (is->priv->connection, previous_timeout);
+                       g_mutex_unlock (&is->priv->stream_lock);
+               }
+
+               camel_imapx_command_unref (ic);
+               camel_imapx_command_unref (idle_command);
+
+               if (success)
+                       c (camel_imapx_server_get_tagprefix (is), "DONE finished successfully");
+               else
+                       c (camel_imapx_server_get_tagprefix (is), "DONE finished with error: %s", local_error 
? local_error->message : "Unknown error");
+
+               if (!success) {
+                       GError *tmp = local_error;
+
+                       local_error = NULL;
+
+                       g_set_error (
+                               &local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+                               "Failed to finish IDLE with DONE: %s", tmp ? tmp->message : "Unknown error");
+
+                       g_clear_error (&tmp);
+               }
+
+               if (local_error) {
+                       g_propagate_error (error, local_error);
+                       success = FALSE;
+               }
+       }
+
+       return success;
 }
 
 /**
@@ -9801,210 +6063,46 @@ camel_imapx_server_register_untagged_handler (CamelIMAPXServer *is,
        return previous;
 }
 
-/**
- * camel_imapx_server_is_job_in_queue:
- * @imapx_server: a #CamelIMAPXServer instance
- * @mailbox: a mailbox to search job for
- * @job_type: a job type specifier to search for
- * @uid: optional message UID for which the job might be searched
- *
- * Searches queue of jobs for the particular job. The returned job
- * is referenced for thread safety, unref it with camel_imapx_job_unref().
- *
- * Returns: %NULL, if such job could not be found, or a referenced job.
- **/
-CamelIMAPXJob *
-camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
-                           CamelIMAPXMailbox *mailbox,
-                           guint32 job_type,
-                           const gchar *uid)
+const struct _capability_info *
+camel_imapx_server_get_capability_info (CamelIMAPXServer *is)
 {
-       GList *head, *link;
-       CamelIMAPXJob *job = NULL;
-       gboolean found = FALSE;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
-
-       QUEUE_LOCK (imapx_server);
-
-       head = g_queue_peek_head_link (&imapx_server->jobs);
-
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               job = (CamelIMAPXJob *) link->data;
-
-               if (!job || !(job->type & job_type))
-                       continue;
-
-               if (camel_imapx_job_matches (job, mailbox, uid)) {
-                       found = TRUE;
-                       camel_imapx_job_ref (job);
-                       break;
-               }
-       }
-
-       QUEUE_UNLOCK (imapx_server);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
 
-       return found ? job : NULL;
+       return is->priv->cinfo;
 }
 
-/**
- * camel_imapx_server_shutdown:
- * @is: a #CamelIMAPXServer
- * @error: a #GError with which cancel any pending jobs
- *
- * Signals the server to shut down command processing. A #CamelIMAPXStore
- * should call this immediately before unreferencing its server instance.
- * Note, the server instance may linger a short time after this function
- * returns as its own worker threads finish.
- *
- * Since: 3.12
- **/
-void
-camel_imapx_server_shutdown (CamelIMAPXServer *is,
-                            const GError *error)
+gchar
+camel_imapx_server_get_tagprefix (CamelIMAPXServer *is)
 {
-       GCancellable *cancellable;
-       GError *shutdown_error_copy = NULL;
-
-       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
-
-       QUEUE_LOCK (is);
-
-       is->state = IMAPX_SHUTDOWN;
-
-       cancellable = g_weak_ref_get (&is->priv->parser_cancellable);
-
-       QUEUE_UNLOCK (is);
-
-       if (!error) {
-               shutdown_error_copy = imapx_server_dup_shutdown_error (is);
-               error = shutdown_error_copy;
-       }
-
-       if (error) {
-               imapx_abort_all_commands (is, error);
-       } else {
-               GError *local_error = NULL;
-
-               g_set_error (
-                       &local_error, CAMEL_SERVICE_ERROR,
-                       CAMEL_SERVICE_ERROR_UNAVAILABLE,
-                       "Shutting down");
-
-               imapx_abort_all_commands (is, local_error);
-
-               g_clear_error (&local_error);
-       }
-
-       g_main_loop_quit (is->priv->idle_main_loop);
-       g_main_loop_quit (is->priv->parser_main_loop);
-
-       g_cancellable_cancel (cancellable);
-       g_clear_object (&cancellable);
-       g_clear_error (&shutdown_error_copy);
-}
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), 0);
 
-static const gchar *
-imapx_server_get_job_type_name (CamelIMAPXJob *job)
-{
-       if (!job)
-               return "[null]";
-
-       switch (job->type) {
-       case IMAPX_JOB_GET_MESSAGE:
-               return "GET_MESSAGE";
-       case IMAPX_JOB_APPEND_MESSAGE:
-               return "APPEND_MESSAGE";
-       case IMAPX_JOB_COPY_MESSAGE:
-               return "COPY_MESSAGE";
-       case IMAPX_JOB_FETCH_NEW_MESSAGES:
-               return "FETCH_NEW_MESSAGES";
-       case IMAPX_JOB_REFRESH_INFO:
-               return "REFRESH_INFO";
-       case IMAPX_JOB_SYNC_CHANGES:
-               return "SYNC_CHANGES";
-       case IMAPX_JOB_EXPUNGE:
-               return "EXPUNGE";
-       case IMAPX_JOB_NOOP:
-               return "NOOP";
-       case IMAPX_JOB_IDLE:
-               return "IDLE";
-       case IMAPX_JOB_LIST:
-               return "LIST";
-       case IMAPX_JOB_CREATE_MAILBOX:
-               return "CREATE_MAILBOX";
-       case IMAPX_JOB_DELETE_MAILBOX:
-               return "DELETE_MAILBOX";
-       case IMAPX_JOB_RENAME_MAILBOX:
-               return "RENAME_MAILBOX";
-       case IMAPX_JOB_SUBSCRIBE_MAILBOX:
-               return "SUBSCRIBE_MAILBOX";
-       case IMAPX_JOB_UNSUBSCRIBE_MAILBOX:
-               return "UNSUBSCRIBE_MAILBOX";
-       case IMAPX_JOB_UPDATE_QUOTA_INFO:
-               return "UPDATE_QUOTA_INFO";
-       case IMAPX_JOB_UID_SEARCH:
-               return "UID_SEARCH";
-       }
-
-       return "???";
+       return is->priv->tagprefix;
 }
 
-static void
-imapx_server_dump_one_queue (CamelIMAPXCommandQueue *queue,
-                            const gchar *queue_name)
+void
+camel_imapx_server_set_tagprefix (CamelIMAPXServer *is,
+                                 gchar tagprefix)
 {
-       GList *iter;
-       gint ii;
-
-       g_return_if_fail (queue != NULL);
-       g_return_if_fail (queue_name != NULL);
-
-       if (camel_imapx_command_queue_is_empty (queue))
-               return;
-
-       printf ("      Content of '%s':\n", queue_name);
-
-       for (ii = 0, iter = camel_imapx_command_queue_peek_head_link (queue); iter != NULL; iter = 
g_list_next (iter), ii++) {
-               CamelIMAPXCommand *ic = iter->data;
-               CamelIMAPXJob *job = camel_imapx_command_get_job (ic);
+       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+       g_return_if_fail ((tagprefix >= 'A' && tagprefix <= 'Z') || (tagprefix >= 'a' && tagprefix <= 'z'));
 
-               printf ("         [%d] command:%p for job:%p (type:0x%x %s)\n", ii, ic, job, job ? job->type 
: 0, imapx_server_get_job_type_name (job));
-       }
+       is->priv->tagprefix = tagprefix;
 }
 
-/* for debugging purposes only */
-void
-camel_imapx_server_dump_queue_status (CamelIMAPXServer *imapx_server)
+CamelIMAPXCommand *
+camel_imapx_server_ref_current_command (CamelIMAPXServer *is)
 {
-       g_return_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server));
+       CamelIMAPXCommand *command;
 
-       QUEUE_LOCK (imapx_server);
-
-       printf ("   Queue status for server %p: jobs:%d queued:%d active:%d done:%d\n", imapx_server,
-               g_queue_get_length (&imapx_server->jobs),
-               camel_imapx_command_queue_get_length (imapx_server->queue),
-               camel_imapx_command_queue_get_length (imapx_server->active),
-               camel_imapx_command_queue_get_length (imapx_server->done));
-
-       if (!g_queue_is_empty (&imapx_server->jobs)) {
-               GList *iter;
-               gint ii;
-
-               printf ("      Content of 'jobs':\n");
+       g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
 
-               for (ii = 0, iter = g_queue_peek_head_link (&imapx_server->jobs); iter != NULL; iter = 
g_list_next (iter), ii++) {
-                       CamelIMAPXJob *job = iter->data;
+       COMMAND_LOCK (is);
 
-                       printf ("         [%d] job:%p (type:0x%x %s) with pending commands:%d\n", ii, job, 
job ? job->type : 0,
-                               imapx_server_get_job_type_name (job),
-                               job ? g_atomic_int_get (&job->commands) : -1);
-               }
-       }
+       command = is->priv->current_command;
+       if (command)
+               camel_imapx_command_ref (command);
 
-       imapx_server_dump_one_queue (imapx_server->queue, "queue");
-       imapx_server_dump_one_queue (imapx_server->active, "active");
-       imapx_server_dump_one_queue (imapx_server->done, "done");
+       COMMAND_UNLOCK (is);
 
-       QUEUE_UNLOCK (imapx_server);
+       return command;
 }
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 78289c7..c47dcf8 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -106,37 +106,14 @@ struct _CamelIMAPXUntaggedRespHandlerDesc {
 struct _CamelIMAPXServer {
        GObject parent;
        CamelIMAPXServerPrivate *priv;
-
-       /* Info about the current connection */
-       struct _capability_info *cinfo;
-
-       /* incoming jobs */
-       GQueue jobs;
-
-       gchar tagprefix;
-       gint state : 4;
-
-       /* Current command/work queue.  All commands are stored in one list,
-        * all the time, so they can be cleaned up in exception cases */
-       GRecMutex queue_lock;
-       CamelIMAPXCommand *literal;
-       CamelIMAPXCommandQueue *queue;
-       CamelIMAPXCommandQueue *active;
-       CamelIMAPXCommandQueue *done;
-
-       gboolean use_qresync;
 };
 
 struct _CamelIMAPXServerClass {
        GObjectClass parent_class;
 
        /* Signals */
-       void            (*mailbox_select)       (CamelIMAPXServer *is,
+       void            (*refresh_mailbox)      (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox);
-       void            (*mailbox_closed)       (CamelIMAPXServer *is,
-                                                CamelIMAPXMailbox *mailbox);
-       void            (*shutdown)             (CamelIMAPXServer *is,
-                                                const GError *error);
 };
 
 GType          camel_imapx_server_get_type     (void);
@@ -155,50 +132,82 @@ CamelIMAPXMailbox *
 CamelIMAPXMailbox *
                camel_imapx_server_ref_pending_or_selected
                                                (CamelIMAPXServer *is);
-gboolean       camel_imapx_server_connect      (CamelIMAPXServer *is,
+const struct _capability_info *
+               camel_imapx_server_get_capability_info
+                                               (CamelIMAPXServer *is);
+gchar          camel_imapx_server_get_tagprefix
+                                               (CamelIMAPXServer *is);
+void           camel_imapx_server_set_tagprefix
+                                               (CamelIMAPXServer *is,
+                                                gchar tagprefix);
+CamelIMAPXCommand *
+               camel_imapx_server_ref_current_command
+                                               (CamelIMAPXServer *is);
+gboolean       camel_imapx_server_connect_sync (CamelIMAPXServer *is,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       imapx_connect_to_server         (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_disconnect_sync
+                                               (CamelIMAPXServer *is,
                                                 GCancellable *cancellable,
                                                 GError **error);
 gboolean       camel_imapx_server_is_connected (CamelIMAPXServer *imapx_server);
 CamelAuthenticationResult
-               camel_imapx_server_authenticate (CamelIMAPXServer *is,
+               camel_imapx_server_authenticate_sync
+                                               (CamelIMAPXServer *is,
                                                 const gchar *mechanism,
                                                 GCancellable *cancellable,
                                                 GError **error);
-void           camel_imapx_server_shutdown     (CamelIMAPXServer *is,
-                                                const GError *error);
-gboolean       camel_imapx_server_list         (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_query_auth_types_sync
+                                               (CamelIMAPXServer *is,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_server_mailbox_selected
+                                               (CamelIMAPXServer *is,
+                                                CamelIMAPXMailbox *mailbox);
+gboolean       camel_imapx_server_ensure_selected_sync
+                                               (CamelIMAPXServer *is,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_server_process_command_sync
+                                               (CamelIMAPXServer *is,
+                                                CamelIMAPXCommand *ic,
+                                                const gchar *error_prefix,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_server_list_sync    (CamelIMAPXServer *is,
                                                 const gchar *pattern,
                                                 CamelStoreGetFolderInfoFlags flags,
                                                 GCancellable *cancellable,
                                                 GError **error);
-CamelFolderChangeInfo *
-               camel_imapx_server_refresh_info (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_refresh_info_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_sync_changes (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_sync_changes_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_expunge      (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_expunge_sync (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_noop         (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_noop_sync    (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-CamelStream *  camel_imapx_server_get_message  (CamelIMAPXServer *is,
+CamelStream *  camel_imapx_server_get_message_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 CamelFolderSummary *summary,
                                                 CamelDataCache *message_cache,
                                                 const gchar *message_uid,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_copy_message (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_copy_message_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 CamelIMAPXMailbox *destination,
                                                 GPtrArray *uids,
@@ -206,7 +215,7 @@ gboolean    camel_imapx_server_copy_message (CamelIMAPXServer *is,
                                                 gboolean remove_deleted_flags,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_append_message
+gboolean       camel_imapx_server_append_message_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 CamelFolderSummary *summary,
@@ -216,70 +225,66 @@ gboolean  camel_imapx_server_append_message
                                                 gchar **append_uid,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_sync_message (CamelIMAPXServer *is,
+gboolean       camel_imapx_server_sync_message_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 CamelFolderSummary *summary,
                                                 CamelDataCache *message_cache,
                                                 const gchar *message_uid,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_create_mailbox
+gboolean       camel_imapx_server_create_mailbox_sync
                                                (CamelIMAPXServer *is,
                                                 const gchar *mailbox_name,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_delete_mailbox
+gboolean       camel_imapx_server_delete_mailbox_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_rename_mailbox
+gboolean       camel_imapx_server_rename_mailbox_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 const gchar *new_mailbox_name,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_subscribe_mailbox
+gboolean       camel_imapx_server_subscribe_mailbox_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_unsubscribe_mailbox
+gboolean       camel_imapx_server_unsubscribe_mailbox_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-gboolean       camel_imapx_server_update_quota_info
+gboolean       camel_imapx_server_update_quota_info_sync
                                                (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 GCancellable *cancellable,
                                                 GError **error);
-GPtrArray *    camel_imapx_server_uid_search   (CamelIMAPXServer *is,
+GPtrArray *    camel_imapx_server_uid_search_sync
+                                               (CamelIMAPXServer *is,
                                                 CamelIMAPXMailbox *mailbox,
                                                 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);
+gboolean       camel_imapx_server_schedule_idle_sync
+                                               (CamelIMAPXServer *is,
+                                                CamelIMAPXMailbox *mailbox,
+                                                GCancellable *cancellable,
+                                                GError **error);
+gboolean       camel_imapx_server_stop_idle_sync
+                                               (CamelIMAPXServer *is,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
 const CamelIMAPXUntaggedRespHandlerDesc *
                camel_imapx_server_register_untagged_handler
                                                (CamelIMAPXServer *is,
                                                 const gchar *untagged_response,
                                                 const CamelIMAPXUntaggedRespHandlerDesc *desc);
-struct _CamelIMAPXJob *
-               camel_imapx_server_ref_job      (CamelIMAPXServer *imapx_server,
-                                                CamelIMAPXMailbox *mailbox,
-                                                guint32 job_type,
-                                                const gchar *uid);
-
-/* for debugging purposes only */
-void           camel_imapx_server_dump_queue_status
-                                               (CamelIMAPXServer *imapx_server);
 G_END_DECLS
 
 #endif /* CAMEL_IMAPX_SERVER_H */
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index d64591c..18572c4 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -59,7 +59,7 @@
 #define e(...) camel_imapx_debug(extra, __VA_ARGS__)
 
 struct _CamelIMAPXStorePrivate {
-       CamelIMAPXConnManager *con_man;
+       CamelIMAPXConnManager *conn_man;
 
        CamelIMAPXServer *connecting_server;
        gboolean is_concurrent_connection;
@@ -88,7 +88,8 @@ struct _CamelIMAPXStorePrivate {
 enum {
        PROP_0,
        PROP_CONNECTABLE,
-       PROP_HOST_REACHABLE
+       PROP_HOST_REACHABLE,
+       PROP_CONN_MANAGER
 };
 
 enum {
@@ -660,6 +661,13 @@ imapx_store_get_property (GObject *object,
                                camel_network_service_get_host_reachable (
                                CAMEL_NETWORK_SERVICE (object)));
                        return;
+
+               case PROP_CONN_MANAGER:
+                       g_value_set_object (
+                               value,
+                               camel_imapx_store_get_conn_manager (
+                               CAMEL_IMAPX_STORE (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -672,9 +680,9 @@ imapx_store_dispose (GObject *object)
 
        /* 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->conn_man != NULL) {
                camel_service_disconnect_sync (CAMEL_SERVICE (imapx_store), FALSE, NULL, NULL);
-               g_clear_object (&imapx_store->priv->con_man);
+               g_clear_object (&imapx_store->priv->conn_man);
        }
 
        if (imapx_store->priv->settings_notify_handler_id > 0) {
@@ -771,8 +779,6 @@ imapx_connect_sync (CamelService *service,
                     GError **error)
 {
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
-       gboolean success;
 
        /* Chain up to parent's method. */
        if (!CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class)->connect_sync (service, cancellable, error))
@@ -780,12 +786,7 @@ imapx_connect_sync (CamelService *service,
 
        imapx_store = CAMEL_IMAPX_STORE (service);
 
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-       success = imapx_server != NULL;
-
-       g_clear_object (&imapx_server);
-
-       return success;
+       return camel_imapx_conn_manager_connect_sync (imapx_store->priv->conn_man, cancellable, error);
 }
 
 static gboolean
@@ -798,8 +799,8 @@ imapx_disconnect_sync (CamelService *service,
 
        priv = CAMEL_IMAPX_STORE_GET_PRIVATE (service);
 
-       if (priv->con_man != NULL)
-               camel_imapx_conn_manager_close_connections (priv->con_man, NULL);
+       if (priv->conn_man != NULL)
+               camel_imapx_conn_manager_disconnect_sync (priv->conn_man, cancellable, error);
 
        g_mutex_lock (&priv->server_lock);
 
@@ -828,7 +829,7 @@ imapx_authenticate_sync (CamelService *service,
        imapx_server = g_object_ref (priv->connecting_server);
        g_mutex_unlock (&priv->server_lock);
 
-       result = camel_imapx_server_authenticate (
+       result = camel_imapx_server_authenticate_sync (
                imapx_server, mechanism, cancellable, error);
 
        g_clear_object (&imapx_server);
@@ -856,28 +857,32 @@ imapx_query_auth_types_sync (CamelService *service,
        GList *sasl_types = NULL;
        GList *t, *next;
        CamelIMAPXServer *server;
+       const struct _capability_info *cinfo;
 
        imapx_store = CAMEL_IMAPX_STORE (service);
 
        server = camel_imapx_server_new (imapx_store);
-       server->tagprefix = 'Z';
+       camel_imapx_server_set_tagprefix (server, 'Z');
+
+       g_signal_emit_by_name (imapx_store->priv->conn_man, "connection-created", 0, server);
 
-       if (!imapx_connect_to_server (server, cancellable, error))
+       if (!camel_imapx_server_query_auth_types_sync (server, cancellable, error))
                goto exit;
 
+       cinfo = camel_imapx_server_get_capability_info (server);
+
        sasl_types = camel_sasl_authtype_list (FALSE);
        for (t = sasl_types; t; t = next) {
                authtype = t->data;
                next = t->next;
 
-               if (!server->cinfo || !g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
+               if (!cinfo || !g_hash_table_lookup (cinfo->auth_types, authtype->authproto)) {
                        sasl_types = g_list_remove_link (sasl_types, t);
                        g_list_free_1 (t);
                }
        }
 
-       sasl_types = g_list_prepend (
-               sasl_types, &camel_imapx_password_authtype);
+       sasl_types = g_list_prepend (sasl_types, &camel_imapx_password_authtype);
 
 exit:
        g_object_unref (server);
@@ -1018,6 +1023,7 @@ get_folder_info_offline (CamelStore *store,
        GPtrArray *folders;
        GPtrArray *array;
        gboolean use_subscriptions;
+       gint top_len;
        guint ii;
 
        service = CAMEL_SERVICE (store);
@@ -1038,6 +1044,8 @@ get_folder_info_offline (CamelStore *store,
                top = "";
        }
 
+       top_len = strlen (top);
+
        /* folder_info_build will insert parent nodes as necessary and mark
         * them as noselect, which is information we actually don't have at
         * the moment. So let it do the right thing by bailing out if it's
@@ -1058,7 +1066,8 @@ get_folder_info_offline (CamelStore *store,
                /* Filter by folder path. */
                si_is_match =
                        (include_inbox && si_is_inbox) ||
-                       g_str_has_prefix (folder_path, top);
+                       (g_str_has_prefix (folder_path, top) && (top_len == 0 ||
+                       !folder_path[top_len] || folder_path[top_len] == '/'));
 
                if (!si_is_match)
                        continue;
@@ -1160,7 +1169,7 @@ collect_folder_info_for_list (CamelIMAPXStore *imapx_store,
 }
 
 static gboolean
-fetch_folder_info_for_pattern (CamelIMAPXServer *server,
+fetch_folder_info_for_pattern (CamelIMAPXConnManager *conn_man,
                                CamelIMAPXNamespace *namespace,
                                const gchar *pattern,
                                CamelStoreGetFolderInfoFlags flags,
@@ -1173,22 +1182,9 @@ fetch_folder_info_for_pattern (CamelIMAPXServer *server,
        GError *local_error = NULL;
        gboolean success;
 
-       g_object_ref (server);
-
-       imapx_store = camel_imapx_server_ref_store (server);
-
-       success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&server);
+       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
 
-               server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
-               if (server)
-                       success = camel_imapx_server_list (server, pattern, flags, cancellable, &local_error);
-       }
-
-       g_clear_object (&server);
+       success = camel_imapx_conn_manager_list_sync (conn_man, pattern, flags, cancellable, &local_error);
 
        if (!success) {
                g_clear_object (&imapx_store);
@@ -1225,34 +1221,18 @@ fetch_folder_info_for_pattern (CamelIMAPXServer *server,
 }
 
 static gboolean
-fetch_folder_info_for_inbox (CamelIMAPXServer *server,
+fetch_folder_info_for_inbox (CamelIMAPXConnManager *conn_man,
                              CamelStoreGetFolderInfoFlags flags,
                              GHashTable *folder_info_results,
                              GCancellable *cancellable,
                              GError **error)
 {
        CamelIMAPXStore *imapx_store;
-       GError *local_error = NULL;
        gboolean success;
 
-       g_object_ref (server);
-       imapx_store = camel_imapx_server_ref_store (server);
+       imapx_store = camel_imapx_conn_manager_ref_store (conn_man);
 
-       success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&server);
-
-               server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, &local_error);
-               if (server)
-                       success = camel_imapx_server_list (server, "INBOX", flags, cancellable, &local_error);
-       }
-
-       g_clear_object (&server);
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_list_sync (conn_man, "INBOX", flags, cancellable, error);
 
        if (success) {
                CamelIMAPXMailbox *mailbox;
@@ -1271,7 +1251,7 @@ fetch_folder_info_for_inbox (CamelIMAPXServer *server,
 
 static gboolean
 fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
-                                         CamelIMAPXServer *server,
+                                         CamelIMAPXConnManager *conn_man,
                                           CamelIMAPXNamespaceCategory category,
                                           CamelStoreGetFolderInfoFlags flags,
                                           GHashTable *folder_info_results,
@@ -1303,7 +1283,7 @@ fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
                pattern = g_strdup_printf ("%s*", ns_prefix);
 
                success = fetch_folder_info_for_pattern (
-                       server, namespace, pattern, flags,
+                       conn_man, namespace, pattern, flags,
                        folder_info_results, cancellable, error);
 
                g_free (pattern);
@@ -1321,7 +1301,7 @@ fetch_folder_info_for_namespace_category (CamelIMAPXStore *imapx_store,
 
 static gboolean
 fetch_folder_info_from_folder_path (CamelIMAPXStore *imapx_store,
-                                   CamelIMAPXServer *server,
+                                   CamelIMAPXConnManager *conn_man,
                                     const gchar *folder_path,
                                     CamelStoreGetFolderInfoFlags flags,
                                     GHashTable *folder_info_results,
@@ -1359,7 +1339,7 @@ fetch_folder_info_from_folder_path (CamelIMAPXStore *imapx_store,
        pattern = g_strdup_printf ("%s*", utf7_mailbox_name);
 
        success = fetch_folder_info_for_pattern (
-               server, namespace, pattern, flags,
+               conn_man, namespace, pattern, flags,
                folder_info_results, cancellable, error);
 
        g_free (pattern);
@@ -1495,14 +1475,12 @@ sync_folders (CamelIMAPXStore *imapx_store,
               GCancellable *cancellable,
               GError **error)
 {
-       CamelIMAPXServer *server;
+       CamelIMAPXConnManager *conn_man;
        GHashTable *folder_info_results;
        gboolean update_folder_list;
        gboolean success;
 
-       server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-       if (server == NULL)
-               return FALSE;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        /* mailbox name -> CamelFolderInfo */
        folder_info_results = g_hash_table_new_full (
@@ -1525,13 +1503,13 @@ sync_folders (CamelIMAPXStore *imapx_store,
 
        if (root_folder_path != NULL && *root_folder_path != '\0') {
                success = fetch_folder_info_from_folder_path (
-                       imapx_store, server, root_folder_path, flags,
+                       imapx_store, conn_man, root_folder_path, flags,
                        folder_info_results, cancellable, error);
        } else {
                gboolean have_folder_info_for_inbox;
 
                success = fetch_folder_info_for_namespace_category (
-                       imapx_store, server, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
+                       imapx_store, conn_man, CAMEL_IMAPX_NAMESPACE_PERSONAL, flags |
                        (update_folder_list ? CAMEL_STORE_FOLDER_INFO_SUBSCRIBED : 0),
                        folder_info_results, cancellable, error);
 
@@ -1543,7 +1521,7 @@ sync_folders (CamelIMAPXStore *imapx_store,
                 *     then LIST it explicitly. */
                if (success && !have_folder_info_for_inbox)
                        success = fetch_folder_info_for_inbox (
-                               server, flags, folder_info_results,
+                               conn_man, flags, folder_info_results,
                                cancellable, error);
        }
 
@@ -1593,8 +1571,6 @@ sync_folders (CamelIMAPXStore *imapx_store,
 exit:
        g_hash_table_destroy (folder_info_results);
 
-       g_object_unref (server);
-
        return success;
 }
 
@@ -1633,42 +1609,30 @@ static void
 discover_inbox (CamelIMAPXStore *imapx_store,
                 GCancellable *cancellable)
 {
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        const gchar *attribute;
 
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, NULL);
-
-       if (imapx_server == NULL)
-               return;
-
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
        mailbox = camel_imapx_store_ref_mailbox (imapx_store, "INBOX");
 
        if (mailbox == NULL)
-               goto exit;
+               return;
 
        attribute = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
        if (!camel_imapx_mailbox_has_attribute (mailbox, attribute)) {
                GError *local_error = NULL;
                gboolean success;
 
-               success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-
-               while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                       g_clear_error (&local_error);
-                       g_clear_object (&imapx_server);
-
-                       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-                       if (imapx_server)
-                               success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, 
cancellable, &local_error);
+               success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, 
&local_error);
+               if (!success && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_warning ("%s: Failed to subscribe INBOX: %s", G_STRFUNC, local_error ? 
local_error->message : "Unknown error");
                }
 
                g_clear_error (&local_error);
        }
 
-exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 }
 
 static gboolean
@@ -1998,7 +1962,7 @@ imapx_store_create_folder_sync (CamelStore *store,
        CamelIMAPXNamespaceResponse *namespace_response;
        CamelIMAPXNamespace *namespace;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelFolder *folder;
        CamelIMAPXMailbox *parent_mailbox = NULL;
        CamelFolderInfo *fi = NULL;
@@ -2008,13 +1972,9 @@ imapx_store_create_folder_sync (CamelStore *store,
        gchar *mailbox_name = NULL;
        gchar separator;
        gboolean success;
-       GError *local_error = NULL;
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               return NULL;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        if (parent_name == NULL || *parent_name == '\0')
                goto check_namespace;
@@ -2085,19 +2045,7 @@ check_separator:
        /* This also LISTs the mailbox after creating it, which
         * triggers the CamelIMAPXStore::mailbox-created signal
         * and all the local processing that goes along with it. */
-       success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-               if (imapx_server)
-                       success = camel_imapx_server_create_mailbox (imapx_server, mailbox_name, cancellable, 
&local_error);
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_create_mailbox_sync (conn_man, mailbox_name, cancellable, error);
 
        if (success) {
                fi = imapx_store_build_folder_info (
@@ -2108,8 +2056,6 @@ check_separator:
 exit:
        g_free (mailbox_name);
 
-       g_clear_object (&imapx_server);
-
        return fi;
 }
 
@@ -2121,10 +2067,9 @@ imapx_store_delete_folder_sync (CamelStore *store,
 {
        CamelFolder *folder;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        folder = camel_store_get_folder_sync (
                store, folder_name, 0, cancellable, error);
@@ -2133,29 +2078,14 @@ imapx_store_delete_folder_sync (CamelStore *store,
                return FALSE;
 
        imapx_store = CAMEL_IMAPX_STORE (store);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        mailbox = camel_imapx_folder_list_mailbox (
                CAMEL_IMAPX_FOLDER (folder), cancellable, error);
        if (mailbox == NULL)
                goto exit;
 
-       success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-               if (imapx_server)
-                       success = camel_imapx_server_delete_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_delete_mailbox_sync (conn_man, mailbox, cancellable, error);
 
        if (success)
                imapx_delete_folder_from_cache (imapx_store, folder_name, TRUE);
@@ -2163,7 +2093,6 @@ imapx_store_delete_folder_sync (CamelStore *store,
 exit:
        g_clear_object (&folder);
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -2179,7 +2108,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
        CamelService *service;
        CamelSettings *settings;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        CamelIMAPXMailbox *cloned_mailbox;
        gchar *new_mailbox_name = NULL;
@@ -2202,10 +2131,7 @@ imapx_store_rename_folder_sync (CamelStore *store,
         * in imapx_store_process_mailbox_attributes(). */
        g_atomic_int_inc (&imapx_store->priv->syncing_folders);
 
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        folder = camel_store_get_folder_sync (
                store, old, 0, cancellable, error);
@@ -2226,30 +2152,11 @@ imapx_store_rename_folder_sync (CamelStore *store,
        new_mailbox_name = camel_imapx_folder_path_to_mailbox (new, separator);
 
        if (use_subscriptions) {
-               success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-
-               while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                       g_clear_error (&local_error);
-                       g_clear_object (&imapx_server);
-
-                       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-                       if (imapx_server)
-                               success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, 
cancellable, &local_error);
-               }
-
+               success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, 
&local_error);
                g_clear_error (&local_error);
        }
 
-       success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name, cancellable, 
&local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-               if (imapx_server)
-                       success = camel_imapx_server_rename_mailbox (imapx_server, mailbox, new_mailbox_name, 
cancellable, &local_error);
-       }
+       success = camel_imapx_conn_manager_rename_mailbox_sync (conn_man, mailbox, new_mailbox_name, 
cancellable, &local_error);
 
        if (!success) {
                if (local_error)
@@ -2259,19 +2166,14 @@ imapx_store_rename_folder_sync (CamelStore *store,
                if (use_subscriptions) {
                        gboolean success_2;
 
-                       success_2 = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-
-                       while (!success_2 && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                               g_clear_error (&local_error);
-                               g_clear_object (&imapx_server);
-
-                               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, 
cancellable, &local_error);
-                               if (imapx_server)
-                                       success_2 = camel_imapx_server_subscribe_mailbox (imapx_server, 
mailbox, cancellable, &local_error);
+                       success_2 = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, 
cancellable, &local_error);
+                       if (!success_2) {
+                               g_warning ("%s: Failed to subscribe '%s': %s", G_STRFUNC, 
camel_imapx_mailbox_get_name (mailbox),
+                                       local_error ? local_error->message : "Unknown error");
                        }
-
                        g_clear_error (&local_error);
                }
+
                goto exit;
        }
 
@@ -2282,23 +2184,10 @@ imapx_store_rename_folder_sync (CamelStore *store,
        /* Create a cloned CamelIMAPXMailbox with the new mailbox name. */
        cloned_mailbox = camel_imapx_mailbox_clone (mailbox, new_mailbox_name);
 
-       camel_imapx_folder_set_mailbox (
-               CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
+       camel_imapx_folder_set_mailbox (CAMEL_IMAPX_FOLDER (folder), cloned_mailbox);
 
        if (use_subscriptions) {
-               success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox, cancellable, 
&local_error);
-
-               while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-                       g_clear_error (&local_error);
-                       g_clear_object (&imapx_server);
-
-                       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-                       if (imapx_server)
-                               success = camel_imapx_server_subscribe_mailbox (imapx_server, cloned_mailbox, 
cancellable, &local_error);
-               }
-
-               if (local_error)
-                       g_propagate_error (error, local_error);
+               success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, cloned_mailbox, 
cancellable, error);
        }
 
        g_clear_object (&cloned_mailbox);
@@ -2307,9 +2196,8 @@ exit:
        g_free (new_mailbox_name);
 
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
-       /* This enabled CamelStore signal emissions
+       /* This enables CamelStore signal emissions
         * in imapx_store_process_mailbox_attributes() again. */
        g_atomic_int_dec_and_test (&imapx_store->priv->syncing_folders);
 
@@ -2478,6 +2366,8 @@ imapx_ensure_parents_subscribed (CamelIMAPXStore *imapx_store,
 
                /* Since this is a "fake" folder node, it is not selectable. */
                fi->flags |= CAMEL_FOLDER_NOSELECT;
+               fi->unread = -1;
+               fi->total = -1;
 
                parents = g_slist_prepend (parents, fi);
        }
@@ -2488,6 +2378,9 @@ imapx_ensure_parents_subscribed (CamelIMAPXStore *imapx_store,
                camel_subscribable_folder_subscribed (subscribable, fi);
                camel_folder_info_free (fi);
        }
+
+       g_slist_free (parents);
+       g_free (parent);
 }
 
 static gboolean
@@ -2498,16 +2391,12 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
 {
        CamelFolder *folder;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        imapx_store = CAMEL_IMAPX_STORE (subscribable);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        folder = camel_store_get_folder_sync (
                CAMEL_STORE (subscribable),
@@ -2522,19 +2411,7 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
        if (mailbox == NULL)
                goto exit;
 
-       success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-               if (imapx_server)
-                       success = camel_imapx_server_subscribe_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_subscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
 
        if (success) {
                CamelFolderInfo *fi;
@@ -2550,7 +2427,6 @@ imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -2563,16 +2439,12 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 {
        CamelFolder *folder;
        CamelIMAPXStore *imapx_store;
-       CamelIMAPXServer *imapx_server;
+       CamelIMAPXConnManager *conn_man;
        CamelIMAPXMailbox *mailbox = NULL;
        gboolean success = FALSE;
-       GError *local_error = NULL;
 
        imapx_store = CAMEL_IMAPX_STORE (subscribable);
-       imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, error);
-
-       if (imapx_server == NULL)
-               goto exit;
+       conn_man = camel_imapx_store_get_conn_manager (imapx_store);
 
        folder = camel_store_get_folder_sync (
                CAMEL_STORE (subscribable),
@@ -2587,19 +2459,7 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
        if (mailbox == NULL)
                goto exit;
 
-       success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, &local_error);
-
-       while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, 
CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
-               g_clear_error (&local_error);
-               g_clear_object (&imapx_server);
-
-               imapx_server = camel_imapx_store_ref_server (imapx_store, NULL, FALSE, cancellable, 
&local_error);
-               if (imapx_server)
-                       success = camel_imapx_server_unsubscribe_mailbox (imapx_server, mailbox, cancellable, 
&local_error);
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
+       success = camel_imapx_conn_manager_unsubscribe_mailbox_sync (conn_man, mailbox, cancellable, error);
 
        if (success) {
                CamelFolderInfo *fi;
@@ -2612,7 +2472,6 @@ imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
 
 exit:
        g_clear_object (&mailbox);
-       g_clear_object (&imapx_server);
 
        return success;
 }
@@ -2700,6 +2559,17 @@ camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
        class->mailbox_renamed = imapx_store_mailbox_renamed;
        class->mailbox_updated = imapx_store_mailbox_updated;
 
+       g_object_class_install_property (
+               object_class,
+               PROP_CONN_MANAGER,
+               g_param_spec_object (
+                       "conn-manager",
+                       "Connection Manager",
+                       "The Connection Manager being used for remote operations",
+                       CAMEL_TYPE_IMAPX_CONN_MANAGER,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
        /* Inherited from CamelNetworkService. */
        g_object_class_override_property (
                object_class,
@@ -2769,7 +2639,7 @@ camel_imapx_store_init (CamelIMAPXStore *store)
 {
        store->priv = CAMEL_IMAPX_STORE_GET_PRIVATE (store);
 
-       store->priv->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
+       store->priv->conn_man = camel_imapx_conn_manager_new (CAMEL_STORE (store));
 
        g_mutex_init (&store->priv->get_finfo_lock);
 
@@ -2800,70 +2670,12 @@ camel_imapx_store_init (CamelIMAPXStore *store)
                G_CALLBACK (imapx_store_update_store_flags), NULL);
 }
 
-/**
- * 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.
- *
- * As a convenience, if the @store is not currently connected to an IMAP
- * server, the function sets @error to %CAMEL_SERVER_ERROR_UNAVAILABLE and
- * returns %NULL.  If an operation can possibly be executed while offline,
- * pass %NULL for @error.
- *
- * The returned #CamelIMAPXServer is referenced for thread-safety and must
- * be unreferenced with g_object_unref() when finished with it.
- *
- * Returns: a #CamelIMAPXServer, or %NULL
- *
- * Since: 3.10
- **/
-CamelIMAPXServer *
-camel_imapx_store_ref_server (CamelIMAPXStore *store,
-                             const gchar *folder_name,
-                             gboolean for_expensive_job,
-                             GCancellable *cancellable,
-                              GError **error)
-{
-       CamelIMAPXServer *server = NULL;
-       CamelSession *session;
-       GError *local_error = NULL;
-
+CamelIMAPXConnManager *
+camel_imapx_store_get_conn_manager (CamelIMAPXStore *store)
+{
        g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), NULL);
 
-       session = camel_service_ref_session (CAMEL_SERVICE (store));
-
-       if (camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)) &&
-           camel_session_get_online (session))
-               server = camel_imapx_conn_manager_get_connection (
-                       store->priv->con_man, folder_name, for_expensive_job, cancellable, &local_error);
-
-       g_clear_object (&session);
-
-       if (!server && (!local_error || local_error->domain == G_RESOLVER_ERROR)) {
-               if (!local_error) {
-                       g_set_error (
-                               &local_error, CAMEL_SERVICE_ERROR,
-                               CAMEL_SERVICE_ERROR_UNAVAILABLE,
-                               _("You must be working online to complete this operation"));
-               } else {
-                       g_set_error (
-                               error, CAMEL_SERVICE_ERROR,
-                               CAMEL_SERVICE_ERROR_UNAVAILABLE,
-                               _("You must be working online to complete this operation (%s)"),
-                               local_error->message);
-
-                       g_clear_error (&local_error);
-               }
-       }
-
-       if (local_error)
-               g_propagate_error (error, local_error);
-
-       return server;
+       return store->priv->conn_man;
 }
 
 /* The caller should hold the store->priv->server_lock already, when calling this */
@@ -2904,19 +2716,6 @@ camel_imapx_store_is_connecting_concurrent_connection (CamelIMAPXStore *imapx_st
        return res;
 }
 
-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);
-}
-
 /**
  * camel_imapx_store_ref_namespaces:
  * @imapx_store: a #CamelIMAPXStore
@@ -3244,8 +3043,8 @@ imapx_store_rename_mailbox_unlocked (CamelIMAPXStore *imapx_store,
                new_child_name = g_strconcat (
                        new_mailbox_name,
                        old_child_name + old_mailbox_name_length, NULL);
-               new_child = camel_imapx_mailbox_clone (
-                       old_child, new_child_name);
+
+               new_child = camel_imapx_mailbox_clone (old_child, new_child_name);
 
                /* Add the new mailbox, remove the old mailbox.
                 * Note we still have a reference on the old mailbox. */
@@ -3400,7 +3199,7 @@ camel_imapx_store_handle_list_response (CamelIMAPXStore *imapx_store,
 
        /* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
         * NAMESPACE capability and this is the first LIST / LSUB response. */
-       if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+       if (CAMEL_IMAPX_LACK_CAPABILITY (camel_imapx_server_get_capability_info (imapx_server), NAMESPACE)) {
                g_mutex_lock (&imapx_store->priv->namespaces_lock);
                if (imapx_store->priv->namespaces == NULL) {
                        imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3464,7 +3263,7 @@ camel_imapx_store_handle_lsub_response (CamelIMAPXStore *imapx_store,
 
        /* Fabricate a CamelIMAPXNamespaceResponse if the server lacks the
         * NAMESPACE capability and this is the first LIST / LSUB response. */
-       if (CAMEL_IMAPX_LACK_CAPABILITY (imapx_server->cinfo, NAMESPACE)) {
+       if (CAMEL_IMAPX_LACK_CAPABILITY (camel_imapx_server_get_capability_info (imapx_server), NAMESPACE)) {
                g_mutex_lock (&imapx_store->priv->namespaces_lock);
                if (imapx_store->priv->namespaces == NULL) {
                        imapx_store->priv->namespaces = camel_imapx_namespace_response_faux_new (response);
@@ -3535,41 +3334,11 @@ camel_imapx_store_set_quota_info (CamelIMAPXStore *store,
        g_mutex_unlock (&store->priv->quota_info_lock);
 }
 
-/* Tries to find matching job among all active connections.
-   See camel_imapx_server_ref_job() for more information on parameters
-   and return values.
-*/
-CamelIMAPXJob *
-camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
-                          CamelIMAPXMailbox *mailbox,
-                          guint32 job_type,
-                          const gchar *uid)
-{
-       GList *servers, *siter;
-       CamelIMAPXJob *job = NULL;
-
-       g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), NULL);
-
-       servers = camel_imapx_conn_manager_get_connections (imapx_store->priv->con_man);
-
-       for (siter = servers; siter; siter = g_list_next (siter)) {
-               CamelIMAPXServer *imapx_server = siter->data;
-
-               job = camel_imapx_server_ref_job (imapx_server, mailbox, job_type, uid);
-               if (job)
-                       break;
-       }
-
-       g_list_free_full (servers, g_object_unref);
-
-       return job;
-}
-
 /* for debugging purposes only */
 void
 camel_imapx_store_dump_queue_status (CamelIMAPXStore *imapx_store)
 {
        g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
 
-       camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->con_man);
+       camel_imapx_conn_manager_dump_queue_status (imapx_store->priv->conn_man);
 }
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index f1311c2..e25eccd 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -23,6 +23,7 @@
 
 #include <camel/camel.h>
 
+#include "camel-imapx-conn-manager.h"
 #include "camel-imapx-server.h"
 
 /* Standard GObject macros */
@@ -74,22 +75,15 @@ 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);
+CamelIMAPXConnManager *
+               camel_imapx_store_get_conn_manager
+                                               (CamelIMAPXStore *store);
 void           camel_imapx_store_set_connecting_server
                                                (CamelIMAPXStore *store,
                                                 CamelIMAPXServer *server,
                                                 gboolean is_concurrent_connection);
 gboolean       camel_imapx_store_is_connecting_concurrent_connection
                                                (CamelIMAPXStore *imapx_store);
-void           camel_imapx_store_folder_op_done
-                                               (CamelIMAPXStore *store,
-                                                CamelIMAPXServer *server,
-                                                const gchar *folder_name);
 CamelIMAPXNamespaceResponse *
                camel_imapx_store_ref_namespaces
                                                (CamelIMAPXStore *imapx_store);
@@ -126,12 +120,6 @@ void               camel_imapx_store_set_quota_info
                                                (CamelIMAPXStore *store,
                                                 const gchar *quota_root_name,
                                                 const CamelFolderQuotaInfo *info);
-struct _CamelIMAPXJob *
-               camel_imapx_store_ref_job       (CamelIMAPXStore *imapx_store,
-                                                CamelIMAPXMailbox *mailbox,
-                                                guint32 job_type,
-                                                const gchar *uid);
-
 /* for debugging purposes only */
 void           camel_imapx_store_dump_queue_status
                                                (CamelIMAPXStore *imapx_store);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 04d2a17..ea550a5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -134,6 +134,7 @@ camel/camel-vee-store.c
 camel/camel-vee-summary.c
 camel/camel-vtrash-folder.c
 camel/providers/imapx/camel-imapx-command.c
+camel/providers/imapx/camel-imapx-conn-manager.c
 camel/providers/imapx/camel-imapx-folder.c
 camel/providers/imapx/camel-imapx-input-stream.c
 camel/providers/imapx/camel-imapx-provider.c




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