[evolution-kolab/EDS_IMAPX_nobuild] updated IMAPX files as of EDS commit a97a7aff3ea212f7046a929942a6c884d4e1cfe7



commit 5c6b97385a7da6dae7ceb46060770da3f3f0df98
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Wed Feb 1 16:57:24 2012 +0100

    updated IMAPX files as of EDS commit a97a7aff3ea212f7046a929942a6c884d4e1cfe7
    
    * updated the local IMAPX code from upstream
    * now at EDS commit
      a97a7aff3ea212f7046a929942a6c884d4e1cfe7
    * pulling in of upstream now is needed to
      keep in sync for upcoming 3.3.5 prerelease

 src/camel/providers/imapx/Makefile.am              |    4 +
 src/camel/providers/imapx/camel-imapx-command.c    |  538 +++
 src/camel/providers/imapx/camel-imapx-command.h    |  120 +
 .../providers/imapx/camel-imapx-conn-manager.c     |  584 +++-
 src/camel/providers/imapx/camel-imapx-job.c        |  243 ++
 src/camel/providers/imapx/camel-imapx-job.h        |   78 +
 src/camel/providers/imapx/camel-imapx-server.c     | 3599 ++++++++++----------
 src/camel/providers/imapx/camel-imapx-server.h     |   22 +-
 src/camel/providers/imapx/camel-imapx-store.c      |   17 +-
 src/camel/providers/imapx/camel-imapx-utils.c      |   38 +-
 src/camel/providers/imapx/camel-imapx-utils.h      |    2 +-
 11 files changed, 3140 insertions(+), 2105 deletions(-)
---
diff --git a/src/camel/providers/imapx/Makefile.am b/src/camel/providers/imapx/Makefile.am
index 00b3508..8d76c5a 100644
--- a/src/camel/providers/imapx/Makefile.am
+++ b/src/camel/providers/imapx/Makefile.am
@@ -11,8 +11,10 @@ libcamelimapx_la_CPPFLAGS = \
 	-DG_LOG_DOMAIN=\"camel-imapx\"
 
 libcamelimapx_la_SOURCES =			\
+	camel-imapx-command.c			\
 	camel-imapx-conn-manager.c		\
 	camel-imapx-folder.c			\
+	camel-imapx-job.c			\
 	camel-imapx-provider.c			\
 	camel-imapx-server.c			\
 	camel-imapx-settings.c			\
@@ -23,8 +25,10 @@ libcamelimapx_la_SOURCES =			\
 	camel-imapx-utils.c
 
 noinst_HEADERS =				\
+	camel-imapx-command.h			\
 	camel-imapx-conn-manager.h		\
 	camel-imapx-folder.h			\
+	camel-imapx-job.h			\
 	camel-imapx-server.h			\
 	camel-imapx-settings.h			\
 	camel-imapx-store-summary.h		\
diff --git a/src/camel/providers/imapx/camel-imapx-command.c b/src/camel/providers/imapx/camel-imapx-command.c
new file mode 100644
index 0000000..a8bf635
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-command.c
@@ -0,0 +1,538 @@
+/*
+ * camel-imapx-command.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-imapx-command.h"
+
+#include <config.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include "camel-imapx-store.h"
+
+#define c(...) camel_imapx_debug(command, __VA_ARGS__)
+
+typedef struct _CamelIMAPXRealCommand CamelIMAPXRealCommand;
+
+/* CamelIMAPXCommand + some private bits */
+struct _CamelIMAPXRealCommand {
+	CamelIMAPXCommand public;
+
+	volatile gint ref_count;
+
+	/* For building the part. */
+	GString *buffer;
+
+	/* Used for running some commands synchronously. */
+	GCond *done_sync_cond;
+	GMutex *done_sync_mutex;
+	gboolean done_sync_flag;
+};
+
+CamelIMAPXCommand *
+camel_imapx_command_new (CamelIMAPXServer *is,
+                         const gchar *name,
+                         CamelFolder *select,
+                         const gchar *format,
+                         ...)
+{
+	CamelIMAPXRealCommand *real_ic;
+	static gint tag = 0;
+	va_list ap;
+
+	real_ic = g_slice_new0 (CamelIMAPXRealCommand);
+
+	/* Initialize private bits. */
+	real_ic->ref_count = 1;
+	real_ic->buffer = g_string_sized_new (512);
+	real_ic->done_sync_cond = g_cond_new ();
+	real_ic->done_sync_mutex = g_mutex_new ();
+
+	/* Initialize public bits. */
+	real_ic->public.is = is;
+	real_ic->public.tag = tag++;
+	real_ic->public.name = name;
+	real_ic->public.select = select;
+	g_queue_init (&real_ic->public.parts);
+
+	if (format != NULL && *format != '\0') {
+		va_start (ap, format);
+		camel_imapx_command_addv (
+			(CamelIMAPXCommand *) real_ic, format, ap);
+		va_end (ap);
+	}
+
+	return (CamelIMAPXCommand *) real_ic;
+}
+
+CamelIMAPXCommand *
+camel_imapx_command_ref (CamelIMAPXCommand *ic)
+{
+	CamelIMAPXRealCommand *real_ic;
+
+	real_ic = (CamelIMAPXRealCommand *) ic;
+
+	g_return_val_if_fail (real_ic != NULL, NULL);
+	g_return_val_if_fail (real_ic->ref_count > 0, NULL);
+
+	g_atomic_int_inc (&real_ic->ref_count);
+
+	return ic;
+}
+
+void
+camel_imapx_command_unref (CamelIMAPXCommand *ic)
+{
+	CamelIMAPXRealCommand *real_ic;
+
+	real_ic = (CamelIMAPXRealCommand *) ic;
+
+	g_return_if_fail (real_ic != NULL);
+	g_return_if_fail (real_ic->ref_count > 0);
+
+	if (g_atomic_int_dec_and_test (&real_ic->ref_count)) {
+		CamelIMAPXCommandPart *cp;
+
+		/* Free the public stuff. */
+
+		imapx_free_status (ic->status);
+
+		while ((cp = g_queue_pop_head (&ic->parts)) != NULL) {
+			g_free (cp->data);
+			if (cp->ob) {
+				switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
+				case CAMEL_IMAPX_COMMAND_FILE:
+				case CAMEL_IMAPX_COMMAND_STRING:
+					g_free (cp->ob);
+					break;
+				default:
+					g_object_unref (cp->ob);
+				}
+			}
+			g_free (cp);
+		}
+
+		/* Free the private stuff. */
+
+		g_string_free (real_ic->buffer, TRUE);
+
+		g_cond_free (real_ic->done_sync_cond);
+		g_mutex_free (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. */
+
+		g_slice_free (CamelIMAPXRealCommand, real_ic);
+	}
+}
+
+gint
+camel_imapx_command_compare (CamelIMAPXCommand *ic1,
+                             CamelIMAPXCommand *ic2)
+{
+	g_return_val_if_fail (ic1 != NULL, 0);
+	g_return_val_if_fail (ic2 != NULL, 0);
+
+	if (ic1->pri == ic2->pri)
+		return 0;
+
+	return (ic1->pri < ic2->pri) ? -1 : 1;
+}
+
+void
+camel_imapx_command_add (CamelIMAPXCommand *ic,
+                         const gchar *format,
+                         ...)
+{
+	va_list ap;
+
+	g_return_if_fail (ic != NULL);
+
+	if (format != NULL && *format != '\0') {
+		va_start (ap, format);
+		camel_imapx_command_addv (ic, format, ap);
+		va_end (ap);
+	}
+}
+
+void
+camel_imapx_command_addv (CamelIMAPXCommand *ic,
+                          const gchar *format,
+                          va_list ap)
+{
+	const gchar *p, *ps, *start;
+	guchar c;
+	guint width;
+	gchar ch;
+	gint llong;
+	gchar *s;
+	gchar *P;
+	gint d;
+	glong l;
+	guint32 f;
+	CamelFlag *F;
+	CamelStream *S;
+	CamelDataWrapper *D;
+	CamelSasl *A;
+	gchar literal_format[16];
+	CamelFolder *folder;
+	CamelStore *parent_store;
+	GString *buffer;
+	gchar *fname = NULL, *encoded = NULL;
+	const gchar *full_name;
+
+	g_return_if_fail (ic != NULL);
+
+	c(ic->is->tagprefix, "adding command, format = '%s'\n", format);
+
+	buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
+
+	p = format;
+	ps = format;
+	while ((c = *p++) != '\0') {
+		switch (c) {
+		case '%':
+			if (*p == '%') {
+				g_string_append_len (buffer, ps, p - ps);
+				p++;
+				ps = p;
+				continue;
+			}
+
+			g_string_append_len (buffer, ps, p - ps - 1);
+			start = p - 1;
+			width = 0;
+			llong = 0;
+
+			do {
+				c = *p++;
+				if (c == '0')
+					;
+				else if ( c== '-')
+					;
+				else
+					break;
+			} while (c);
+
+			do {
+				if (g_ascii_isdigit (c))
+					width = width * 10 + (c - '0');
+				else
+					break;
+			} while ((c = *p++));
+
+			while (c == 'l') {
+				llong++;
+				c = *p++;
+			}
+
+			switch (c) {
+			case 'A': /* auth object - sasl auth, treat as special kind of continuation */
+				A = va_arg (ap, CamelSasl *);
+				camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_AUTH, A);
+				break;
+			case 'S': /* stream */
+				S = va_arg (ap, CamelStream *);
+				c(ic->is->tagprefix, "got stream '%p'\n", S);
+				camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STREAM, S);
+				break;
+			case 'D': /* datawrapper */
+				D = va_arg (ap, CamelDataWrapper *);
+				c(ic->is->tagprefix, "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);
+				camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
+				break;
+			case 't': /* token */
+				s = va_arg (ap, gchar *);
+				g_string_append (buffer, s);
+				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);
+			output_string:
+				if (*s) {
+					guchar mask = imapx_is_mask (s);
+
+					if (mask & IMAPX_TYPE_ATOM_CHAR)
+						g_string_append (buffer, s);
+					else if (mask & IMAPX_TYPE_TEXT_CHAR) {
+						g_string_append_c (buffer, '"');
+						while (*s) {
+							gchar *start = s;
+
+							while (*s && imapx_is_quoted_char (*s))
+								s++;
+							g_string_append_len (buffer, start, s - start);
+							if (*s) {
+								g_string_append_c (buffer, '\\');
+								g_string_append_c (buffer, *s);
+								s++;
+							}
+						}
+						g_string_append_c (buffer, '"');
+					} else {
+						camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STRING, s);
+					}
+				} else {
+					g_string_append (buffer, "\"\"");
+				}
+				if (encoded) {
+					g_free (encoded);
+					encoded = NULL;
+				}
+				break;
+			case 'f': /* imap folder name */
+				folder = va_arg (ap, CamelFolder *);
+				full_name = camel_folder_get_full_name (folder);
+				c(ic->is->tagprefix, "got folder '%s'\n", full_name);
+				parent_store = camel_folder_get_parent_store (folder);
+				fname = camel_imapx_store_summary_full_from_path (((CamelIMAPXStore *) parent_store)->summary, full_name);
+				if (fname) {
+					encoded = camel_utf8_utf7 (fname);
+					g_free (fname);
+				} else
+					encoded = camel_utf8_utf7 (full_name);
+
+				if (encoded) {
+					s = encoded;
+					goto output_string;
+				} else
+					g_string_append (buffer, "\"\"");
+
+				break;
+			case 'F': /* IMAP flags set */
+				f = va_arg (ap, guint32);
+				F = va_arg (ap, CamelFlag *);
+				imapx_write_flags (buffer, f, F);
+				break;
+			case 'c':
+				d = va_arg (ap, gint);
+				ch = d;
+				g_string_append_c (buffer, ch);
+				break;
+			case 'd': /* int/unsigned */
+			case 'u':
+				if (llong == 1) {
+					l = va_arg (ap, glong);
+					c(ic->is->tagprefix, "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);
+					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);
+					memcpy (literal_format, start, p - start);
+					literal_format[p - start] = 0;
+					g_string_append_printf (buffer, literal_format, d);
+				}
+				break;
+			}
+
+			ps = p;
+			break;
+
+		case '\\':	/* only for \\ really, we dont support \n\r etc at all */
+			c = *p;
+			if (c) {
+				g_assert (c == '\\');
+				g_string_append_len (buffer, ps, p - ps);
+				p++;
+				ps = p;
+			}
+		}
+	}
+
+	g_string_append_len (buffer, ps, p - ps - 1);
+}
+
+void
+camel_imapx_command_add_part (CamelIMAPXCommand *ic,
+                              CamelIMAPXCommandPartType type,
+                              gpointer data)
+{
+	CamelIMAPXCommandPart *cp;
+	CamelStreamNull *null;
+	GString *buffer;
+	guint ob_size = 0;
+
+	buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
+
+	/* TODO: literal+? */
+
+	switch (type & CAMEL_IMAPX_COMMAND_MASK) {
+	case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
+	case CAMEL_IMAPX_COMMAND_STREAM: {
+		CamelObject *ob = data;
+
+		/* TODO: seekable streams we could just seek to the end and back */
+		null = (CamelStreamNull *) camel_stream_null_new ();
+		if ( (type & CAMEL_IMAPX_COMMAND_MASK) == CAMEL_IMAPX_COMMAND_DATAWRAPPER) {
+			camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) ob, (CamelStream *) null, NULL, NULL);
+		} else {
+			g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
+			camel_stream_write_to_stream ((CamelStream *) ob, (CamelStream *) null, NULL, NULL);
+			g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
+		}
+		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+		g_object_ref (ob);
+		ob_size = null->written;
+		g_object_unref (null);
+		break;
+	}
+	case CAMEL_IMAPX_COMMAND_AUTH: {
+		CamelObject *ob = data;
+		const gchar *mechanism;
+
+		/* we presume we'll need to get additional data only if we're not authenticated yet */
+		g_object_ref (ob);
+		mechanism = camel_sasl_get_mechanism (CAMEL_SASL (ob));
+		g_string_append (buffer, mechanism);
+		if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
+			type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+		break;
+	}
+	case CAMEL_IMAPX_COMMAND_FILE: {
+		gchar *path = data;
+		struct stat st;
+
+		if (g_stat (path, &st) == 0) {
+			data = g_strdup (data);
+			ob_size = st.st_size;
+		} else
+			data = NULL;
+
+		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+		break;
+	}
+	case CAMEL_IMAPX_COMMAND_STRING:
+		data = g_strdup (data);
+		ob_size = strlen (data);
+		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+		break;
+	default:
+		ob_size = 0;
+	}
+
+	if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
+		g_string_append_c (buffer, '{');
+		g_string_append_printf (buffer, "%u", ob_size);
+		if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
+			g_string_append_c (buffer, '+');
+		} else {
+			type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
+			type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
+		}
+		g_string_append_c (buffer, '}');
+	}
+
+	cp = g_malloc0 (sizeof (*cp));
+	cp->type = type;
+	cp->ob_size = ob_size;
+	cp->ob = data;
+	cp->data_size = buffer->len;
+	cp->data = g_strdup (buffer->str);
+
+	g_string_set_size (buffer, 0);
+
+	g_queue_push_tail (&ic->parts, cp);
+}
+
+void
+camel_imapx_command_close (CamelIMAPXCommand *ic)
+{
+	GString *buffer;
+
+	g_return_if_fail (ic != NULL);
+
+	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", buffer->len);
+	} else {
+		c(ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", buffer->len, 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 (ic != NULL);
+
+	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 (ic != NULL);
+
+	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);
+}
+
+gboolean
+camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
+                                         GError **error)
+{
+	g_return_val_if_fail (ic != NULL, FALSE);
+
+	if (ic->status != NULL && ic->status->result != IMAPX_OK) {
+		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;
+	}
+
+	return FALSE;
+}
+
diff --git a/src/camel/providers/imapx/camel-imapx-command.h b/src/camel/providers/imapx/camel-imapx-command.h
new file mode 100644
index 0000000..8c96621
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-command.h
@@ -0,0 +1,120 @@
+/*
+ * camel-imapx-command.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef CAMEL_IMAPX_COMMAND_H
+#define CAMEL_IMAPX_COMMAND_H
+
+#include <camel.h>
+
+#include "camel-imapx-server.h"
+#include "camel-imapx-utils.h"
+
+G_BEGIN_DECLS
+
+/* Avoid a circular reference. */
+struct _CamelIMAPXJob;
+
+typedef struct _CamelIMAPXCommand CamelIMAPXCommand;
+typedef struct _CamelIMAPXCommandPart CamelIMAPXCommandPart;
+
+typedef gboolean
+		(*CamelIMAPXCommandFunc)	(CamelIMAPXServer *is,
+						 CamelIMAPXCommand *ic,
+						 GError **error);
+
+typedef enum {
+	CAMEL_IMAPX_COMMAND_SIMPLE = 0,
+	CAMEL_IMAPX_COMMAND_DATAWRAPPER,
+	CAMEL_IMAPX_COMMAND_STREAM,
+	CAMEL_IMAPX_COMMAND_AUTH,
+	CAMEL_IMAPX_COMMAND_FILE,
+	CAMEL_IMAPX_COMMAND_STRING,
+	CAMEL_IMAPX_COMMAND_MASK = 0xff,
+
+	/* Continuation with LITERAL+ */
+	CAMEL_IMAPX_COMMAND_LITERAL_PLUS = 1 << 14,
+
+	/* Does this command expect continuation? */
+	CAMEL_IMAPX_COMMAND_CONTINUATION = 1 << 15
+
+} CamelIMAPXCommandPartType;
+
+struct _CamelIMAPXCommandPart {
+	gint data_size;
+	gchar *data;
+
+	CamelIMAPXCommandPartType type;
+
+	gint ob_size;
+	gpointer ob;
+};
+
+struct _CamelIMAPXCommand {
+	CamelIMAPXServer *is;
+	gint pri;
+
+	/* Command name/type (e.g. FETCH) */
+	const gchar *name;
+
+	/* Folder to select */
+	CamelFolder *select;
+
+	/* Status for command, indicates it is complete if != NULL. */
+	struct _status_info *status;
+
+	guint32 tag;
+
+	GQueue parts;
+	GList *current_part;
+
+	/* Responsible for free'ing the command. */
+	CamelIMAPXCommandFunc complete;
+	struct _CamelIMAPXJob *job;
+};
+
+CamelIMAPXCommand *
+		camel_imapx_command_new		(CamelIMAPXServer *is,
+						 const gchar *name,
+						 CamelFolder *select,
+						 const gchar *format,
+						 ...);
+CamelIMAPXCommand *
+		camel_imapx_command_ref		(CamelIMAPXCommand *ic);
+void		camel_imapx_command_unref	(CamelIMAPXCommand *ic);
+gint		camel_imapx_command_compare	(CamelIMAPXCommand *ic1,
+						 CamelIMAPXCommand *ic2);
+void		camel_imapx_command_add		(CamelIMAPXCommand *ic,
+						 const gchar *format,
+						 ...);
+void		camel_imapx_command_addv	(CamelIMAPXCommand *ic,
+						 const gchar *format,
+						 va_list ap);
+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);
+gboolean	camel_imapx_command_set_error_if_failed
+						(CamelIMAPXCommand *ic,
+						 GError **error);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_COMMAND_H */
+
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.c b/src/camel/providers/imapx/camel-imapx-conn-manager.c
index d6ccd0b..1b87384 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -26,63 +26,266 @@
 
 #define c(...) camel_imapx_debug(conman, __VA_ARGS__)
 
-#define CON_LOCK(x) (g_static_rec_mutex_lock(&(x)->priv->con_man_lock))
-#define CON_UNLOCK(x) (g_static_rec_mutex_unlock(&(x)->priv->con_man_lock))
+#define CON_READ_LOCK(x) \
+	(g_static_rw_lock_reader_lock (&(x)->priv->rw_lock))
+#define CON_READ_UNLOCK(x) \
+	(g_static_rw_lock_reader_unlock (&(x)->priv->rw_lock))
+#define CON_WRITE_LOCK(x) \
+	(g_static_rw_lock_writer_lock (&(x)->priv->rw_lock))
+#define CON_WRITE_UNLOCK(x) \
+	(g_static_rw_lock_writer_unlock (&(x)->priv->rw_lock))
 
 #define CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_IMAPX_CONN_MANAGER, CamelIMAPXConnManagerPrivate))
 
-G_DEFINE_TYPE (
-	CamelIMAPXConnManager,
-	camel_imapx_conn_manager,
-	CAMEL_TYPE_OBJECT)
+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;
 	gpointer store;  /* weak pointer */
-	GStaticRecMutex con_man_lock;
-	gboolean clearing_connections;
+	GStaticRWLock rw_lock;
 };
 
-typedef struct {
-	GHashTable *folders;
-	CamelIMAPXServer *conn;
+struct _ConnectionInfo {
+	GMutex *lock;
+	CamelIMAPXServer *is;
+	GHashTable *folder_names;
 	gchar *selected_folder;
-} ConnectionInfo;
+	volatile gint ref_count;
+};
 
 enum {
 	PROP_0,
 	PROP_STORE
 };
 
+G_DEFINE_TYPE (
+	CamelIMAPXConnManager,
+	camel_imapx_conn_manager,
+	CAMEL_TYPE_OBJECT)
+
+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);
+	cinfo->lock = g_mutex_new ();
+	cinfo->is = g_object_ref (is);
+	cinfo->folder_names = folder_names;
+	cinfo->ref_count = 1;
+
+	return cinfo;
+}
+
+static ConnectionInfo *
+connection_info_ref (ConnectionInfo *cinfo)
+{
+	g_return_val_if_fail (cinfo != NULL, NULL);
+	g_return_val_if_fail (cinfo->ref_count > 0, NULL);
+
+	g_atomic_int_inc (&cinfo->ref_count);
+
+	return cinfo;
+}
+
 static void
-free_connection (gpointer data,
-                 gpointer user_data)
+connection_info_unref (ConnectionInfo *cinfo)
 {
-	ConnectionInfo *cinfo = (ConnectionInfo *) data;
-	CamelIMAPXServer *conn = cinfo->conn;
+	g_return_if_fail (cinfo != NULL);
+	g_return_if_fail (cinfo->ref_count > 0);
 
-	camel_imapx_server_connect (conn, NULL, NULL);
+	if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
+		camel_imapx_server_connect (cinfo->is, NULL, NULL);
 
-	g_object_unref (conn);
-	g_hash_table_destroy (cinfo->folders);
-	g_free (cinfo->selected_folder);
+		g_mutex_free (cinfo->lock);
+		g_object_unref (cinfo->is);
+		g_hash_table_destroy (cinfo->folder_names);
+		g_free (cinfo->selected_folder);
+
+		g_slice_free (ConnectionInfo, cinfo);
+	}
+}
+
+static gboolean
+connection_info_is_available (ConnectionInfo *cinfo)
+{
+	gboolean available;
+
+	g_return_val_if_fail (cinfo != NULL, FALSE);
+
+	g_mutex_lock (cinfo->lock);
 
-	g_free (cinfo);
+	/* Available means it's not tracking any folder names. */
+	available = (g_hash_table_size (cinfo->folder_names) == 0);
+
+	g_mutex_unlock (cinfo->lock);
+
+	return available;
+}
+
+static gboolean
+connection_info_has_folder_name (ConnectionInfo *cinfo,
+                                 const gchar *folder_name)
+{
+	gpointer value;
+
+	g_return_val_if_fail (cinfo != NULL, FALSE);
+
+	if (folder_name == NULL)
+		return FALSE;
+
+	g_mutex_lock (cinfo->lock);
+
+	value = g_hash_table_lookup (cinfo->folder_names, folder_name);
+
+	g_mutex_unlock (cinfo->lock);
+
+	return (value != NULL);
 }
 
 static void
-imapx_prune_connections (CamelIMAPXConnManager *con_man)
+connection_info_insert_folder_name (ConnectionInfo *cinfo,
+                                    const gchar *folder_name)
 {
-	CON_LOCK (con_man);
+	g_return_if_fail (cinfo != NULL);
+	g_return_if_fail (folder_name != NULL);
 
-	con_man->priv->clearing_connections = TRUE;
-	g_list_foreach (con_man->priv->connections, (GFunc) free_connection, NULL);
-	con_man->priv->connections = NULL;
-	con_man->priv->clearing_connections = FALSE;
+	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);
 
-	CON_UNLOCK (con_man);
+	g_mutex_unlock (cinfo->lock);
+}
+
+static gchar *
+connection_info_dup_selected_folder (ConnectionInfo *cinfo)
+{
+	gchar *selected_folder;
+
+	g_return_val_if_fail (cinfo != NULL, NULL);
+
+	g_mutex_lock (cinfo->lock);
+
+	selected_folder = g_strdup (cinfo->selected_folder);
+
+	g_mutex_unlock (cinfo->lock);
+
+	return selected_folder;
+}
+
+static void
+connection_info_set_selected_folder (ConnectionInfo *cinfo,
+                                     const gchar *selected_folder)
+{
+	g_return_if_fail (cinfo != NULL);
+
+	g_mutex_lock (cinfo->lock);
+
+	g_free (cinfo->selected_folder);
+	cinfo->selected_folder = g_strdup (selected_folder);
+
+	g_mutex_unlock (cinfo->lock);
+}
+
+static GList *
+imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
+{
+	GList *list;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+
+	CON_READ_LOCK (con_man);
+
+	list = g_list_copy (con_man->priv->connections);
+	g_list_foreach (list, (GFunc) connection_info_ref, NULL);
+
+	CON_READ_UNLOCK (con_man);
+
+	return list;
+}
+
+static ConnectionInfo *
+imapx_conn_manager_lookup_info (CamelIMAPXConnManager *con_man,
+                                CamelIMAPXServer *is)
+{
+	ConnectionInfo *cinfo = NULL;
+	GList *list, *link;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), NULL);
+
+	CON_READ_LOCK (con_man);
+
+	list = con_man->priv->connections;
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		ConnectionInfo *candidate = link->data;
+
+		if (candidate->is == is) {
+			cinfo = connection_info_ref (candidate);
+			break;
+		}
+	}
+
+	CON_READ_UNLOCK (con_man);
+
+	return cinfo;
+}
+
+static gboolean
+imapx_conn_manager_remove_info (CamelIMAPXConnManager *con_man,
+                                ConnectionInfo *cinfo)
+{
+	GList *list, *link;
+	gboolean removed = FALSE;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), FALSE);
+	g_return_val_if_fail (cinfo != NULL, FALSE);
+
+	CON_WRITE_LOCK (con_man);
+
+	list = con_man->priv->connections;
+	link = g_list_find (list, cinfo);
+
+	if (link != NULL) {
+		list = g_list_remove_link (list, link);
+		connection_info_unref (cinfo);
+		removed = TRUE;
+	}
+
+	con_man->priv->connections = list;
+
+	CON_WRITE_UNLOCK (con_man);
+
+	return removed;
 }
 
 static void
@@ -140,7 +343,10 @@ imapx_conn_manager_dispose (GObject *object)
 
 	priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
 
-	imapx_prune_connections (CAMEL_IMAPX_CONN_MANAGER (object));
+	g_list_free_full (
+		priv->connections,
+		(GDestroyNotify) connection_info_unref);
+	priv->connections = NULL;
 
 	if (priv->store != NULL) {
 		g_object_remove_weak_pointer (
@@ -159,7 +365,7 @@ imapx_conn_manager_finalize (GObject *object)
 
 	priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (object);
 
-	g_static_rec_mutex_free (&priv->con_man_lock);
+	g_static_rw_lock_free (&priv->rw_lock);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
@@ -196,101 +402,75 @@ camel_imapx_conn_manager_init (CamelIMAPXConnManager *con_man)
 {
 	con_man->priv = CAMEL_IMAPX_CONN_MANAGER_GET_PRIVATE (con_man);
 
-	g_static_rec_mutex_init (&con_man->priv->con_man_lock);
-
-	con_man->priv->clearing_connections = FALSE;
+	g_static_rw_lock_init (&con_man->priv->rw_lock);
 }
 
 /* Static functions go here */
 
 /* TODO destroy unused connections in a time-out loop */
 static void
-imapx_conn_shutdown (CamelIMAPXServer *conn,
+imapx_conn_shutdown (CamelIMAPXServer *is,
                      CamelIMAPXConnManager *con_man)
 {
-	GList *l;
 	ConnectionInfo *cinfo;
-	gboolean found = FALSE;
-
-	/* when clearing connections then other thread than a parser thread,
-	 * in which this function is called, holds the CON_LOCK, thus skip
-	 * this all, because otherwise a deadlock will happen.
-	 * The connection will be freed later anyway. */
-	if (con_man->priv->clearing_connections) {
-		c(conn->tagprefix, "%s: called on %p when clearing connections, skipping it...\n", G_STRFUNC, conn);
-		return;
-	}
-
-	CON_LOCK (con_man);
 
-	for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
-		cinfo = (ConnectionInfo *) l->data;
-		if (cinfo->conn == conn) {
-			found = TRUE;
-			break;
-		}
-	}
+	/* Returns a new ConnectionInfo reference. */
+	cinfo = imapx_conn_manager_lookup_info (con_man, is);
 
-	if (found) {
-		con_man->priv->connections = g_list_remove (con_man->priv->connections, cinfo);
-		free_connection (cinfo, GINT_TO_POINTER (1));
+	if (cinfo != NULL) {
+		imapx_conn_manager_remove_info (con_man, cinfo);
+		connection_info_unref (cinfo);
 	}
-
-	CON_UNLOCK (con_man);
 }
 
 static void
-imapx_conn_update_select (CamelIMAPXServer *conn,
+imapx_conn_update_select (CamelIMAPXServer *is,
                           const gchar *selected_folder,
                           CamelIMAPXConnManager *con_man)
 {
-	GList *l;
 	ConnectionInfo *cinfo;
-	gboolean found = FALSE;
+	gchar *old_selected_folder;
 
-	CON_LOCK (con_man);
+	/* Returns a new ConnectionInfo reference. */
+	cinfo = imapx_conn_manager_lookup_info (con_man, is);
 
-	for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
-		cinfo = (ConnectionInfo *) l->data;
-		if (cinfo->conn == conn) {
-			found = TRUE;
-			break;
-		}
-	}
+	if (cinfo == NULL)
+		return;
 
-	if (found) {
-		if (cinfo->selected_folder) {
-			IMAPXJobQueueInfo *jinfo;
-
-			jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
-			if (!g_hash_table_lookup (jinfo->folders, cinfo->selected_folder)) {
-				g_hash_table_remove (cinfo->folders, cinfo->selected_folder);
-				c(conn->tagprefix, "Removed folder %s from connection folder list - select changed \n", cinfo->selected_folder);
-			}
-			camel_imapx_destroy_job_queue_info (jinfo);
-			g_free (cinfo->selected_folder);
+	old_selected_folder = connection_info_dup_selected_folder (cinfo);
+
+	if (old_selected_folder != NULL) {
+		IMAPXJobQueueInfo *jinfo;
+
+		jinfo = camel_imapx_server_get_job_queue_info (is);
+		if (!g_hash_table_lookup (jinfo->folders, 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);
 		}
+		camel_imapx_destroy_job_queue_info (jinfo);
 
-		cinfo->selected_folder = g_strdup (selected_folder);
+		g_free (old_selected_folder);
 	}
 
-	CON_UNLOCK (con_man);
+	connection_info_set_selected_folder (cinfo, selected_folder);
+
+	connection_info_unref (cinfo);
 }
 
 /* This should find a connection if the slots are full, returns NULL if there are slots available for a new connection for a folder */
 static CamelIMAPXServer *
-imapx_find_connection (CamelIMAPXConnManager *con_man,
-                       const gchar *folder_name)
+imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
+                                const gchar *folder_name)
 {
-	guint i = 0, prev_len = -1, n = -1;
-	GList *l;
-	CamelIMAPXServer *conn = NULL;
 	CamelService *service;
 	CamelSettings *settings;
+	CamelIMAPXServer *is = NULL;
 	ConnectionInfo *cinfo = NULL;
+	GList *list, *link;
 	guint concurrent_connections;
+	guint min_jobs = G_MAXUINT;
 
-	CON_LOCK (con_man);
+	/* Caller must be holding CON_WRITE_LOCK. */
 
 	service = CAMEL_SERVICE (con_man->priv->store);
 	settings = camel_service_get_settings (service);
@@ -299,73 +479,96 @@ imapx_find_connection (CamelIMAPXConnManager *con_man,
 		camel_imapx_settings_get_concurrent_connections (
 		CAMEL_IMAPX_SETTINGS (settings));
 
-	/* Have a dedicated connection for INBOX ? */
-	for (l = con_man->priv->connections, i = 0; l != NULL; l = g_list_next (l), i++) {
-		IMAPXJobQueueInfo *jinfo = NULL;
+	/* XXX Have a dedicated connection for INBOX ? */
 
-		cinfo = (ConnectionInfo *) l->data;
-		jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
+	list = con_man->priv->connections;
 
-		if (prev_len == -1) {
-			prev_len = jinfo->queue_len;
-			n = 0;
-		}
+	/* If a folder was not given, find the least-busy connection. */
+	if (folder_name == NULL)
+		goto least_busy;
 
-		if (jinfo->queue_len < prev_len)
-			n = i;
+	/* First try to find a connection already handling this folder. */
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		ConnectionInfo *candidate = link->data;
 
-		camel_imapx_destroy_job_queue_info (jinfo);
+		if (connection_info_has_folder_name (candidate, folder_name)) {
+			cinfo = connection_info_ref (candidate);
+			goto exit;
+		}
+	}
 
-		if (folder_name && (g_hash_table_lookup (cinfo->folders, folder_name) || g_hash_table_size (cinfo->folders) == 0)) {
-			conn = g_object_ref (cinfo->conn);
+	/* Next try to find a connection not handling any folders. */
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		ConnectionInfo *candidate = link->data;
 
-			if (folder_name)
-				g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
-			c(conn->tagprefix, "Found connection for %s and connection number %d \n", folder_name, i+1);
-			break;
+		if (connection_info_is_available (candidate)) {
+			cinfo = connection_info_ref (candidate);
+			goto exit;
 		}
 	}
 
-	if (!conn && n != -1 && (!folder_name || concurrent_connections == g_list_length (con_man->priv->connections))) {
-		cinfo = g_list_nth_data (con_man->priv->connections, n);
-		conn = g_object_ref (cinfo->conn);
+least_busy:
+	/* 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;
+		IMAPXJobQueueInfo *jinfo = NULL;
+
+		jinfo = camel_imapx_server_get_job_queue_info (candidate->is);
+
+		if (cinfo == NULL) {
+			cinfo = connection_info_ref (candidate);
+			min_jobs = jinfo->queue_len;
 
-		if (folder_name) {
-			g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
-			c(conn->tagprefix, "Adding folder %s to connection number %d \n", folder_name, n+1);
+		} else if (jinfo->queue_len < min_jobs) {
+			connection_info_unref (cinfo);
+			cinfo = connection_info_ref (candidate);
+			min_jobs = jinfo->queue_len;
 		}
+
+		camel_imapx_destroy_job_queue_info (jinfo);
 	}
 
-	if (camel_debug_flag (conman))
-		g_assert (!(concurrent_connections == g_list_length (con_man->priv->connections) && !conn));
+exit:
+	if (cinfo != NULL && folder_name != NULL)
+		connection_info_insert_folder_name (cinfo, folder_name);
+
+	if (cinfo != NULL) {
+		is = g_object_ref (cinfo->is);
+		connection_info_unref (cinfo);
+	}
 
-	CON_UNLOCK (con_man);
+	if (camel_debug_flag (conman))
+		g_assert (!(concurrent_connections == g_list_length (con_man->priv->connections) && is == NULL));
 
-	return conn;
+	return is;
 }
 
 static CamelIMAPXServer *
-imapx_create_new_connection (CamelIMAPXConnManager *con_man,
-                             const gchar *folder_name,
-                             GCancellable *cancellable,
-                             GError **error)
+imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
+                                      const gchar *folder_name,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-	CamelIMAPXServer *conn;
+	CamelIMAPXServer *is = NULL;
 	CamelIMAPXStore *imapx_store;
 	CamelStore *store = con_man->priv->store;
 	CamelService *service;
 	ConnectionInfo *cinfo = NULL;
 	gboolean success;
 
+	/* Caller must be holding CON_WRITE_LOCK. */
+
 	service = CAMEL_SERVICE (store);
 
 	imapx_store = CAMEL_IMAPX_STORE (store);
 
-	CON_LOCK (con_man);
-
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	conn = camel_imapx_server_new (store);
+	/* Check if we got cancelled while we were waiting. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		goto exit;
+
+	is = camel_imapx_server_new (store);
 
 	/* XXX As part of the connect operation the CamelIMAPXServer will
 	 *     have to call camel_session_authenticate_sync(), but it has
@@ -379,45 +582,42 @@ imapx_create_new_connection (CamelIMAPXConnManager *con_man,
 	 *     CamelIMAPXServer to act on in its authenticate_sync() method.
 	 *
 	 *     Because we're holding the CAMEL_SERVICE_REC_CONNECT_LOCK
-	 *     (and our own CON_LOCK for that matter) we should not have
-	 *     multiple IMAPX connections trying to authenticate at once,
-	 *     so this should be thread-safe.
+	 *     we should not have multiple IMAPX connections trying to
+	 *     authenticate at once, so this should be thread-safe.
 	 */
-	imapx_store->authenticating_server = g_object_ref (conn);
-	success = camel_imapx_server_connect (conn, cancellable, error);
+	imapx_store->authenticating_server = g_object_ref (is);
+	success = camel_imapx_server_connect (is, cancellable, error);
 	g_object_unref (imapx_store->authenticating_server);
 	imapx_store->authenticating_server = NULL;
 
-	if (success) {
-		g_object_ref (conn);
-	} else {
-		g_object_unref (conn);
-
-		camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
-		CON_UNLOCK (con_man);
-
-		return NULL;
+	if (!success) {
+		g_object_unref (is);
+		is = NULL;
+		goto exit;
 	}
 
-	g_signal_connect (conn, "shutdown", G_CALLBACK (imapx_conn_shutdown), con_man);
-	g_signal_connect (conn, "select_changed", G_CALLBACK (imapx_conn_update_select), con_man);
-
-	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
+	g_signal_connect (
+		is, "shutdown",
+		G_CALLBACK (imapx_conn_shutdown), con_man);
+	g_signal_connect (
+		is, "select_changed",
+		G_CALLBACK (imapx_conn_update_select), con_man);
 
-	cinfo = g_new0 (ConnectionInfo, 1);
-	cinfo->conn = conn;
-	cinfo->folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+	cinfo = connection_info_new (is);
 
-	if (folder_name)
-		g_hash_table_insert (cinfo->folders, g_strdup (folder_name), GINT_TO_POINTER (1));
+	if (folder_name != NULL)
+		connection_info_insert_folder_name (cinfo, folder_name);
 
-	con_man->priv->connections = g_list_prepend (con_man->priv->connections, cinfo);
+	/* Takes ownership of the ConnectionInfo. */
+	con_man->priv->connections = g_list_prepend (
+		con_man->priv->connections, cinfo);
 
-	c(conn->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
+	c(is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
 
-	CON_UNLOCK (con_man);
+exit:
+	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	return conn;
+	return is;
 }
 
 /****************************/
@@ -445,73 +645,71 @@ camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
                                          GCancellable *cancellable,
                                          GError **error)
 {
-	CamelIMAPXServer *conn = NULL;
+	CamelIMAPXServer *is = NULL;
 
 	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
 
-	CON_LOCK (con_man);
+	/* Hold the writer lock while we requisition a CamelIMAPXServer
+	 * to prevent other threads from adding or removing connections. */
+	CON_WRITE_LOCK (con_man);
 
-	conn = imapx_find_connection (con_man, folder_name);
-	if (!conn)
-		conn = imapx_create_new_connection (con_man, folder_name, cancellable, error);
+	/* Check if we got cancelled while waiting for the lock. */
+	if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		is = imapx_find_connection_unlocked (con_man, folder_name);
+		if (is == NULL)
+			is = imapx_create_new_connection_unlocked (
+				con_man, folder_name, cancellable, error);
+	}
 
-	CON_UNLOCK (con_man);
+	CON_WRITE_UNLOCK (con_man);
 
-	return conn;
+	return is;
 }
 
 GList *
 camel_imapx_conn_manager_get_connections (CamelIMAPXConnManager *con_man)
 {
-	GList *l, *conns = NULL;
+	GList *list, *link;
 
-	CON_LOCK (con_man);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man), NULL);
 
-	for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
-		ConnectionInfo *cinfo = (ConnectionInfo *) l->data;
+	list = imapx_conn_manager_list_info (con_man);
 
-		conns = g_list_prepend (conns, g_object_ref (cinfo->conn));
+	/* 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);
 	}
 
-	CON_UNLOCK (con_man);
-
-	return conns;
+	return list;
 }
 
 /* Used for handling operations that fails to execute and that needs to removed from folder list */
 void
 camel_imapx_conn_manager_update_con_info (CamelIMAPXConnManager *con_man,
-                                          CamelIMAPXServer *conn,
+                                          CamelIMAPXServer *is,
                                           const gchar *folder_name)
 {
-	GList *l;
 	ConnectionInfo *cinfo;
-	gboolean found = FALSE;
+	IMAPXJobQueueInfo *jinfo;
 
 	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
 
-	CON_LOCK (con_man);
+	/* Returns a new ConnectionInfo reference. */
+	cinfo = imapx_conn_manager_lookup_info (con_man, is);
 
-	for (l = con_man->priv->connections; l != NULL; l = g_list_next (l)) {
-		cinfo = (ConnectionInfo *) l->data;
-		if (cinfo->conn == conn) {
-			found = TRUE;
-			break;
-		}
-	}
-
-	if (found) {
-		IMAPXJobQueueInfo *jinfo;
+	if (cinfo == NULL)
+		return;
 
-		jinfo = camel_imapx_server_get_job_queue_info (cinfo->conn);
-		if (!g_hash_table_lookup (jinfo->folders, folder_name)) {
-			g_hash_table_remove (cinfo->folders, folder_name);
-			c(conn->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
-		}
-		camel_imapx_destroy_job_queue_info (jinfo);
+	jinfo = camel_imapx_server_get_job_queue_info (cinfo->is);
+	if (!g_hash_table_lookup (jinfo->folders, 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);
 	}
+	camel_imapx_destroy_job_queue_info (jinfo);
 
-	CON_UNLOCK (con_man);
+	connection_info_unref (cinfo);
 }
 
 void
@@ -519,5 +717,13 @@ camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
 {
 	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
 
-	imapx_prune_connections (con_man);
+	CON_WRITE_LOCK (con_man);
+
+	g_list_free_full (
+		con_man->priv->connections,
+		(GDestroyNotify) connection_info_unref);
+	con_man->priv->connections = NULL;
+
+	CON_WRITE_UNLOCK (con_man);
 }
+
diff --git a/src/camel/providers/imapx/camel-imapx-job.c b/src/camel/providers/imapx/camel-imapx-job.c
new file mode 100644
index 0000000..e61ed3b
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-job.c
@@ -0,0 +1,243 @@
+/*
+ * camel-imapx-job.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "camel-imapx-job.h"
+
+typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
+
+/* CamelIMAPXJob + some private bits */
+struct _CamelIMAPXRealJob {
+	CamelIMAPXJob public;
+
+	volatile gint ref_count;
+
+	/* Used for running some jobs synchronously. */
+	GCond *done_cond;
+	GMutex *done_mutex;
+	gboolean done_flag;
+
+	/* Extra job-specific data. */
+	gpointer data;
+	GDestroyNotify destroy_data;
+};
+
+static void
+imapx_job_cancelled_cb (GCancellable *cancellable,
+                        CamelIMAPXJob *job)
+{
+	/* 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. */
+
+	camel_imapx_job_done (job);
+}
+
+CamelIMAPXJob *
+camel_imapx_job_new (GCancellable *cancellable)
+{
+	CamelIMAPXRealJob *real_job;
+
+	if (cancellable != NULL)
+		g_object_ref (cancellable);
+
+	real_job = g_slice_new0 (CamelIMAPXRealJob);
+
+	/* Initialize private bits. */
+	real_job->ref_count = 1;
+	real_job->done_cond = g_cond_new ();
+	real_job->done_mutex = g_mutex_new ();
+
+	/* Initialize public bits. */
+	real_job->public.cancellable = cancellable;
+
+	return (CamelIMAPXJob *) real_job;
+}
+
+CamelIMAPXJob *
+camel_imapx_job_ref (CamelIMAPXJob *job)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_val_if_fail (real_job != NULL, NULL);
+	g_return_val_if_fail (real_job->ref_count > 0, NULL);
+
+	g_atomic_int_inc (&real_job->ref_count);
+
+	return job;
+}
+
+void
+camel_imapx_job_unref (CamelIMAPXJob *job)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_if_fail (real_job != NULL);
+	g_return_if_fail (real_job->ref_count > 0);
+
+	if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
+
+		/* Free the public stuff. */
+
+		g_clear_error (&real_job->public.error);
+
+		if (real_job->public.pop_operation_msg)
+			camel_operation_pop_message (
+				real_job->public.cancellable);
+
+		if (real_job->public.cancellable != NULL)
+			g_object_unref (real_job->public.cancellable);
+
+		/* Free the private stuff. */
+
+		g_cond_free (real_job->done_cond);
+		g_mutex_free (real_job->done_mutex);
+
+		if (real_job->destroy_data != NULL)
+			real_job->destroy_data (real_job->data);
+
+		g_slice_free (CamelIMAPXRealJob, real_job);
+	}
+}
+
+void
+camel_imapx_job_wait (CamelIMAPXJob *job)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_if_fail (real_job != NULL);
+
+	g_mutex_lock (real_job->done_mutex);
+	while (!real_job->done_flag)
+		g_cond_wait (
+			real_job->done_cond,
+			real_job->done_mutex);
+	g_mutex_unlock (real_job->done_mutex);
+}
+
+void
+camel_imapx_job_done (CamelIMAPXJob *job)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_if_fail (real_job != 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);
+}
+
+gboolean
+camel_imapx_job_run (CamelIMAPXJob *job,
+                     CamelIMAPXServer *is,
+                     GError **error)
+{
+	gulong cancel_id = 0;
+
+	g_return_val_if_fail (job != NULL, FALSE);
+	g_return_val_if_fail (job->start != NULL, FALSE);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
+
+	if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
+		return FALSE;
+
+	if (G_IS_CANCELLABLE (job->cancellable))
+		cancel_id = g_cancellable_connect (
+			job->cancellable,
+			G_CALLBACK (imapx_job_cancelled_cb),
+			camel_imapx_job_ref (job),
+			(GDestroyNotify) camel_imapx_job_unref);
+
+	job->start (job, is);
+
+	if (!job->noreply)
+		camel_imapx_job_wait (job);
+
+	if (cancel_id > 0)
+		g_cancellable_disconnect (job->cancellable, cancel_id);
+
+	if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
+		return FALSE;
+
+	if (job->error != NULL) {
+		g_propagate_error (error, job->error);
+		job->error = NULL;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+gboolean
+camel_imapx_job_matches (CamelIMAPXJob *job,
+                         CamelFolder *folder,
+                         const gchar *uid)
+{
+	/* XXX CamelFolder 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);
+
+	if (folder != NULL)
+		g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	if (job->matches == NULL)
+		return FALSE;
+
+	return job->matches (job, folder, uid);
+}
+
+gpointer
+camel_imapx_job_get_data (CamelIMAPXJob *job)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_val_if_fail (real_job != NULL, NULL);
+
+	return real_job->data;
+}
+
+void
+camel_imapx_job_set_data (CamelIMAPXJob *job,
+                          gpointer data,
+                          GDestroyNotify destroy_data)
+{
+	CamelIMAPXRealJob *real_job;
+
+	real_job = (CamelIMAPXRealJob *) job;
+
+	g_return_if_fail (real_job != NULL);
+
+	if (real_job->destroy_data != NULL)
+		real_job->destroy_data (real_job->data);
+
+	real_job->data = data;
+	real_job->destroy_data = destroy_data;
+}
+
diff --git a/src/camel/providers/imapx/camel-imapx-job.h b/src/camel/providers/imapx/camel-imapx-job.h
new file mode 100644
index 0000000..0ca97e9
--- /dev/null
+++ b/src/camel/providers/imapx/camel-imapx-job.h
@@ -0,0 +1,78 @@
+/*
+ * camel-imapx-job.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef CAMEL_IMAPX_JOB_H
+#define CAMEL_IMAPX_JOB_H
+
+#include <camel.h>
+
+#include "camel-imapx-server.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CamelIMAPXJob CamelIMAPXJob;
+
+struct _uidset_state {
+	gint entries, uids;
+	gint total, limit;
+	guint32 start;
+	guint32 last;
+};
+
+struct _CamelIMAPXJob {
+	GCancellable *cancellable;
+	GError *error;
+
+	/* Whether to pop a status message off the
+	 * GCancellable when the job is finalized. */
+	gboolean pop_operation_msg;
+
+	void		(*start)		(CamelIMAPXJob *job,
+						 CamelIMAPXServer *is);
+	gboolean	(*matches)		(CamelIMAPXJob *job,
+						 CamelFolder *folder,
+						 const gchar *uid);
+
+	guint noreply:1;	/* dont wait for reply */
+	guint32 type;		/* operation type */
+	gint pri;		/* the command priority */
+	gshort commands;	/* counts how many commands are outstanding */
+
+	CamelFolder *folder;
+};
+
+CamelIMAPXJob *	camel_imapx_job_new		(GCancellable *cancellable);
+CamelIMAPXJob *	camel_imapx_job_ref		(CamelIMAPXJob *job);
+void		camel_imapx_job_unref		(CamelIMAPXJob *job);
+void		camel_imapx_job_wait		(CamelIMAPXJob *job);
+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,
+						 CamelFolder *folder,
+						 const gchar *uid);
+gpointer	camel_imapx_job_get_data	(CamelIMAPXJob *job);
+void		camel_imapx_job_set_data	(CamelIMAPXJob *job,
+						 gpointer data,
+						 GDestroyNotify destroy_data);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_JOB_H */
+
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index 0781b64..493bba8 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -23,7 +23,6 @@
 
 #include <time.h>
 #include <errno.h>
-#include <string.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
@@ -35,13 +34,16 @@
 #include <prerror.h>
 #include <prerr.h>
 
-#include "camel-imapx-utils.h"
-#include "camel-imapx-stream.h"
 #include "camel-imapx-server.h"
+
+#include "camel-imapx-command.h"
 #include "camel-imapx-folder.h"
+#include "camel-imapx-job.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-store.h"
+#include "camel-imapx-stream.h"
 #include "camel-imapx-summary.h"
+#include "camel-imapx-utils.h"
 
 #ifdef G_OS_WIN32
 #include <winsock2.h>
@@ -59,8 +61,6 @@
 #define IDLE_LOCK(x) (g_mutex_lock((x)->idle_lock))
 #define IDLE_UNLOCK(x) (g_mutex_unlock((x)->idle_lock))
 
-/* All comms with server go here */
-
 /* Try pipelining fetch requests, 'in bits' */
 #define MULTI_SIZE (20480)
 
@@ -71,12 +71,90 @@
 
 extern gint camel_application_is_exiting;
 
-struct _uidset_state {
-	struct _CamelIMAPXEngine *ie;
-	gint entries, uids;
-	gint total, limit;
-	guint32 start;
-	guint32 last;
+/* 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 _ManageSubscriptionsData ManageSubscriptionsData;
+typedef struct _RenameFolderData RenameFolderData;
+typedef struct _CreateFolderData CreateFolderData;
+typedef struct _DeleteFolderData DeleteFolderData;
+
+struct _GetMessageData {
+	/* in: uid requested */
+	gchar *uid;
+	/* in/out: message content stream output */
+	CamelStream *stream;
+	/* working variables */
+	gsize body_offset;
+	gssize body_len;
+	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;
+	gboolean update_unseen;
+	struct _uidset_state uidset;
+	/* changes during refresh */
+	CamelFolderChangeInfo *changes;
+};
+
+struct _SyncChangesData {
+	CamelFolder *folder;
+	GPtrArray *changed_uids;
+	guint32 on_set;
+	guint32 off_set;
+	GArray *on_user; /* imapx_flag_change */
+	GArray *off_user;
+	gint unread_change;
+};
+
+struct _AppendMessageData {
+	gchar *path;
+	CamelMessageInfo *info;
+};
+
+struct _CopyMessagesData {
+	CamelFolder *dest;
+	GPtrArray *uids;
+	gboolean delete_originals;
+	gint index;
+	gint last_index;
+	struct _uidset_state uidset;
+};
+
+struct _ListData {
+	gchar *pattern;
+	guint32 flags;
+	gchar *ext;
+	GHashTable *folders;
+};
+
+struct _ManageSubscriptionsData {
+	gchar *folder_name;
+	gboolean subscribe;
+};
+
+struct _RenameFolderData {
+	gchar *old_folder_name;
+	gchar *new_folder_name;
+};
+
+struct _CreateFolderData {
+	gchar *folder_name;
+};
+
+struct _DeleteFolderData {
+	gchar *folder_name;
 };
 
 enum {
@@ -91,78 +169,10 @@ void imapx_uidset_init (struct _uidset_state *ss, gint total, gint limit);
 gint imapx_uidset_done (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic);
 gint imapx_uidset_add (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic, const gchar *uid);
 static gboolean imapx_command_idle_stop (CamelIMAPXServer *is, GError **error);
-static gint imapx_continuation (CamelIMAPXServer *imap, gboolean litplus, GCancellable *cancellable, GError **error);
+static gboolean imapx_continuation (CamelIMAPXServer *is, gboolean litplus, GCancellable *cancellable, GError **error);
 static gboolean imapx_disconnect (CamelIMAPXServer *is);
 static gint imapx_uid_cmp (gconstpointer ap, gconstpointer bp, gpointer data);
 
-typedef struct _CamelIMAPXCommandPart CamelIMAPXCommandPart;
-
-typedef enum {
-	CAMEL_IMAPX_COMMAND_SIMPLE = 0,
-	CAMEL_IMAPX_COMMAND_DATAWRAPPER,
-	CAMEL_IMAPX_COMMAND_STREAM,
-	CAMEL_IMAPX_COMMAND_AUTH,
-	CAMEL_IMAPX_COMMAND_FILE,
-	CAMEL_IMAPX_COMMAND_STRING,
-	CAMEL_IMAPX_COMMAND_MASK = 0xff,
-	CAMEL_IMAPX_COMMAND_LITERAL_PLUS = 0x4000, /* continuation with literal+ */
-	CAMEL_IMAPX_COMMAND_CONTINUATION = 0x8000 /* does this command expect continuation? */
-} camel_imapx_command_part_t;
-
-struct _CamelIMAPXCommandPart {
-	struct _CamelIMAPXCommandPart *next;
-	struct _CamelIMAPXCommandPart *prev;
-
-	struct _CamelIMAPXCommand *parent;
-
-	gint data_size;
-	gchar *data;
-
-	camel_imapx_command_part_t type;
-
-	gint ob_size;
-	gpointer ob;
-};
-
-typedef gint (*CamelIMAPXEngineFunc)(struct _CamelIMAPXServer *engine, guint32 id, gpointer data);
-typedef void (*CamelIMAPXCommandFunc)(struct _CamelIMAPXServer *engine, struct _CamelIMAPXCommand *);
-
-struct _CamelIMAPXCommand {
-	struct _CamelIMAPXCommand *next, *prev;
-
-	volatile gint ref_count;
-
-	CamelIMAPXServer *is;
-	gint pri;
-
-	const gchar *name;	/* command name/type (e.g. FETCH) */
-
-	CamelFolder *select;		/* folder to select */
-
-	struct _status_info *status; /* status for command, indicates it is complete if != NULL */
-
-	/* If exception is set, it means we were not able to parse above status, it might be
-	 * because user cancelled the operation or io error */
-	GCancellable *cancellable;
-	GError *error;
-
-	guint32 tag;
-
-	struct _CamelStreamMem *mem;	/* for building the part TOOD: just use a GString? */
-	CamelDList parts;
-	CamelIMAPXCommandPart *current;
-
-	/* used for running some commands syncronously */
-	gboolean run_sync_done;
-	GCond *run_sync_cond;
-	GMutex *run_sync_mutex;
-
-	/* responsible for free'ing the command */
-	CamelIMAPXCommandFunc complete;
-	struct _CamelIMAPXJob *job;
-};
-
-static void imapx_command_add (CamelIMAPXCommand *ic, const gchar *fmt, ...);
 static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
 
 /* states for the connection? */
@@ -224,101 +234,17 @@ struct _imapx_flag_change {
 	gchar *name;
 };
 
-typedef struct _CamelIMAPXJob CamelIMAPXJob;
-
-struct _CamelIMAPXJob {
-	volatile gint ref_count;
-
-	GCond *done_cond;
-	GMutex *done_mutex;
-	gboolean done_flag;
-
-	GCancellable *cancellable;
-	GError *error;
-	gboolean with_operation_msg;
-
-	void (*start)(CamelIMAPXServer *is, struct _CamelIMAPXJob *job);
-
-	guint noreply:1;	/* dont wait for reply */
-	guint32 type;		/* operation type */
-	gint pri;		/* the command priority */
-	gshort commands;	/* counts how many commands are outstanding */
-
-	CamelFolder *folder;
-
-	union {
-		struct {
-			/* in: uid requested */
-			gchar *uid;
-			/* in/out: message content stream output */
-			CamelStream *stream;
-			/* working variables */
-			gsize body_offset;
-			gssize body_len;
-			gsize fetch_offset;
-			gsize size;
-			gboolean use_multi_fetch;
-		} get_message;
-		struct {
-			/* array of refresh info's */
-			GArray *infos;
-			/* used for biulding uidset stuff */
-			gint index;
-			gint last_index;
-			gboolean update_unseen;
-			struct _uidset_state uidset;
-			/* changes during refresh */
-			CamelFolderChangeInfo *changes;
-		} refresh_info;
-		struct {
-			GPtrArray *changed_uids;
-			guint32 on_set;
-			guint32 off_set;
-			GArray *on_user; /* imapx_flag_change */
-			GArray *off_user;
-			gint unread_change;
-		} sync_changes;
-		struct {
-			gchar *path;
-			CamelMessageInfo *info;
-		} append_message;
-		struct {
-			CamelFolder *dest;
-			GPtrArray *uids;
-			gboolean delete_originals;
-			gint index;
-			gint last_index;
-			struct _uidset_state uidset;
-		} copy_messages;
-		struct {
-			gchar *pattern;
-			guint32 flags;
-			const gchar *ext;
-			GHashTable *folders;
-		} list;
-
-		struct {
-			const gchar *folder_name;
-			gboolean subscribe;
-		} manage_subscriptions;
-
-		struct {
-			const gchar *ofolder_name;
-			const gchar *nfolder_name;
-		} rename_folder;
-
-		const gchar *folder_name;
-	} u;
-};
-
 static CamelIMAPXJob *imapx_match_active_job (CamelIMAPXServer *is, guint32 type, const gchar *uid);
-static void imapx_job_done (CamelIMAPXServer *is, CamelIMAPXJob *job);
-static gboolean imapx_run_job (CamelIMAPXServer *is, CamelIMAPXJob *job, GError **error);
-static void imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job);
-static void imapx_command_copy_messages_step_done (CamelIMAPXServer *is, CamelIMAPXCommand *ic);
+static void imapx_job_fetch_new_messages_start (CamelIMAPXJob *job, CamelIMAPXServer *is);
 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, CamelFolder *folder, gint pri, GCancellable *cancellable, GError **error);
+static void imapx_sync_free_user (GArray *user_set);
+
+static void	imapx_command_copy_messages_step_start
+						(CamelIMAPXServer *is,
+						 CamelIMAPXJob *job,
+						 gint index);
 
 enum _idle_state {
 	IMAPX_IDLE_OFF,
@@ -367,6 +293,107 @@ static gboolean imapx_select (CamelIMAPXServer *is, CamelFolder *folder, gboolea
 
 G_DEFINE_TYPE (CamelIMAPXServer, camel_imapx_server, CAMEL_TYPE_OBJECT)
 
+static void
+get_message_data_free (GetMessageData *data)
+{
+	g_free (data->uid);
+
+	if (data->stream != NULL)
+		g_object_unref (data->stream);
+
+	g_slice_free (GetMessageData, data);
+}
+
+static void
+refresh_info_data_free (RefreshInfoData *data)
+{
+	camel_folder_change_info_free (data->changes);
+
+	g_slice_free (RefreshInfoData, data);
+}
+
+static void
+sync_changes_data_free (SyncChangesData *data)
+{
+	if (data->folder != NULL) {
+		camel_folder_free_uids (data->folder, data->changed_uids);
+		g_object_unref (data->folder);
+	}
+
+	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);
+
+	camel_message_info_free (data->info);
+
+	g_slice_free (AppendMessageData, data);
+}
+
+static void
+copy_messages_data_free (CopyMessagesData *data)
+{
+	if (data->dest != NULL)
+		g_object_unref (data->dest);
+
+	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_free (data->ext);
+
+	g_hash_table_destroy (data->folders);
+
+	g_slice_free (ListData, data);
+}
+
+static void
+manage_subscriptions_data_free (ManageSubscriptionsData *data)
+{
+	g_free (data->folder_name);
+
+	g_slice_free (ManageSubscriptionsData, data);
+}
+
+static void
+rename_folder_data_free (RenameFolderData *data)
+{
+	g_free (data->old_folder_name);
+	g_free (data->new_folder_name);
+
+	g_slice_free (RenameFolderData, data);
+}
+
+static void
+create_folder_data_free (CreateFolderData *data)
+{
+	g_free (data->folder_name);
+
+	g_slice_free (CreateFolderData, data);
+}
+
+static void
+delete_folder_data_free (DeleteFolderData *data)
+{
+	g_free (data->folder_name);
+
+	g_slice_free (DeleteFolderData, data);
+}
+
 /*
   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)
@@ -392,7 +419,7 @@ imapx_uidset_done (struct _uidset_state *ss,
 	gint ret = 0;
 
 	if (ss->last != 0 && ss->last != ss->start) {
-		imapx_command_add (ic, ":%d", ss->last);
+		camel_imapx_command_add (ic, ":%d", ss->last);
 	}
 
 	ret = ss->last != 0;
@@ -422,18 +449,18 @@ imapx_uidset_add (struct _uidset_state *ss,
 
 	if (ss->last == 0) {
 		e(ic->is->tagprefix, " start\n");
-		imapx_command_add (ic, "%d", uidn);
+		camel_imapx_command_add (ic, "%d", uidn);
 		ss->entries++;
 		ss->start = uidn;
 	} else {
 		if (ss->last != uidn - 1) {
 			if (ss->last == ss->start) {
 				e(ic->is->tagprefix, " ,next\n");
-				imapx_command_add (ic, ",%d", uidn);
+				camel_imapx_command_add (ic, ",%d", uidn);
 				ss->entries++;
 			} else {
 				e(ic->is->tagprefix, " :range\n");
-				imapx_command_add (ic, ":%d,%d", ss->last, uidn);
+				camel_imapx_command_add (ic, ":%d,%d", ss->last, uidn);
 				ss->entries+=2;
 			}
 			ss->start = uidn;
@@ -452,489 +479,81 @@ imapx_uidset_add (struct _uidset_state *ss,
 	return 0;
 }
 
-static void
-imapx_command_add_part (CamelIMAPXCommand *ic,
-                        camel_imapx_command_part_t type,
-                        gpointer o)
-{
-	CamelIMAPXCommandPart *cp;
-	CamelStreamNull *null;
-	GByteArray *byte_array;
-	guint ob_size = 0;
-
-	/* TODO: literal+? */
-
-	switch (type & CAMEL_IMAPX_COMMAND_MASK) {
-	case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
-	case CAMEL_IMAPX_COMMAND_STREAM: {
-		CamelObject *ob = o;
-
-		/* TODO: seekable streams we could just seek to the end and back */
-		null = (CamelStreamNull *) camel_stream_null_new ();
-		if ( (type & CAMEL_IMAPX_COMMAND_MASK) == CAMEL_IMAPX_COMMAND_DATAWRAPPER) {
-			camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) ob, (CamelStream *) null, NULL, NULL);
-		} else {
-			g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
-			camel_stream_write_to_stream ((CamelStream *) ob, (CamelStream *) null, NULL, NULL);
-			g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
-		}
-		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
-		g_object_ref (ob);
-		ob_size = null->written;
-		g_object_unref (null);
-		break;
-	}
-	case CAMEL_IMAPX_COMMAND_AUTH: {
-		CamelObject *ob = o;
-
-		/* we presume we'll need to get additional data only if we're not authenticated yet */
-		g_object_ref (ob);
-		camel_stream_write_string (
-			(CamelStream *) ic->mem,
-			camel_sasl_get_mechanism (CAMEL_SASL (ob)),
-			NULL, NULL);
-		if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
-			type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
-		break;
-	}
-	case CAMEL_IMAPX_COMMAND_FILE: {
-		gchar *path = o;
-		struct stat st;
-
-		if (g_stat (path, &st) == 0) {
-			o = g_strdup (o);
-			ob_size = st.st_size;
-		} else
-			o = NULL;
-
-		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
-		break;
-	}
-	case CAMEL_IMAPX_COMMAND_STRING:
-		o = g_strdup (o);
-		ob_size = strlen (o);
-		type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
-		break;
-	default:
-		ob_size = 0;
-	}
-
-	if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
-		gchar *string;
-
-		if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
-			string = g_strdup_printf ("{%u+}", ob_size);
-		} else {
-			type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
-			type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
-			string = g_strdup_printf ("{%u}", ob_size);
-		}
-
-		camel_stream_write_string ((CamelStream *) ic->mem, string, NULL, NULL);
-
-		g_free (string);
-	}
-
-	byte_array = camel_stream_mem_get_byte_array (ic->mem);
-
-	cp = g_malloc0 (sizeof (*cp));
-	cp->type = type;
-	cp->ob_size = ob_size;
-	cp->ob = o;
-	cp->data_size = byte_array->len;
-	cp->data = g_malloc (cp->data_size + 1);
-	memcpy (cp->data, byte_array->data, cp->data_size);
-	cp->data[cp->data_size] = 0;
-
-	g_seekable_seek (G_SEEKABLE (ic->mem), 0, G_SEEK_SET, NULL, NULL);
-
-	/* FIXME: hackish? */
-	g_byte_array_set_size (byte_array, 0);
-
-	camel_dlist_addtail (&ic->parts, (CamelDListNode *) cp);
-}
-
-static void
-imapx_command_addv (CamelIMAPXCommand *ic,
-                    const gchar *fmt,
-                    va_list ap)
-{
-	const gchar *p, *ps, *start;
-	guchar c;
-	guint width;
-	gchar ch;
-	gint llong;
-	gchar *s;
-	gchar *P;
-	gint d;
-	glong l;
-	guint32 f;
-	CamelFlag *F;
-	CamelStream *S;
-	CamelDataWrapper *D;
-	CamelSasl *A;
-	gchar buffer[16];
-	CamelFolder *folder;
-	CamelStore *parent_store;
-	gchar *fname = NULL, *encoded = NULL;
-	const gchar *full_name;
-
-	c(ic->is->tagprefix, "adding command, fmt = '%s'\n", fmt);
-
-	p = fmt;
-	ps = fmt;
-	while (( c = *p++ )) {
-		switch (c) {
-		case '%':
-			if (*p == '%') {
-				camel_stream_write ((CamelStream *) ic->mem, ps, p - ps, ic->cancellable, NULL);
-				p++;
-				ps = p;
-			} else {
-				camel_stream_write ((CamelStream *) ic->mem, ps, p - ps - 1, ic->cancellable, NULL);
-				start = p - 1;
-				width = 0;
-				llong = 0;
-
-				do {
-					c = *p++;
-					if (c == '0')
-						;
-					else if ( c== '-')
-						;
-					else
-						break;
-				} while (c);
-
-				do {
-					// FIXME: ascii isdigit
-					if (isdigit (c))
-						width = width * 10 + (c - '0');
-					else
-						break;
-				} while ((c = *p++));
-
-				while (c == 'l') {
-					llong++;
-					c = *p++;
-				}
-
-				switch (c) {
-				case 'A': /* auth object - sasl auth, treat as special kind of continuation */
-					A = va_arg (ap, CamelSasl *);
-					imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_AUTH, A);
-					break;
-				case 'S': /* stream */
-					S = va_arg (ap, CamelStream *);
-					c(ic->is->tagprefix, "got stream '%p'\n", S);
-					imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STREAM, S);
-					break;
-				case 'D': /* datawrapper */
-					D = va_arg (ap, CamelDataWrapper *);
-					c(ic->is->tagprefix, "got data wrapper '%p'\n", D);
-					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);
-					imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
-					break;
-				case 't': /* token */
-					s = va_arg (ap, gchar *);
-					camel_stream_write ((CamelStream *) ic->mem, s, strlen (s), ic->cancellable, NULL);
-					break;
-				case 's': /* simple string */
-					s = va_arg (ap, gchar *);
-					c(ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (fmt, "LOGIN") ? "***" : s);
-				output_string:
-					if (*s) {
-						guchar mask = imapx_is_mask (s);
-
-						if (mask & IMAPX_TYPE_ATOM_CHAR)
-							camel_stream_write ((CamelStream *) ic->mem, s, strlen (s), ic->cancellable, NULL);
-						else if (mask & IMAPX_TYPE_TEXT_CHAR) {
-							camel_stream_write((CamelStream *)ic->mem, "\"", 1, ic->cancellable, NULL);
-							while (*s) {
-								gchar *start = s;
-
-								while (*s && imapx_is_quoted_char (*s))
-									s++;
-								camel_stream_write ((CamelStream *) ic->mem, start, s - start, ic->cancellable, NULL);
-								if (*s) {
-									camel_stream_write((CamelStream *)ic->mem, "\\", 1, ic->cancellable, NULL);
-									camel_stream_write ((CamelStream *) ic->mem, s, 1, ic->cancellable, NULL);
-									s++;
-								}
-							}
-							camel_stream_write((CamelStream *)ic->mem, "\"", 1, ic->cancellable, NULL);
-						} else {
-							imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STRING, s);
-						}
-					} else {
-						camel_stream_write((CamelStream *)ic->mem, "\"\"", 2, ic->cancellable, NULL);
-					}
-					if (encoded) {
-						g_free (encoded);
-						encoded = NULL;
-					}
-					break;
-				case 'f': /* imap folder name */
-					folder = va_arg (ap, CamelFolder *);
-					full_name = camel_folder_get_full_name (folder);
-					c(ic->is->tagprefix, "got folder '%s'\n", full_name);
-					parent_store = camel_folder_get_parent_store (folder);
-					fname = camel_imapx_store_summary_full_from_path (((CamelIMAPXStore *) parent_store)->summary, full_name);
-					if (fname) {
-						encoded = camel_utf8_utf7 (fname);
-						g_free (fname);
-					} else
-						encoded = camel_utf8_utf7 (full_name);
-
-					if (encoded) {
-						s = encoded;
-						goto output_string;
-					} else
-						camel_stream_write((CamelStream *)ic->mem, "\"\"", 2, ic->cancellable, NULL);
-
-					break;
-				case 'F': /* IMAP flags set */
-					f = va_arg (ap, guint32);
-					F = va_arg (ap, CamelFlag *);
-					imapx_write_flags ((CamelStream *) ic->mem, f, F, ic->cancellable, NULL);
-					break;
-				case 'c':
-					d = va_arg (ap, gint);
-					ch = d;
-					camel_stream_write ((CamelStream *) ic->mem, &ch, 1, ic->cancellable, NULL);
-					break;
-				case 'd': /* int/unsigned */
-				case 'u':
-					if (llong == 1) {
-						gchar *string;
-						l = va_arg (ap, glong);
-						c(ic->is->tagprefix, "got glong '%d'\n", (gint)l);
-						memcpy (buffer, start, p - start);
-						buffer[p - start] = 0;
-						string = g_strdup_printf (buffer, l);
-						camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
-						g_free (string);
-					} else if (llong == 2) {
-						gchar *string;
-						guint64 i64 = va_arg (ap, guint64);
-						c(ic->is->tagprefix, "got guint64 '%d'\n", (gint)i64);
-						memcpy (buffer, start, p - start);
-						buffer[p - start] = 0;
-						string = g_strdup_printf (buffer, i64);
-						camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
-						g_free (string);
-					} else {
-						gchar *string;
-						d = va_arg (ap, gint);
-						c(ic->is->tagprefix, "got gint '%d'\n", d);
-						memcpy (buffer, start, p - start);
-						buffer[p - start] = 0;
-						string = g_strdup_printf (buffer, d);
-						camel_stream_write_string ((CamelStream *) ic->mem, string, ic->cancellable, NULL);
-						g_free (string);
-					}
-					break;
-				}
-
-				ps = p;
-			}
-			break;
-		case '\\':	/* only for \\ really, we dont support \n\r etc at all */
-			c = *p;
-			if (c) {
-				g_assert (c == '\\');
-				camel_stream_write ((CamelStream *) ic->mem, ps, p - ps, ic->cancellable, NULL);
-				p++;
-				ps = p;
-			}
-		}
-	}
-
-	camel_stream_write ((CamelStream *) ic->mem, ps, p - ps - 1, ic->cancellable, NULL);
-}
-
-static CamelIMAPXCommand *
-imapx_command_new (CamelIMAPXServer *is,
-                   const gchar *name,
-                   CamelFolder *select,
-                   GCancellable *cancellable,
-                   const gchar *fmt, ...)
-{
-	CamelIMAPXCommand *ic;
-	static gint tag = 0;
-	va_list ap;
-
-	if (cancellable != NULL)
-		g_object_ref (cancellable);
-
-	ic = g_slice_new0 (CamelIMAPXCommand);
-	ic->ref_count = 1;
-	ic->tag = tag++;
-	ic->name = name;
-	ic->mem = (CamelStreamMem *) camel_stream_mem_new ();
-	ic->select = select;
-	ic->cancellable = cancellable;
-	ic->is = is;
-	camel_dlist_init (&ic->parts);
-
-	if (fmt && fmt[0]) {
-		va_start (ap, fmt);
-		imapx_command_addv (ic, fmt, ap);
-		va_end (ap);
-	}
-
-	return ic;
-}
-
-static void
-imapx_command_add (CamelIMAPXCommand *ic,
-                   const gchar *fmt,
-                   ...)
-{
-	va_list ap;
-
-	g_assert (ic->mem);	/* gets reset on queue */
-
-	if (fmt && fmt[0]) {
-		va_start (ap, fmt);
-		imapx_command_addv (ic, fmt, ap);
-		va_end (ap);
-	}
-}
-
-static CamelIMAPXCommand *
-imapx_command_ref (CamelIMAPXCommand *ic)
-{
-	g_return_val_if_fail (ic != NULL, NULL);
-	g_return_val_if_fail (ic->ref_count > 0, NULL);
-
-	g_atomic_int_inc (&ic->ref_count);
-
-	return ic;
-}
-
-static void
-imapx_command_unref (CamelIMAPXCommand *ic)
-{
-	g_return_if_fail (ic != NULL);
-	g_return_if_fail (ic->ref_count > 0);
-
-	if (g_atomic_int_dec_and_test (&ic->ref_count)) {
-		CamelIMAPXCommandPart *cp;
-
-		if (ic->mem != NULL)
-			g_object_unref (ic->mem);
-
-		imapx_free_status (ic->status);
-
-		while ((cp = ((CamelIMAPXCommandPart *) camel_dlist_remhead (&ic->parts)))) {
-			g_free (cp->data);
-			if (cp->ob) {
-				switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
-				case CAMEL_IMAPX_COMMAND_FILE:
-				case CAMEL_IMAPX_COMMAND_STRING:
-					g_free (cp->ob);
-					break;
-				default:
-					g_object_unref (cp->ob);
-				}
-			}
-			g_free (cp);
-		}
-
-		if (ic->cancellable != NULL)
-			g_object_unref (ic->cancellable);
-
-		/* 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. */
-
-		g_slice_free (CamelIMAPXCommand, ic);
-	}
-}
-
-static void
-imapx_command_close (CamelIMAPXCommand *ic)
-{
-	if (ic->mem) {
-		GByteArray *byte_array;
-
-		byte_array = camel_stream_mem_get_byte_array (ic->mem);
-
-		if (byte_array->len > 5 && g_ascii_strncasecmp ((const gchar *) byte_array->data, "LOGIN", 5)) {
-			c(ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", byte_array->len);
-		} else {
-			c(ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", byte_array->len, (gint)byte_array->len, byte_array->data);
-		}
-		if (byte_array->len > 0)
-			imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
-
-		g_object_unref (ic->mem);
-		ic->mem = NULL;
-	}
-}
-
 /* Must hold QUEUE_LOCK */
 static gboolean
-imapx_command_start (CamelIMAPXServer *imap,
-                     CamelIMAPXCommand *ic)
+imapx_command_start (CamelIMAPXServer *is,
+                     CamelIMAPXCommand *ic,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 	CamelIMAPXCommandPart *cp;
+	gboolean cp_continuation;
+	gboolean cp_literal_plus;
+	GList *head;
 	gint retval;
 
-	imapx_command_close (ic);
-	cp = (CamelIMAPXCommandPart *) ic->parts.head;
-	g_assert (cp->next);
-	ic->current = cp;
+	camel_imapx_command_close (ic);
+
+	head = g_queue_peek_head_link (&ic->parts);
+	g_return_val_if_fail (head != NULL, FALSE);
+	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->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS))
-		imap->literal = ic;
+	if (cp_continuation || cp_literal_plus)
+		is->literal = ic;
 
-	camel_dlist_addtail (&imap->active, (CamelDListNode *) ic);
+	g_queue_push_tail (&is->active, ic);
 
-	g_static_rec_mutex_lock (&imap->ostream_lock);
+	g_static_rec_mutex_lock (&is->ostream_lock);
 
-	c(imap->tagprefix, "Starting command (active=%d,%s) %c%05u %s\r\n", camel_dlist_length(&imap->active), imap->literal?" literal":"", imap->tagprefix, ic->tag, cp->data && g_str_has_prefix (cp->data, "LOGIN") ? "LOGIN..." : cp->data);
-	if (imap->stream != NULL) {
+	c(is->tagprefix, "Starting command (active=%d,%s) %c%05u %s\r\n", g_queue_get_length (&is->active), is->literal?" literal":"", is->tagprefix, ic->tag, cp->data && g_str_has_prefix (cp->data, "LOGIN") ? "LOGIN..." : cp->data);
+	if (is->stream != NULL) {
 		gchar *string;
 
-		string = g_strdup_printf ("%c%05u %s\r\n", imap->tagprefix, ic->tag, cp->data);
-		retval = camel_stream_write_string ((CamelStream *) imap->stream, string, ic->cancellable, NULL);
+		string = g_strdup_printf ("%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
+		retval = camel_stream_write_string ((CamelStream *) is->stream, string, cancellable, NULL);
 		g_free (string);
 	} else
 		retval = -1;
 	if (retval == -1) {
 		g_set_error (
-			&ic->error, CAMEL_IMAPX_ERROR, 1,
+			error, CAMEL_IMAPX_ERROR, 1,
 			"Failed to issue the command");
-	err:
-		g_static_rec_mutex_unlock (&imap->ostream_lock);
-
-		camel_dlist_remove ((CamelDListNode *) ic);
-		if (ic && ic->complete)
-			ic->complete (imap, ic);
-		return FALSE;
+		goto err;
 	}
-	while (imap->literal == ic &&
-	       ic->current->type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
+	while (is->literal == ic && cp_literal_plus) {
 		/* Sent LITERAL+ continuation immediately */
-		if (!imapx_continuation (imap, TRUE, ic->cancellable, &ic->error))
+		if (!imapx_continuation (is, TRUE, cancellable, error))
 			goto err;
 	}
 
-	g_static_rec_mutex_unlock (&imap->ostream_lock);
+	g_static_rec_mutex_unlock (&is->ostream_lock);
 
 	return TRUE;
+
+err:
+	g_static_rec_mutex_unlock (&is->ostream_lock);
+
+	g_queue_remove (&is->active, ic);
+
+	/* Send a NULL GError since we've already set a
+	 * GError to get here, and we're not interested
+	 * in individual command errors. */
+	if (ic != NULL && ic->complete != NULL)
+		ic->complete (is, ic, NULL);
+
+	return FALSE;
 }
 
-static gboolean duplicate_fetch_or_refresh (CamelIMAPXServer *is, CamelIMAPXCommand *ic)
+static gboolean
+duplicate_fetch_or_refresh (CamelIMAPXServer *is,
+                            CamelIMAPXCommand *ic)
 {
 	if (!ic->job)
 		return FALSE;
@@ -949,6 +568,7 @@ static gboolean duplicate_fetch_or_refresh (CamelIMAPXServer *is, CamelIMAPXComm
 
 	return FALSE;
 }
+
 /* See if we can start another task yet.
  *
  * If we're waiting for a literal, we cannot proceed.
@@ -972,9 +592,8 @@ imapx_command_start_next (CamelIMAPXServer *is,
                           GCancellable *cancellable,
                           GError **error)
 {
-	CamelIMAPXCommand *ic, *nc;
-	gint count = 0;
-	gint pri = -128;
+	CamelIMAPXCommand *first_ic;
+	gint min_pri = -128;
 
 	c(is->tagprefix, "** Starting next command\n");
 	if (is->literal) {
@@ -983,33 +602,48 @@ imapx_command_start_next (CamelIMAPXServer *is,
 	}
 
 	if (is->select_pending) {
+		GQueue start = G_QUEUE_INIT;
+		GList *head, *link;
+
 		c(is->tagprefix, "-- Checking job queue for non-folder jobs\n");
-		ic = (CamelIMAPXCommand *) is->queue.head;
-		nc = ic->next;
-		while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+
+		head = g_queue_peek_head_link (&is->queue);
+
+		/* Tag which commands in the queue to start. */
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			CamelIMAPXCommand *ic = link->data;
+
+			if (ic->pri < min_pri)
+				break;
+
 			c(is->tagprefix, "-- %3d '%s'?\n", (gint)ic->pri, ic->name);
 			if (!ic->select) {
 				c(is->tagprefix, "--> starting '%s'\n", ic->name);
-				pri = ic->pri;
-				camel_dlist_remove ((CamelDListNode *) ic);
-				imapx_command_start (is, ic);
-				count++;
+				min_pri = ic->pri;
+				g_queue_push_tail (&start, link);
 			}
-			ic = nc;
-			nc = nc->next;
+
+			if (g_queue_get_length (&start) == MAX_COMMANDS)
+				break;
 		}
 
-		if (count)
-			return;
+		if (g_queue_is_empty (&start))
+			c(is->tagprefix, "* no, waiting for pending select '%s'\n", camel_folder_get_full_name (is->select_pending));
+
+		/* Start the tagged commands. */
+		while ((link = g_queue_pop_head (&start)) != NULL) {
+			CamelIMAPXCommand *ic = link->data;
+			g_queue_delete_link (&is->queue, link);
+			imapx_command_start (is, ic, cancellable, error);
+		}
 
-		c(is->tagprefix, "* no, waiting for pending select '%s'\n", camel_folder_get_full_name (is->select_pending));
 		return;
 	}
 
 	if (imapx_idle_supported (is) && is->state == IMAPX_SELECTED) {
 		gboolean empty = imapx_is_command_queue_empty (is);
 
-		if (imapx_in_idle (is) && !camel_dlist_empty (&is->queue)) {
+		if (imapx_in_idle (is) && !g_queue_is_empty (&is->queue)) {
 			/* if imapx_stop_idle() returns FALSE, it was only
 			 * pending and we can go ahead and send a new command
 			 * immediately. If it returns TRUE, either it sent the
@@ -1026,78 +660,122 @@ imapx_command_start_next (CamelIMAPXServer *is,
 		}
 	}
 
-	ic = (CamelIMAPXCommand *) is->queue.head;
-	nc = ic->next;
-	if (nc == NULL) {
+	if (g_queue_is_empty (&is->queue)) {
 		c(is->tagprefix, "* no, no jobs\n");
 		return;
 	}
 
 	/* See if any queued jobs on this select first */
 	if (is->select_folder) {
+		GQueue start = G_QUEUE_INIT;
+		GList *head, *link;
+		gboolean commands_started = FALSE;
+
 		c(is->tagprefix, "- we're selected on '%s', current jobs?\n",
 		  camel_folder_get_full_name (is->select_folder));
-		for (ic = (CamelIMAPXCommand *) is->active.head; ic->next; ic = ic->next) {
+
+		head = g_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 (ic->pri > pri)
-				pri = ic->pri;
-			count++;
-			if (count > MAX_COMMANDS) {
-				c(is->tagprefix, "** too many jobs busy, waiting for results for now\n");
-				return;
-			}
+		}
+
+		if (g_queue_get_length (&is->active) >= MAX_COMMANDS) {
+			c(is->tagprefix, "** too many jobs busy, waiting for results for now\n");
+			return;
 		}
 
 		c(is->tagprefix, "-- Checking job queue\n");
-		count = 0;
-		ic = (CamelIMAPXCommand *) is->queue.head;
-		nc = ic->next;
-		while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+
+		head = g_queue_peek_head_link (&is->queue);
+
+		/* Tag which commands in the queue to start. */
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			CamelIMAPXCommand *ic = link->data;
+
+			if (is->literal != NULL)
+				break;
+
+			if (ic->pri < min_pri)
+				break;
+
 			c(is->tagprefix, "-- %3d '%s'?\n", (gint)ic->pri, ic->name);
 			if (!ic->select || ((ic->select == is->select_folder) &&
 					    !duplicate_fetch_or_refresh (is, ic))) {
 				c(is->tagprefix, "--> starting '%s'\n", ic->name);
-				pri = ic->pri;
-				camel_dlist_remove ((CamelDListNode *) ic);
-				imapx_command_start (is, ic);
-				count++;
+				min_pri = ic->pri;
+				g_queue_push_tail (&start, link);
 			} else {
 				/* This job isn't for the selected folder, but we don't want to
 				 * consider jobs with _lower_ priority than this, even if they
 				 * are for the selected folder. */
-				pri = ic->pri;
+				min_pri = ic->pri;
 			}
-			ic = nc;
-			nc = nc->next;
+
+			if (g_queue_get_length (&start) == MAX_COMMANDS)
+				break;
 		}
 
-		if (count)
-			return;
+		/* Start the tagged commands. */
+		while ((link = g_queue_pop_head (&start)) != NULL) {
+			CamelIMAPXCommand *ic = link->data;
+			g_queue_delete_link (&is->queue, link);
+			imapx_command_start (is, ic, cancellable, error);
+			commands_started = TRUE;
+		}
 
-		ic = (CamelIMAPXCommand *) is->queue.head;
+		if (commands_started)
+			return;
 	}
 
-	/* If we need to select a folder for the first command, do it now, once
-	 * it is complete it will re-call us if it succeeded */
-	if (ic->select) {
+	/* This won't be NULL because we checked for an empty queue above. */
+	first_ic = g_queue_peek_head (&is->queue);
+
+	/* If we need to select a folder for the first command, do it now,
+	 * once it is complete it will re-call us if it succeeded. */
+	if (first_ic->select) {
 		c(is->tagprefix, "Selecting folder '%s' for command '%s'(%p)\n",
-		  camel_folder_get_full_name (ic->select), ic->name, ic);
-		imapx_select (is, ic->select, FALSE, cancellable, error);
+		  camel_folder_get_full_name (first_ic->select),
+		  first_ic->name, first_ic);
+		imapx_select (is, first_ic->select, FALSE, cancellable, error);
 	} else {
-		pri = ic->pri;
-		nc = ic->next;
-		count = 0;
-		while (nc && is->literal == NULL && count < MAX_COMMANDS && ic->pri >= pri) {
+		GQueue start = G_QUEUE_INIT;
+		GList *head, *link;
+
+		min_pri = first_ic->pri;
+
+		head = g_queue_peek_head_link (&is->queue);
+
+		/* Tag which commands in the queue to start. */
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			CamelIMAPXCommand *ic = link->data;
+
+			if (is->literal != NULL)
+				break;
+
+			if (ic->pri < min_pri)
+				break;
+
 			if (!ic->select || (ic->select == is->select_folder &&
 					    !duplicate_fetch_or_refresh (is, ic))) {
 				c(is->tagprefix, "* queueing job %3d '%s'\n", (gint)ic->pri, ic->name);
-				pri = ic->pri;
-				camel_dlist_remove ((CamelDListNode *) ic);
-				imapx_command_start (is, ic);
-				count++;
+				min_pri = ic->pri;
+				g_queue_push_tail (&start, link);
 			}
-			ic = nc;
-			nc = nc->next;
+
+			if (g_queue_get_length (&start) == MAX_COMMANDS)
+				break;
+		}
+
+		/* Start the tagged commands. */
+		while ((link = g_queue_pop_head (&start)) != NULL) {
+			CamelIMAPXCommand *ic = link->data;
+			g_queue_delete_link (&is->queue, link);
+			imapx_command_start (is, ic, cancellable, error);
 		}
 	}
 }
@@ -1105,57 +783,49 @@ imapx_command_start_next (CamelIMAPXServer *is,
 static gboolean
 imapx_is_command_queue_empty (CamelIMAPXServer *is)
 {
-	gboolean ret = FALSE;
+	if (!g_queue_is_empty (&is->queue))
+		return FALSE;
 
-	if (camel_dlist_empty (&is->queue) && camel_dlist_empty (&is->active))
-		ret = TRUE;
+	if (!g_queue_is_empty (&is->active))
+		return FALSE;
 
-	return ret;
+	return TRUE;
 }
 
 static void
 imapx_command_queue (CamelIMAPXServer *is,
                      CamelIMAPXCommand *ic)
 {
-	CamelIMAPXCommand *scan;
-
 	/* We enqueue in priority order, new messages have
 	 * higher priority than older messages with the same priority */
 
-	imapx_command_close (ic);
+	camel_imapx_command_close (ic);
 
-	c(is->tagprefix, "enqueue job '%.*s'\n", ((CamelIMAPXCommandPart *)ic->parts.head)->data_size, ((CamelIMAPXCommandPart *)ic->parts.head)->data);
+	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) {
 		c(is->tagprefix, "refuse to queue job on disconnected server\n");
-		g_set_error (
-			&ic->error, CAMEL_IMAPX_ERROR, 1,
-			"Server disconnected");
+		if (ic->job->error == NULL)
+			g_set_error (
+				&ic->job->error, CAMEL_IMAPX_ERROR, 1,
+				"%s", _("Server disconnected"));
 		QUEUE_UNLOCK (is);
-		if (ic->complete)
-			ic->complete (is, ic);
+
+		/* Send a NULL GError since we've already set
+		 * the job's GError, and we're not interested
+		 * in individual command errors. */
+		if (ic->complete != NULL)
+			ic->complete (is, ic, NULL);
 		return;
 	}
 
-	scan = (CamelIMAPXCommand *) is->queue.head;
-	if (scan->next == NULL)
-		camel_dlist_addtail (&is->queue, (CamelDListNode *) ic);
-	else {
-		while (scan->next) {
-			if (ic->pri >= scan->pri)
-				break;
-			scan = scan->next;
-		}
+	g_queue_insert_sorted (
+		&is->queue, ic, (GCompareDataFunc)
+		camel_imapx_command_compare, NULL);
 
-		scan->prev->next = ic;
-		ic->next = scan;
-		ic->prev = scan->prev;
-		scan->prev = ic;
-	}
-
-	imapx_command_start_next (is, ic->cancellable, NULL);
+	imapx_command_start_next (is, ic->job->cancellable, NULL);
 
 	QUEUE_UNLOCK (is);
 
@@ -1164,54 +834,34 @@ imapx_command_queue (CamelIMAPXServer *is,
 
 /* Must have QUEUE lock */
 static CamelIMAPXCommand *
-imapx_find_command_tag (CamelIMAPXServer *imap,
+imapx_find_command_tag (CamelIMAPXServer *is,
                         guint tag)
 {
 	CamelIMAPXCommand *ic = NULL;
+	GList *head, *link;
 
-	QUEUE_LOCK (imap);
-
-	ic = imap->literal;
-	if (ic && ic->tag == tag)
-		goto found;
-
-	for (ic = (CamelIMAPXCommand *) imap->active.head; ic->next; ic = ic->next)
-		if (ic->tag == tag)
-			goto found;
+	QUEUE_LOCK (is);
 
-	/* Not found: force it to NULL otherwise we return the tail address */
-	ic = NULL;
+	if (is->literal != NULL && is->literal->tag == tag) {
+		ic = is->literal;
+		goto exit;
+	}
 
-found:
-	QUEUE_UNLOCK (imap);
+	head = g_queue_peek_head_link (&is->active);
 
-	return ic;
-}
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		CamelIMAPXCommand *candidate = link->data;
 
-static gboolean
-imapx_job_matches (CamelFolder *folder,
-                   CamelIMAPXJob *job,
-                   guint32 type,
-                   const gchar *uid)
-{
-	switch (job->type) {
-		case IMAPX_JOB_GET_MESSAGE:
-			if (folder == job->folder &&
-			    strcmp (job->u.get_message.uid, uid) == 0)
-				return TRUE;
-			break;
-		case IMAPX_JOB_FETCH_NEW_MESSAGES:
-		case IMAPX_JOB_REFRESH_INFO:
-		case IMAPX_JOB_SYNC_CHANGES:
-		case IMAPX_JOB_EXPUNGE:
-			if (folder == job->folder)
-				return TRUE;
+		if (candidate->tag == tag) {
+			ic = candidate;
 			break;
-		case IMAPX_JOB_LIST:
-			return TRUE;
+		}
 	}
 
-	return FALSE;
+exit:
+	QUEUE_UNLOCK (is);
+
+	return ic;
 }
 
 /* Must not have QUEUE lock */
@@ -1221,21 +871,29 @@ imapx_match_active_job (CamelIMAPXServer *is,
                         const gchar *uid)
 {
 	CamelIMAPXJob *job = NULL;
-	CamelIMAPXCommand *ic;
+	GList *head, *link;
 
 	QUEUE_LOCK (is);
 
-	for (ic = (CamelIMAPXCommand *) is->active.head; ic->next; ic = ic->next) {
-		job = ic->job;
-		if (!job || !(job->type & type))
+	head = g_queue_peek_head_link (&is->active);
+
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		CamelIMAPXCommand *ic = link->data;
+
+		if (ic->job == NULL)
+			continue;
+
+		if (!(ic->job->type & type))
 			continue;
 
-		if (imapx_job_matches (is->select_folder, job, type, uid))
-			goto found;
+		if (camel_imapx_job_matches (ic->job, is->select_folder, uid)) {
+			job = ic->job;
+			break;
+		}
 	}
-	job = NULL;
-found:
+
 	QUEUE_UNLOCK (is);
+
 	return job;
 }
 
@@ -1259,7 +917,7 @@ imapx_is_job_in_queue (CamelIMAPXServer *is,
 		if (!job || !(job->type & type))
 			continue;
 
-		if (imapx_job_matches (folder, job, type, uid)) {
+		if (camel_imapx_job_matches (job, folder, uid)) {
 			found = TRUE;
 			break;
 		}
@@ -1274,35 +932,35 @@ imapx_is_job_in_queue (CamelIMAPXServer *is,
 }
 
 static void
-imapx_expunge_uid_from_summary (CamelIMAPXServer *imap,
+imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
                                 gchar *uid,
                                 gboolean unsolicited)
 {
-	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) imap->select_folder;
+	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_folder;
 
 	if (unsolicited && ifolder->exists_on_server)
 		ifolder->exists_on_server--;
 
-	if (imap->changes == NULL)
-		imap->changes = camel_folder_change_info_new ();
+	if (is->changes == NULL)
+		is->changes = camel_folder_change_info_new ();
 
-	camel_folder_summary_remove_uid (imap->select_folder->summary, uid);
-	imap->expunged = g_list_prepend (imap->expunged, uid);
+	camel_folder_summary_remove_uid (is->select_folder->summary, uid);
+	is->expunged = g_list_prepend (is->expunged, uid);
 
-	camel_folder_change_info_remove_uid (imap->changes, uid);
+	camel_folder_change_info_remove_uid (is->changes, uid);
 
-	if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
+	if (imapx_idle_supported (is) && imapx_in_idle (is)) {
 		const gchar *full_name;
 
-		full_name = camel_folder_get_full_name (imap->select_folder);
-		camel_db_delete_uids (imap->store->cdb_w, full_name, imap->expunged, NULL);
-		imapx_update_store_summary (imap->select_folder);
-		camel_folder_changed (imap->select_folder, imap->changes);
+		full_name = camel_folder_get_full_name (is->select_folder);
+		camel_db_delete_uids (is->store->cdb_w, full_name, is->expunged, NULL);
+		imapx_update_store_summary (is->select_folder);
+		camel_folder_changed (is->select_folder, is->changes);
+
+		g_list_free_full (is->expunged, (GDestroyNotify) g_free);
+		is->expunged = NULL;
 
-		g_list_foreach (imap->expunged, (GFunc) g_free, NULL);
-		g_list_free (imap->expunged);
-		imap->expunged = NULL;
-		camel_folder_change_info_clear (imap->changes);
+		camel_folder_change_info_clear (is->changes);
 	}
 }
 
@@ -1366,8 +1024,8 @@ invalidate_local_cache (CamelIMAPXFolder *ifolder,
 }
 
 /* handle any untagged responses */
-static gint
-imapx_untagged (CamelIMAPXServer *imap,
+static gboolean
+imapx_untagged (CamelIMAPXServer *is,
                 GCancellable *cancellable,
                 GError **error)
 {
@@ -1380,63 +1038,63 @@ imapx_untagged (CamelIMAPXServer *imap,
 	gboolean lsub = FALSE;
 	struct _status_info *sinfo;
 
-	service = CAMEL_SERVICE (imap->store);
+	service = CAMEL_SERVICE (is->store);
 	settings = camel_service_get_settings (service);
 
 	fetch_order = camel_imapx_settings_get_fetch_order (
 		CAMEL_IMAPX_SETTINGS (settings));
 
-	e(imap->tagprefix, "got untagged response\n");
+	e(is->tagprefix, "got untagged response\n");
 	id = 0;
-	tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+	tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
 	if (tok < 0)
-		return -1;
+		return FALSE;
 
 	if (tok == IMAPX_TOK_INT) {
 		id = strtoul ((gchar *) token, NULL, 10);
-		tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+		tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
 		if (tok < 0)
-			return -1;
+			return FALSE;
 	}
 
 	if (tok == '\n') {
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"truncated server response");
-		return -1;
+		return FALSE;
 	}
 
-	e(imap->tagprefix, "Have token '%s' id %d\n", token, id);
+	e(is->tagprefix, "Have token '%s' id %d\n", token, id);
 	p = token;
 	while ((c = *p))
 		*p++ = toupper((gchar) c);
 
 	switch (imapx_tokenise ((const gchar *) token, len)) {
 	case IMAPX_CAPABILITY:
-		if (imap->cinfo)
-			imapx_free_capability (imap->cinfo);
-		imap->cinfo = imapx_parse_capability (imap->stream, cancellable, error);
-		if (imap->cinfo == NULL)
-			return -1;
-		c(imap->tagprefix, "got capability flags %08x\n", imap->cinfo->capa);
-		return 0;
+		if (is->cinfo)
+			imapx_free_capability (is->cinfo);
+		is->cinfo = imapx_parse_capability (is->stream, cancellable, error);
+		if (is->cinfo == NULL)
+			return FALSE;
+		c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
+		return TRUE;
 	case IMAPX_EXPUNGE: {
 		guint32 expunge = id;
-		CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_EXPUNGE, NULL);
+		CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_EXPUNGE, NULL);
 
 		/* If there is a job running, let it handle the deletion */
 		if (job)
 			break;
 
-		c(imap->tagprefix, "expunged: %d\n", id);
-		if (imap->select_folder) {
+		c(is->tagprefix, "expunged: %d\n", id);
+		if (is->select_folder) {
 			gchar *uid = NULL;
 
-			uid = imapx_get_uid_from_index (imap->select_folder->summary, expunge - 1);
+			uid = imapx_get_uid_from_index (is->select_folder->summary, expunge - 1);
 			if (!uid)
 				break;
 
-			imapx_expunge_uid_from_summary (imap, uid, TRUE);
+			imapx_expunge_uid_from_summary (is, uid, TRUE);
 		}
 
 		break;
@@ -1449,27 +1107,27 @@ imapx_untagged (CamelIMAPXServer *imap,
 		guchar *token;
 		gint tok;
 
-		tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+		tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
 		if (tok < 0)
-			return -1;
+			return FALSE;
 		if (tok == '(') {
 			unsolicited = FALSE;
 			while (tok != ')') {
 				/* We expect this to be 'EARLIER' */
-				tok = camel_imapx_stream_token (imap->stream, &token, &len, cancellable, error);
+				tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
 				if (tok < 0)
-					return -1;
+					return FALSE;
 			}
 		} else
-			camel_imapx_stream_ungettoken (imap->stream, tok, token, len);
+			camel_imapx_stream_ungettoken (is->stream, tok, token, len);
 
-		uids = imapx_parse_uids (imap->stream, cancellable, error);
+		uids = imapx_parse_uids (is->stream, cancellable, error);
 		if (uids == NULL)
-			return -1;
+			return FALSE;
 		for (i = 0; i < uids->len; i++) {
 			gchar *uid = g_strdup_printf("%u", GPOINTER_TO_UINT(g_ptr_array_index (uids, i)));
-			c(imap->tagprefix, "vanished: %s\n", uid);
-			imapx_expunge_uid_from_summary (imap, uid, unsolicited);
+			c(is->tagprefix, "vanished: %s\n", uid);
+			imapx_expunge_uid_from_summary (is, uid, unsolicited);
 		}
 		g_ptr_array_free (uids, FALSE);
 		break;
@@ -1477,9 +1135,9 @@ imapx_untagged (CamelIMAPXServer *imap,
 	case IMAPX_NAMESPACE: {
 		CamelIMAPXNamespaceList *nsl = NULL;
 
-		nsl = imapx_parse_namespace_list (imap->stream, cancellable, error);
+		nsl = imapx_parse_namespace_list (is->stream, cancellable, error);
 		if (nsl != NULL) {
-			CamelIMAPXStore *imapx_store = (CamelIMAPXStore *) imap->store;
+			CamelIMAPXStore *imapx_store = (CamelIMAPXStore *) is->store;
 			CamelIMAPXStoreNamespace *ns;
 
 			imapx_store->summary->namespaces = nsl;
@@ -1491,52 +1149,56 @@ imapx_untagged (CamelIMAPXServer *imap,
 				imapx_store->dir_sep = ns->sep;
 		}
 
-		return 0;
+		return TRUE;
 	}
 	case IMAPX_EXISTS:
-		c(imap->tagprefix, "exists: %d\n", id);
-		imap->exists = id;
+		c(is->tagprefix, "exists: %d\n", id);
+		is->exists = id;
 
-		if (imap->select_folder)
-			((CamelIMAPXFolder *) imap->select_folder)->exists_on_server = id;
+		if (is->select_folder)
+			((CamelIMAPXFolder *) is->select_folder)->exists_on_server = id;
 
-		if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
-			if (camel_folder_summary_count (imap->select_folder->summary) < id)
-				imapx_stop_idle (imap, error);
+		if (imapx_idle_supported (is) && imapx_in_idle (is)) {
+			if (camel_folder_summary_count (is->select_folder->summary) < id)
+				imapx_stop_idle (is, error);
 		}
 
 		break;
 	case IMAPX_FLAGS: {
 		guint32 flags;
 
-		imapx_parse_flags (imap->stream, &flags, NULL, cancellable, error);
+		imapx_parse_flags (is->stream, &flags, NULL, cancellable, error);
 
-		c(imap->tagprefix, "flags: %08x\n", flags);
+		c(is->tagprefix, "flags: %08x\n", flags);
 		break;
 	}
 	case IMAPX_FETCH: {
 		struct _fetch_info *finfo;
 
-		finfo = imapx_parse_fetch (imap->stream, cancellable, error);
+		finfo = imapx_parse_fetch (is->stream, cancellable, error);
 		if (finfo == NULL) {
 			imapx_free_fetch (finfo);
-			return -1;
+			return FALSE;
 		}
 
 		if ((finfo->got & (FETCH_BODY | FETCH_UID)) == (FETCH_BODY | FETCH_UID)) {
-			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_GET_MESSAGE, finfo->uid);
+			CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_GET_MESSAGE, finfo->uid);
+			GetMessageData *data;
+
+			data = camel_imapx_job_get_data (job);
+			g_return_val_if_fail (data != NULL, FALSE);
 
 			/* This must've been a get-message request, fill out the body stream,
 			 * in the right spot */
 
 			if (job && job->error == NULL) {
-				if (job->u.get_message.use_multi_fetch) {
-					job->u.get_message.body_offset = finfo->offset;
-					g_seekable_seek (G_SEEKABLE (job->u.get_message.stream), finfo->offset, G_SEEK_SET, NULL, NULL);
+				if (data->use_multi_fetch) {
+					data->body_offset = finfo->offset;
+					g_seekable_seek (G_SEEKABLE (data->stream), finfo->offset, G_SEEK_SET, NULL, NULL);
 				}
 
-				job->u.get_message.body_len = camel_stream_write_to_stream (finfo->body, job->u.get_message.stream, job->cancellable, &job->error);
-				if (job->u.get_message.body_len == -1)
+				data->body_len = camel_stream_write_to_stream (finfo->body, data->stream, job->cancellable, &job->error);
+				if (data->body_len == -1)
 					g_prefix_error (
 						&job->error,
 						_("Error writing to cache stream: "));
@@ -1544,31 +1206,35 @@ imapx_untagged (CamelIMAPXServer *imap,
 		}
 
 		if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
-			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
+			CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
 			/* 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 (job && (finfo->got & FETCH_UID)) {
+				RefreshInfoData *data;
 				struct _refresh_info r;
 
+				data = camel_imapx_job_get_data (job);
+				g_return_val_if_fail (data != NULL, FALSE);
+
 				r.uid = finfo->uid;
 				finfo->uid = NULL;
 				r.server_flags = finfo->flags;
 				r.server_user_flags = finfo->user_flags;
 				finfo->user_flags = NULL;
 				r.exists = FALSE;
-				g_array_append_val (job->u.refresh_info.infos, r);
-			} else if (imap->select_folder) {
+				g_array_append_val (data->infos, r);
+			} else if (is->select_folder) {
 				CamelFolder *folder;
 				CamelMessageInfo *mi = NULL;
 				gboolean changed = FALSE;
 				gchar *uid = NULL;
 
-				g_object_ref (imap->select_folder);
-				folder = imap->select_folder;
+				g_object_ref (is->select_folder);
+				folder = is->select_folder;
 
-				c(imap->tagprefix, "flag changed: %d\n", id);
+				c(is->tagprefix, "flag changed: %d\n", id);
 
 				if (finfo->got & FETCH_UID) {
 					uid = finfo->uid;
@@ -1580,30 +1246,30 @@ imapx_untagged (CamelIMAPXServer *imap,
 				if (uid) {
 					mi = camel_folder_summary_get (folder->summary, uid);
 					if (mi) {
-						/* It's unsolicited _unless_ imap->select_pending (i.e. during
+						/* It's unsolicited _unless_ is->select_pending (i.e. during
 						 * a QRESYNC SELECT */
-						changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, imap->permanentflags, folder, !imap->select_pending);
+						changed = imapx_update_message_info_flags (mi, finfo->flags, finfo->user_flags, is->permanentflags, folder, !is->select_pending);
 					} else {
 						/* This (UID + FLAGS for previously unknown message) might
 						 * happen during a SELECT (QRESYNC). We should use it. */
-						c(imap->tagprefix, "flags changed for unknown uid %s\n.", uid);
+						c(is->tagprefix, "flags changed for unknown uid %s\n.", uid);
 					}
 					finfo->user_flags = NULL;
 				}
 
 				if (changed) {
-					if (imap->changes == NULL)
-						imap->changes = camel_folder_change_info_new ();
+					if (is->changes == NULL)
+						is->changes = camel_folder_change_info_new ();
 
-					camel_folder_change_info_change_uid (imap->changes, uid);
+					camel_folder_change_info_change_uid (is->changes, uid);
 					g_free (uid);
 				}
 
-				if (imapx_idle_supported (imap) && changed && imapx_in_idle (imap)) {
-					camel_folder_summary_save_to_db (imap->select_folder->summary, NULL);
-					imapx_update_store_summary (imap->select_folder);
-					camel_folder_changed (imap->select_folder, imap->changes);
-					camel_folder_change_info_clear (imap->changes);
+				if (imapx_idle_supported (is) && changed && imapx_in_idle (is)) {
+					camel_folder_summary_save_to_db (is->select_folder->summary, NULL);
+					imapx_update_store_summary (is->select_folder);
+					camel_folder_changed (is->select_folder, is->changes);
+					camel_folder_change_info_clear (is->changes);
 				}
 
 				if (mi)
@@ -1613,7 +1279,7 @@ imapx_untagged (CamelIMAPXServer *imap,
 		}
 
 		if ((finfo->got & (FETCH_HEADER | FETCH_UID)) == (FETCH_HEADER | FETCH_UID)) {
-			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
+			CamelIMAPXJob *job = imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO, NULL);
 
 			/* This must be a refresh info job as well, but it has asked for
 			 * new messages to be added to the index */
@@ -1637,20 +1303,24 @@ imapx_untagged (CamelIMAPXServer *imap,
 
 					mi->uid = camel_pstring_strdup (finfo->uid);
 
-					if (!(finfo->got & FETCH_FLAGS))
-					{
+					if (!(finfo->got & FETCH_FLAGS)) {
+						RefreshInfoData *data;
 						struct _refresh_info *r = NULL;
-						GArray *infos = job->u.refresh_info.infos;
-						gint min = job->u.refresh_info.last_index;
-						gint max = job->u.refresh_info.index, mid;
+						gint min, max, mid;
 						gboolean found = FALSE;
 
+						data = camel_imapx_job_get_data (job);
+						g_return_val_if_fail (data != NULL, FALSE);
+
+						min = data->last_index;
+						max = data->index;
+
 						/* array is sorted, so use a binary search */
 						do {
 							gint cmp = 0;
 
 							mid = (min + max) / 2;
-							r = &g_array_index (infos, struct _refresh_info, mid);
+							r = &g_array_index (data->infos, struct _refresh_info, mid);
 							cmp = imapx_refresh_info_uid_cmp (finfo->uid, r->uid, fetch_order == CAMEL_SORT_ASCENDING);
 
 							if (cmp > 0)
@@ -1685,10 +1355,10 @@ imapx_untagged (CamelIMAPXServer *imap,
 						guint64 uidl = strtoull (mi->uid, NULL, 10);
 
 						if (uidl >= ifolder->uidnext_on_server) {
-							c(imap->tagprefix, "Updating unread count for new message %s\n", mi->uid);
+							c(is->tagprefix, "Updating unread count for new message %s\n", mi->uid);
 							((CamelIMAPXFolder *) job->folder)->unread_on_server++;
 						} else {
-							c(imap->tagprefix, "Not updating unread count for new message %s\n", mi->uid);
+							c(is->tagprefix, "Not updating unread count for new message %s\n", mi->uid);
 						}
 					}
 
@@ -1696,15 +1366,19 @@ imapx_untagged (CamelIMAPXServer *imap,
 					binfo->size = finfo->size;
 
 					if (!camel_folder_summary_check_uid (job->folder->summary, mi->uid)) {
+						RefreshInfoData *data;
 						CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
 						gint cnt;
 
+						data = camel_imapx_job_get_data (job);
+						g_return_val_if_fail (data != NULL, FALSE);
+
 						camel_folder_summary_add (job->folder->summary, mi);
 						imapx_set_message_info_flags_for_new_message (mi, server_flags, server_user_flags, job->folder);
-						camel_folder_change_info_add_uid (job->u.refresh_info.changes, mi->uid);
+						camel_folder_change_info_add_uid (data->changes, mi->uid);
 
 						if (!g_hash_table_lookup (ifolder->ignore_recent, mi->uid)) {
-							camel_folder_change_info_recent_uid (job->u.refresh_info.changes, mi->uid);
+							camel_folder_change_info_recent_uid (data->changes, mi->uid);
 							g_hash_table_remove (ifolder->ignore_recent, mi->uid);
 						}
 
@@ -1725,27 +1399,31 @@ imapx_untagged (CamelIMAPXServer *imap,
 	case IMAPX_LSUB:
 		lsub = TRUE;
 	case IMAPX_LIST: {
-		struct _list_info *linfo = imapx_parse_list (imap->stream, cancellable, error);
+		struct _list_info *linfo = imapx_parse_list (is->stream, cancellable, error);
 		CamelIMAPXJob *job;
+		ListData *data;
 
 		if (!linfo)
 			break;
 
-		job = imapx_match_active_job (imap, IMAPX_JOB_LIST, linfo->name);
+		job = imapx_match_active_job (is, IMAPX_JOB_LIST, linfo->name);
+
+		data = camel_imapx_job_get_data (job);
+		g_return_val_if_fail (data != NULL, FALSE);
 
 		// TODO: we want to make sure the names match?
 
-		if (job->u.list.flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
-			c(imap->tagprefix, "lsub: '%s' (%c)\n", linfo->name, linfo->separator);
+		if (data->flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
+			c(is->tagprefix, "lsub: '%s' (%c)\n", linfo->name, linfo->separator);
 
 		} else {
-			c(imap->tagprefix, "list: '%s' (%c)\n", linfo->name, linfo->separator);
+			c(is->tagprefix, "list: '%s' (%c)\n", linfo->name, linfo->separator);
 		}
 
-		if (job && g_hash_table_lookup (job->u.list.folders, linfo->name) == NULL) {
+		if (job && g_hash_table_lookup (data->folders, linfo->name) == NULL) {
 			if (lsub)
 				linfo->flags |= CAMEL_FOLDER_SUBSCRIBED;
-			g_hash_table_insert (job->u.list.folders, linfo->name, linfo);
+			g_hash_table_insert (data->folders, linfo->name, linfo);
 		} else {
 			g_warning("got list response but no current listing job happening?\n");
 			imapx_free_list (linfo);
@@ -1753,13 +1431,13 @@ imapx_untagged (CamelIMAPXServer *imap,
 		break;
 	}
 	case IMAPX_RECENT:
-		c(imap->tagprefix, "recent: %d\n", id);
-		imap->recent = id;
+		c(is->tagprefix, "recent: %d\n", id);
+		is->recent = id;
 		break;
 	case IMAPX_STATUS: {
-		struct _state_info *sinfo = imapx_parse_status_info (imap->stream, cancellable, error);
+		struct _state_info *sinfo = imapx_parse_status_info (is->stream, cancellable, error);
 		if (sinfo) {
-			CamelIMAPXStoreSummary *s = ((CamelIMAPXStore *) imap->store)->summary;
+			CamelIMAPXStoreSummary *s = ((CamelIMAPXStore *) is->store)->summary;
 			CamelIMAPXStoreNamespace *ns;
 			CamelIMAPXFolder *ifolder = NULL;;
 
@@ -1768,9 +1446,9 @@ imapx_untagged (CamelIMAPXServer *imap,
 				gchar *path_name;
 
 				path_name = camel_imapx_store_summary_full_to_path (s, sinfo->name, ns->sep);
-				c(imap->tagprefix, "Got folder path '%s' for full '%s'\n", path_name, sinfo->name);
+				c(is->tagprefix, "Got folder path '%s' for full '%s'\n", path_name, sinfo->name);
 				if (path_name) {
-					ifolder = (gpointer) camel_store_get_folder_sync (imap->store, path_name, 0, cancellable, error);
+					ifolder = (gpointer) camel_store_get_folder_sync (is->store, path_name, 0, cancellable, error);
 					g_free (path_name);
 				}
 			}
@@ -1785,7 +1463,7 @@ imapx_untagged (CamelIMAPXServer *imap,
 				if (sinfo->uidvalidity && sinfo->uidvalidity != ((CamelIMAPXSummary *) cfolder->summary)->validity)
 					invalidate_local_cache (ifolder, sinfo->uidvalidity);
 			} else {
-				c(imap->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
+				c(is->tagprefix, "Received STATUS for unknown folder '%s'\n", sinfo->name);
 			}
 
 			g_free (sinfo->name);
@@ -1796,170 +1474,174 @@ imapx_untagged (CamelIMAPXServer *imap,
 	case IMAPX_BYE: {
 		guchar *token;
 
-		if (camel_imapx_stream_text (imap->stream, &token, cancellable, NULL)) {
-			c(imap->tagprefix, "BYE: %s\n", token);
+		if (camel_imapx_stream_text (is->stream, &token, cancellable, NULL)) {
+			c(is->tagprefix, "BYE: %s\n", token);
 			g_set_error (
 				error, CAMEL_IMAPX_ERROR, 1,
 				"IMAP server said BYE: %s", token);
 		}
-		imap->state = IMAPX_SHUTDOWN;
-		return -1;
+		is->state = IMAPX_SHUTDOWN;
+		return FALSE;
 	}
 	case IMAPX_PREAUTH:
-		c(imap->tagprefix, "preauthenticated\n");
-		if (imap->state < IMAPX_AUTHENTICATED)
-			imap->state = IMAPX_AUTHENTICATED;
+		c(is->tagprefix, "preauthenticated\n");
+		if (is->state < IMAPX_AUTHENTICATED)
+			is->state = IMAPX_AUTHENTICATED;
 		/* fall through... */
 	case IMAPX_OK: case IMAPX_NO: case IMAPX_BAD:
 		/* TODO: validate which ones of these can happen as unsolicited responses */
 		/* TODO: handle bye/preauth differently */
-		camel_imapx_stream_ungettoken (imap->stream, tok, token, len);
-		sinfo = imapx_parse_status (imap->stream, cancellable, error);
+		camel_imapx_stream_ungettoken (is->stream, tok, token, len);
+		sinfo = imapx_parse_status (is->stream, cancellable, error);
 		if (sinfo == NULL)
-			return -1;
+			return FALSE;
 		switch (sinfo->condition) {
 		case IMAPX_CLOSED:
-			c(imap->tagprefix, "previously selected folder is now closed\n");
-			if (imap->select_pending && !imap->select_folder) {
-				imap->select_folder = imap->select_pending;
+			c(is->tagprefix, "previously selected folder is now closed\n");
+			if (is->select_pending && !is->select_folder) {
+				is->select_folder = is->select_pending;
 			}
 			break;
 		case IMAPX_READ_WRITE:
-			imap->mode = IMAPX_MODE_READ | IMAPX_MODE_WRITE;
-			c(imap->tagprefix, "folder is read-write\n");
+			is->mode = IMAPX_MODE_READ | IMAPX_MODE_WRITE;
+			c(is->tagprefix, "folder is read-write\n");
 			break;
 		case IMAPX_READ_ONLY:
-			imap->mode = IMAPX_MODE_READ;
-			c(imap->tagprefix, "folder is read-only\n");
+			is->mode = IMAPX_MODE_READ;
+			c(is->tagprefix, "folder is read-only\n");
 			break;
 		case IMAPX_UIDVALIDITY:
-			imap->uidvalidity = sinfo->u.uidvalidity;
+			is->uidvalidity = sinfo->u.uidvalidity;
 			break;
 		case IMAPX_UNSEEN:
-			imap->unseen = sinfo->u.unseen;
+			is->unseen = sinfo->u.unseen;
 			break;
 		case IMAPX_HIGHESTMODSEQ:
-			imap->highestmodseq = sinfo->u.highestmodseq;
+			is->highestmodseq = sinfo->u.highestmodseq;
 			break;
 		case IMAPX_PERMANENTFLAGS:
-			imap->permanentflags = sinfo->u.permanentflags;
+			is->permanentflags = sinfo->u.permanentflags;
 			break;
 		case IMAPX_UIDNEXT:
-			imap->uidnext = sinfo->u.uidnext;
+			is->uidnext = sinfo->u.uidnext;
 			break;
 		case IMAPX_ALERT:
-			c(imap->tagprefix, "ALERT!: %s\n", sinfo->text);
+			c(is->tagprefix, "ALERT!: %s\n", sinfo->text);
 			break;
 		case IMAPX_PARSE:
-			c(imap->tagprefix, "PARSE: %s\n", sinfo->text);
+			c(is->tagprefix, "PARSE: %s\n", sinfo->text);
 			break;
 		case IMAPX_CAPABILITY:
 			if (sinfo->u.cinfo) {
-				struct _capability_info *cinfo = imap->cinfo;
-				imap->cinfo = sinfo->u.cinfo;
+				struct _capability_info *cinfo = is->cinfo;
+				is->cinfo = sinfo->u.cinfo;
 				sinfo->u.cinfo = NULL;
 				if (cinfo)
 					imapx_free_capability (cinfo);
-				c(imap->tagprefix, "got capability flags %08x\n", imap->cinfo->capa);
+				c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
 			}
 			break;
 		default:
 			break;
 		}
 		imapx_free_status (sinfo);
-		return 0;
+		return TRUE;
 	default:
 		/* unknown response, just ignore it */
-		c(imap->tagprefix, "unknown token: %s\n", token);
+		c(is->tagprefix, "unknown token: %s\n", token);
 	}
 
-	return camel_imapx_stream_skip (imap->stream, cancellable, error);
+	return (camel_imapx_stream_skip (is->stream, cancellable, error) == 0);
 }
 
 /* handle any continuation requests
  * either data continuations, or auth continuation */
-static gint
-imapx_continuation (CamelIMAPXServer *imap,
+static gboolean
+imapx_continuation (CamelIMAPXServer *is,
                     gboolean litplus,
                     GCancellable *cancellable,
                     GError **error)
 {
 	CamelIMAPXCommand *ic, *newliteral = NULL;
 	CamelIMAPXCommandPart *cp;
+	GList *link;
 
 	/* The 'literal' pointer is like a write-lock, nothing else
 	 * can write while we have it ... so we dont need any
 	 * ohter lock here.  All other writes go through
 	 * queue-lock */
-	if (imapx_idle_supported (imap) && imapx_in_idle (imap)) {
-		camel_imapx_stream_skip (imap->stream, cancellable, error);
+	if (imapx_idle_supported (is) && imapx_in_idle (is)) {
+		camel_imapx_stream_skip (is->stream, cancellable, error);
 
-		c(imap->tagprefix, "Got continuation response for IDLE \n");
-		IDLE_LOCK (imap->idle);
+		c(is->tagprefix, "Got continuation response for IDLE \n");
+		IDLE_LOCK (is->idle);
 		/* We might have actually sent the DONE already! */
-		if (imap->idle->state == IMAPX_IDLE_ISSUED)
-			imap->idle->state = IMAPX_IDLE_STARTED;
-		else if (imap->idle->state == IMAPX_IDLE_CANCEL) {
+		if (is->idle->state == IMAPX_IDLE_ISSUED)
+			is->idle->state = IMAPX_IDLE_STARTED;
+		else if (is->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 (imap, error)) {
-				IDLE_UNLOCK (imap->idle);
-				return -1;
+			if (!imapx_command_idle_stop (is, error)) {
+				IDLE_UNLOCK (is->idle);
+				return FALSE;
 			}
-			imap->idle->state = IMAPX_IDLE_OFF;
+			is->idle->state = IMAPX_IDLE_OFF;
 		} else {
-			c(imap->tagprefix, "idle starts in wrong state %d\n",
-				 imap->idle->state);
+			c(is->tagprefix, "idle starts in wrong state %d\n",
+				 is->idle->state);
 		}
-		IDLE_UNLOCK (imap->idle);
+		IDLE_UNLOCK (is->idle);
 
-		QUEUE_LOCK (imap);
-		imap->literal = NULL;
-		imapx_command_start_next (imap, cancellable, error);
-		QUEUE_UNLOCK (imap);
+		QUEUE_LOCK (is);
+		is->literal = NULL;
+		imapx_command_start_next (is, cancellable, error);
+		QUEUE_UNLOCK (is);
 
-		return 1;
+		return TRUE;
 	}
 
-	ic = imap->literal;
+	ic = is->literal;
 	if (!litplus) {
 		if (ic == NULL) {
-			camel_imapx_stream_skip (imap->stream, cancellable, error);
-			c(imap->tagprefix, "got continuation response with no outstanding continuation requests?\n");
-			return 1;
+			camel_imapx_stream_skip (is->stream, cancellable, error);
+			c(is->tagprefix, "got continuation response with no outstanding continuation requests?\n");
+			return TRUE;
 		}
-		c(imap->tagprefix, "got continuation response for data\n");
+		c(is->tagprefix, "got continuation response for data\n");
 	} else {
-		c(imap->tagprefix, "sending LITERAL+ continuation\n");
+		c(is->tagprefix, "sending LITERAL+ continuation\n");
 	}
 
-	cp = ic->current;
+	link = ic->current_part;
+	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(imap->tagprefix, "writing data wrapper to literal\n");
-		camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) imap->stream, cancellable, NULL);
+		c(is->tagprefix, "writing data wrapper to literal\n");
+		camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
 		break;
 	case CAMEL_IMAPX_COMMAND_STREAM:
-		c(imap->tagprefix, "writing stream to literal\n");
-		camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) imap->stream, cancellable, NULL);
+		c(is->tagprefix, "writing stream to literal\n");
+		camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
 		break;
 	case CAMEL_IMAPX_COMMAND_AUTH: {
 		gchar *resp;
 		guchar *token;
 
-		if (camel_imapx_stream_text (imap->stream, &token, cancellable, error))
-			return -1;
+		if (camel_imapx_stream_text (is->stream, &token, cancellable, error))
+			return FALSE;
 
 		resp = camel_sasl_challenge_base64_sync (
 			(CamelSasl *) cp->ob, (const gchar *) token,
 			cancellable, error);
 		g_free (token);
 		if (resp == NULL)
-			return -1;
-		c(imap->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
+			return FALSE;
+		c(is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
 
-		camel_stream_write ((CamelStream *) imap->stream, resp, strlen (resp), cancellable, NULL);
+		camel_stream_write ((CamelStream *) is->stream, resp, strlen (resp), cancellable, NULL);
 		g_free (resp);
 		/* we want to keep getting called until we get a status reponse from the server
 		 * ignore what sasl tells us */
@@ -1970,60 +1652,63 @@ imapx_continuation (CamelIMAPXServer *imap,
 	case CAMEL_IMAPX_COMMAND_FILE: {
 		CamelStream *file;
 
-		c(imap->tagprefix, "writing file '%s' to literal\n", (gchar *)cp->ob);
+		c(is->tagprefix, "writing file '%s' to literal\n", (gchar *)cp->ob);
 
 		// FIXME: errors
 		if (cp->ob && (file = camel_stream_fs_new_with_name (cp->ob, O_RDONLY, 0, NULL))) {
-			camel_stream_write_to_stream (file, (CamelStream *) imap->stream, cancellable, NULL);
+			camel_stream_write_to_stream (file, (CamelStream *) is->stream, cancellable, NULL);
 			g_object_unref (file);
 		} else if (cp->ob_size > 0) {
 			// Server is expecting data ... ummm, send it zeros?  abort?
 		}
 		break; }
 	case CAMEL_IMAPX_COMMAND_STRING:
-		camel_stream_write ((CamelStream *) imap->stream, cp->ob, cp->ob_size, cancellable, NULL);
+		camel_stream_write ((CamelStream *) is->stream, cp->ob, cp->ob_size, cancellable, NULL);
 		break;
 	default:
 		/* should we just ignore? */
-		imap->literal = NULL;
+		is->literal = NULL;
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"continuation response for non-continuation request");
-		return -1;
+		return FALSE;
 	}
 
 	if (!litplus)
-		camel_imapx_stream_skip (imap->stream, cancellable, error);
- noskip:
-	cp = cp->next;
-	if (cp->next) {
-		ic->current = cp;
-		c(imap->tagprefix, "next part of command \"%c%05u: %s\"\n", imap->tagprefix, ic->tag, cp->data);
-		camel_stream_write_string ((CamelStream *) imap->stream, cp->data, cancellable, NULL);
-		camel_stream_write_string ((CamelStream *) imap->stream, "\r\n", cancellable, NULL);
+		camel_imapx_stream_skip (is->stream, cancellable, error);
+
+noskip:
+	link = g_list_next (link);
+	if (link != NULL) {
+		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);
+		camel_stream_write_string ((CamelStream *) is->stream, cp->data, cancellable, NULL);
+		camel_stream_write_string ((CamelStream *) is->stream, "\r\n", cancellable, NULL);
 		if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
 			newliteral = ic;
 		} else {
-			g_assert (cp->next->next == NULL);
+			g_assert (g_list_next (link) == NULL);
 		}
 	} else {
-		c(imap->tagprefix, "%p: queueing continuation\n", ic);
-		camel_stream_write_string((CamelStream *)imap->stream, "\r\n", cancellable, NULL);
+		c(is->tagprefix, "%p: queueing continuation\n", ic);
+		camel_stream_write_string((CamelStream *)is->stream, "\r\n", cancellable, NULL);
 	}
 
-	QUEUE_LOCK (imap);
-	imap->literal = newliteral;
+	QUEUE_LOCK (is);
+	is->literal = newliteral;
 
 	if (!litplus)
-		imapx_command_start_next (imap, cancellable, error);
-	QUEUE_UNLOCK (imap);
+		imapx_command_start_next (is, cancellable, error);
+	QUEUE_UNLOCK (is);
 
-	return 1;
+	return TRUE;
 }
 
 /* handle a completion line */
-static gint
-imapx_completion (CamelIMAPXServer *imap,
+static gboolean
+imapx_completion (CamelIMAPXServer *is,
                   guchar *token,
                   gint len,
                   GCancellable *cancellable,
@@ -2032,79 +1717,81 @@ imapx_completion (CamelIMAPXServer *imap,
 	CamelIMAPXCommand *ic;
 	guint tag;
 
-	if (token[0] != imap->tagprefix) {
+	/* Given "A0001 ...", 'A' = tag prefix, '0001' = tag. */
+
+	if (token[0] != is->tagprefix) {
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"Server sent unexpected response: %s", token);
-
-		return -1;
+		return FALSE;
 	}
 
-	tag = strtoul ( (const gchar *) token + 1, NULL, 10);
+	tag = strtoul ((gchar *) token + 1, NULL, 10);
 
-	if ((ic = imapx_find_command_tag (imap, tag)) == NULL) {
+	if ((ic = imapx_find_command_tag (is, tag)) == NULL) {
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"got response tag unexpectedly: %s", token);
-
-		return -1;
+		return FALSE;
 	}
 
-	c(imap->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
+	c(is->tagprefix, "Got completion response for command %05u '%s'\n", ic->tag, ic->name);
 
-	if (camel_folder_change_info_changed (imap->changes)) {
-		if (imap->changes->uid_changed->len)
-			camel_folder_summary_save_to_db (imap->select_folder->summary, NULL);
+	if (camel_folder_change_info_changed (is->changes)) {
+		if (is->changes->uid_changed->len)
+			camel_folder_summary_save_to_db (is->select_folder->summary, NULL);
 		else {
 			const gchar *full_name;
 
-			full_name = camel_folder_get_full_name (imap->select_folder);
-			camel_db_delete_uids (imap->store->cdb_w, full_name, imap->expunged, NULL);
+			full_name = camel_folder_get_full_name (is->select_folder);
+			camel_db_delete_uids (is->store->cdb_w, full_name, is->expunged, NULL);
 		}
 
-		if (imap->expunged) {
-			g_list_foreach (imap->expunged, (GFunc) g_free, NULL);
-			g_list_free (imap->expunged);
-			imap->expunged = NULL;
-		}
+		g_list_free_full (is->expunged, (GDestroyNotify) g_free);
+		is->expunged = NULL;
 
-		imapx_update_store_summary (imap->select_folder);
-		camel_folder_changed (imap->select_folder, imap->changes);
-		camel_folder_change_info_clear (imap->changes);
+		imapx_update_store_summary (is->select_folder);
+		camel_folder_changed (is->select_folder, is->changes);
+		camel_folder_change_info_clear (is->changes);
 	}
 
-	QUEUE_LOCK (imap);
+	QUEUE_LOCK (is);
 
-	camel_dlist_remove ((CamelDListNode *) ic);
-	camel_dlist_addtail (&imap->done, (CamelDListNode *) ic);
-	if (imap->literal == ic)
-		imap->literal = NULL;
+	g_queue_remove (&is->active, ic);
+	g_queue_push_tail (&is->done, ic);
+
+	if (is->literal == ic)
+		is->literal = NULL;
 
-	if (ic->current->next->next) {
-		QUEUE_UNLOCK (imap);
+	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);
-
-		return -1;
+		return FALSE;
 	}
 
-	camel_dlist_remove ((CamelDListNode *) ic);
-	QUEUE_UNLOCK (imap);
+	g_queue_remove (&is->done, ic);
 
-	ic->status = imapx_parse_status (imap->stream, cancellable, error);
+	QUEUE_UNLOCK (is);
+
+	ic->status = imapx_parse_status (is->stream, cancellable, error);
 
-	if (ic->complete)
-		ic->complete (imap, ic);
+	if (ic->status == NULL)
+		return FALSE;
 
-	QUEUE_LOCK (imap);
-	imapx_command_start_next (imap, cancellable, error);
-	QUEUE_UNLOCK (imap);
+	if (ic->complete != NULL)
+		if (!ic->complete (is, ic, error))
+			return FALSE;
 
-	return 1;
+	QUEUE_LOCK (is);
+	imapx_command_start_next (is, cancellable, error);
+	QUEUE_UNLOCK (is);
+
+	return TRUE;
 }
 
-static void
+static gboolean
 imapx_step (CamelIMAPXServer *is,
             GCancellable *cancellable,
             GError **error)
@@ -2116,56 +1803,61 @@ imapx_step (CamelIMAPXServer *is,
 	// poll ?  wait for other stuff? loop?
 	tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
 	if (tok < 0)
-		return;
+		return FALSE;
 
 	if (tok == '*')
-		imapx_untagged (is, cancellable, error);
-	else if (tok == IMAPX_TOK_TOKEN)
-		imapx_completion (is, token, len, cancellable, error);
-	else if (tok == '+')
-		imapx_continuation (is, FALSE, cancellable, error);
-	else
-		g_set_error (
-			error, CAMEL_IMAPX_ERROR, 1,
-			"unexpected server response:");
+		return imapx_untagged (is, cancellable, error);
+	else if (tok == IMAPX_TOK_TOKEN)
+		return imapx_completion (is, token, len, cancellable, error);
+	else if (tok == '+')
+		return imapx_continuation (is, FALSE, cancellable, error);
+
+	g_set_error (
+		error, CAMEL_IMAPX_ERROR, 1,
+		"unexpected server response:");
+
+	return FALSE;
 }
 
 /* Used to run 1 command synchronously,
  * use for capa, login, and namespaces only. */
 static gboolean
 imapx_command_run (CamelIMAPXServer *is,
-                   CamelIMAPXCommand *ic)
+                   CamelIMAPXCommand *ic,
+                   GCancellable *cancellable,
+                   GError **error)
 /* throws IO,PARSE exception */
 {
-	imapx_command_close (ic);
+	gboolean success = TRUE;
+
+	camel_imapx_command_close (ic);
 
 	QUEUE_LOCK (is);
-	imapx_command_start (is, ic);
+	imapx_command_start (is, ic, cancellable, error);
 	QUEUE_UNLOCK (is);
 
-	while (ic->status == NULL && ic->error == NULL)
-		imapx_step (is, ic->cancellable, &ic->error);
+	while (success && ic->status == NULL)
+		success = imapx_step (is, cancellable, error);
 
 	if (is->literal == ic)
 		is->literal = NULL;
 
 	QUEUE_LOCK (is);
-	camel_dlist_remove ((CamelDListNode *) ic);
+	g_queue_remove (&is->active, ic);
 	QUEUE_UNLOCK (is);
 
-	return (ic->error == NULL);
+	return success;
 }
 
-static void
+static gboolean
 imapx_command_complete (CamelIMAPXServer *is,
-                        CamelIMAPXCommand *ic)
+                        CamelIMAPXCommand *ic,
+                        GError **error)
 {
-	g_mutex_lock (ic->run_sync_mutex);
-	ic->run_sync_done = TRUE;
-	g_cond_broadcast (ic->run_sync_cond);
-	g_mutex_unlock (ic->run_sync_mutex);
+	camel_imapx_command_done (ic);
+	camel_imapx_command_unref (ic);
 
-	imapx_command_unref (ic);
+	return TRUE;
 }
 
 static void
@@ -2174,26 +1866,21 @@ imapx_command_cancelled (GCancellable *cancellable,
 {
 	/* Unblock imapx_command_run_sync() immediately.
 	 *
-	 * If imapx_command_complete() is called sometime later,
+	 * If camel_imapx_command_done() is called sometime later,
 	 * the GCond will broadcast but no one will be listening. */
 
-	g_mutex_lock (ic->run_sync_mutex);
-	ic->run_sync_done = TRUE;
-	g_cond_broadcast (ic->run_sync_cond);
-	g_mutex_unlock (ic->run_sync_mutex);
+	camel_imapx_command_done (ic);
 }
 
 /* The caller should free the command as well */
-static void
+static gboolean
 imapx_command_run_sync (CamelIMAPXServer *is,
-                        CamelIMAPXCommand *ic)
+                        CamelIMAPXCommand *ic,
+                        GCancellable *cancellable,
+                        GError **error)
 {
 	guint cancel_id = 0;
 
-	ic->run_sync_done = FALSE;
-	ic->run_sync_cond = g_cond_new ();
-	ic->run_sync_mutex = g_mutex_new ();
-
 	/* 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
@@ -2205,126 +1892,30 @@ imapx_command_run_sync (CamelIMAPXServer *is,
 	g_warn_if_fail (ic->complete == NULL);
 	ic->complete = imapx_command_complete;
 
-	if (G_IS_CANCELLABLE (ic->cancellable))
+	if (G_IS_CANCELLABLE (cancellable))
 		cancel_id = g_cancellable_connect (
-			ic->cancellable,
+			cancellable,
 			G_CALLBACK (imapx_command_cancelled),
-			imapx_command_ref (ic),
-			(GDestroyNotify) imapx_command_unref);
+			camel_imapx_command_ref (ic),
+			(GDestroyNotify) camel_imapx_command_unref);
 
 	/* Unref'ed in imapx_command_complete(). */
-	imapx_command_ref (ic);
+	camel_imapx_command_ref (ic);
 
 	imapx_command_queue (is, ic);
 
-	g_mutex_lock (ic->run_sync_mutex);
-	while (!ic->run_sync_done)
-		g_cond_wait (ic->run_sync_cond, ic->run_sync_mutex);
-	g_mutex_unlock (ic->run_sync_mutex);
+	camel_imapx_command_wait (ic);
 
 	if (cancel_id > 0)
-		g_cancellable_disconnect (ic->cancellable, cancel_id);
-
-	/* XXX Might this overwrite an existing error? */
-	g_cancellable_set_error_if_cancelled (ic->cancellable, &ic->error);
-
-	g_cond_free (ic->run_sync_cond);
-	g_mutex_free (ic->run_sync_mutex);
-	ic->run_sync_done = FALSE;
-	ic->run_sync_cond = NULL;
-	ic->run_sync_mutex = NULL;
-}
-
-/* ********************************************************************** */
-/* Should be called when there are no more commands needed to complete the job */
-
-static CamelIMAPXJob *
-imapx_job_new (GCancellable *cancellable)
-{
-	CamelIMAPXJob *job;
-
-	if (cancellable != NULL)
-		g_object_ref (cancellable);
-
-	job = g_slice_new0 (CamelIMAPXJob);
-	job->ref_count = 1;
-	job->done_cond = g_cond_new ();
-	job->done_mutex = g_mutex_new ();
-	job->cancellable = cancellable;
-
-	return job;
-}
-
-static CamelIMAPXJob *
-imapx_job_ref (CamelIMAPXJob *job)
-{
-	g_return_val_if_fail (job != NULL, NULL);
-	g_return_val_if_fail (job->ref_count > 0, NULL);
-
-	g_atomic_int_inc (&job->ref_count);
-
-	return job;
-}
-
-static void
-imapx_job_unref (CamelIMAPXJob *job)
-{
-	g_return_if_fail (job != NULL);
-	g_return_if_fail (job->ref_count > 0);
-
-	if (g_atomic_int_dec_and_test (&job->ref_count)) {
-
-		g_cond_free (job->done_cond);
-		g_mutex_free (job->done_mutex);
-
-		g_clear_error (&job->error);
-
-		if (job->cancellable) {
-			if (job->with_operation_msg)
-				camel_operation_pop_message (job->cancellable);
-			g_object_unref (job->cancellable);
-		}
-
-		g_slice_free (CamelIMAPXJob, job);
-	}
-}
+		g_cancellable_disconnect (cancellable, cancel_id);
 
-static gboolean
-imapx_job_can_operation_msg (CamelIMAPXJob *job)
-{
-	return job && job->cancellable && CAMEL_IS_OPERATION (job->cancellable);
-}
-
-static void
-imapx_job_done (CamelIMAPXServer *is,
-                CamelIMAPXJob *job)
-{
-	if (!job->noreply) {
-		g_mutex_lock (job->done_mutex);
-		job->done_flag = TRUE;
-		g_cond_broadcast (job->done_cond);
-		g_mutex_unlock (job->done_mutex);
-	}
-
-	QUEUE_LOCK (is);
-	if (g_queue_remove (&is->jobs, job))
-		imapx_job_unref (job);
-	QUEUE_UNLOCK (is);
-}
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		return FALSE;
 
-static void
-imapx_job_cancelled (GCancellable *cancellable,
-                     CamelIMAPXJob *job)
-{
-	/* Unblock imapx_run_job() immediately.
-	 *
-	 * If imapx_job_done() is called sometime later, the
-	 * GCond will broadcast but no one will be listening. */
+	if (camel_imapx_command_set_error_if_failed (ic, error))
+		return FALSE;
 
-	g_mutex_lock (job->done_mutex);
-	job->done_flag = TRUE;
-	g_cond_broadcast (job->done_cond);
-	g_mutex_unlock (job->done_mutex);
+	return TRUE;
 }
 
 static gboolean
@@ -2334,7 +1925,7 @@ imapx_register_job (CamelIMAPXServer *is,
 {
 	if (is->state >= IMAPX_INITIALISED) {
 		QUEUE_LOCK (is);
-		g_queue_push_head (&is->jobs, imapx_job_ref (job));
+		g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
 		QUEUE_UNLOCK (is);
 
 	} else {
@@ -2349,47 +1940,17 @@ imapx_register_job (CamelIMAPXServer *is,
 	return TRUE;
 }
 
-static gboolean
-imapx_run_job (CamelIMAPXServer *is,
-               CamelIMAPXJob *job,
-               GError **error)
+static void
+imapx_unregister_job (CamelIMAPXServer *is,
+                      CamelIMAPXJob *job)
 {
-	gulong cancel_id = 0;
-
-	g_warn_if_fail (job->done_flag == FALSE);
-
-	if (g_cancellable_set_error_if_cancelled (is->cancellable, error))
-		return FALSE;
-
-	if (G_IS_CANCELLABLE (job->cancellable))
-		cancel_id = g_cancellable_connect (
-			job->cancellable,
-			G_CALLBACK (imapx_job_cancelled),
-			imapx_job_ref (job),
-			(GDestroyNotify) imapx_job_unref);
-
-	job->start (is, job);
-
-	if (!job->noreply) {
-		g_mutex_lock (job->done_mutex);
-		while (!job->done_flag)
-			g_cond_wait (job->done_cond, job->done_mutex);
-		g_mutex_unlock (job->done_mutex);
-	}
-
-	if (cancel_id > 0)
-		g_cancellable_disconnect (job->cancellable, cancel_id);
-
-	if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
-		return FALSE;
-
-	if (job->error != NULL) {
-		g_propagate_error (error, job->error);
-		job->error = NULL;
-		return FALSE;
-	}
+	if (!job->noreply)
+		camel_imapx_job_done (job);
 
-	return TRUE;
+	QUEUE_LOCK (is);
+	if (g_queue_remove (&is->jobs, job))
+		camel_imapx_job_unref (job);
+	QUEUE_UNLOCK (is);
 }
 
 static gboolean
@@ -2400,29 +1961,7 @@ imapx_submit_job (CamelIMAPXServer *is,
 	if (!imapx_register_job (is, job, error))
 		return FALSE;
 
-	return imapx_run_job (is, job, error);
-}
-
-static void
-propagate_ic_error (CamelIMAPXJob *job,
-                    CamelIMAPXCommand *ic,
-                    const gchar *fmt)
-{
-	g_return_if_fail (job != NULL);
-	g_return_if_fail (ic != NULL);
-	g_return_if_fail (fmt != NULL);
-
-	if (job->error)
-		return;
-
-	if (ic->error == NULL) {
-		g_set_error (
-			&job->error, CAMEL_IMAPX_ERROR, 1,
-			fmt, ic->status && ic->status->text ? ic->status->text : _("Unknown error"));
-	} else {
-		g_propagate_error (&job->error, ic->error);
-		ic->error = NULL;
-	}
+	return camel_imapx_job_run (job, is, error);
 }
 
 /* ********************************************************************** */
@@ -2448,40 +1987,46 @@ imapx_command_idle_stop (CamelIMAPXServer *is,
 	return TRUE;
 }
 
-static void
+static gboolean
 imapx_command_idle_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
+                         CamelIMAPXCommand *ic,
+                         GError **error)
 {
 	CamelIMAPXIdle *idle = is->idle;
+	gboolean success = TRUE;
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error performing IDLE: %s");
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error performing IDLE"));
+		success = FALSE;
 	}
 
 	IDLE_LOCK (idle);
 	idle->state = IMAPX_IDLE_OFF;
 	IDLE_UNLOCK (idle);
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_idle_start (CamelIMAPXServer *is,
-                      CamelIMAPXJob *job)
+imapx_job_idle_start (CamelIMAPXJob *job,
+                      CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
 	CamelIMAPXCommandPart *cp;
 
-	ic = imapx_command_new (
-		is, "IDLE", job->folder,
-		job->cancellable, "IDLE");
+	ic = camel_imapx_command_new (
+		is, "IDLE", job->folder, "IDLE");
 	ic->job = job;
 	ic->pri = job->pri;
 	ic->complete = imapx_command_idle_done;
 
-	imapx_command_close (ic);
-	cp = (CamelIMAPXCommandPart *) ic->parts.head;
+	camel_imapx_command_close (ic);
+	cp = g_queue_peek_head (&ic->parts);
 	cp->type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
 
 	QUEUE_LOCK (is);
@@ -2489,10 +2034,10 @@ imapx_job_idle_start (CamelIMAPXServer *is,
 	/* Don't issue it if the idle was cancelled already */
 	if (is->idle->state == IMAPX_IDLE_PENDING) {
 		is->idle->state = IMAPX_IDLE_ISSUED;
-		imapx_command_start (is, ic);
+		imapx_command_start (is, ic, job->cancellable, &job->error);
 	} else {
-		imapx_job_done (is, ic->job);
-		imapx_command_unref (ic);
+		imapx_unregister_job (is, ic->job);
+		camel_imapx_command_unref (ic);
 	}
 	IDLE_UNLOCK (is->idle);
 	QUEUE_UNLOCK (is);
@@ -2507,19 +2052,27 @@ camel_imapx_server_idle (CamelIMAPXServer *is,
 	CamelIMAPXJob *job;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_IDLE;
 	job->start = imapx_job_idle_start;
 	job->folder = folder;
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
 
 static gboolean
+imapx_job_fetch_new_messages_matches (CamelIMAPXJob *job,
+                                      CamelFolder *folder,
+                                      const gchar *uid)
+{
+	return (folder == job->folder);
+}
+
+static gboolean
 imapx_server_fetch_new_messages (CamelIMAPXServer *is,
                                  CamelFolder *folder,
                                  gboolean async,
@@ -2528,20 +2081,26 @@ imapx_server_fetch_new_messages (CamelIMAPXServer *is,
                                  GError **error)
 {
 	CamelIMAPXJob *job;
+	RefreshInfoData *data;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	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->folder = folder;
 	job->noreply = async;
-	job->u.refresh_info.changes = camel_folder_change_info_new ();
-	job->u.refresh_info.update_unseen = update_unseen;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) refresh_info_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	if (!async)
-		imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -2742,62 +2301,69 @@ imapx_idle_supported (CamelIMAPXServer *is)
 
 // end IDLE
 /* ********************************************************************** */
-static void
+static gboolean
 imapx_command_select_done (CamelIMAPXServer *is,
-                           CamelIMAPXCommand *ic)
+                           CamelIMAPXCommand *ic,
+                           GError **error)
 {
 	const gchar *selected_folder = NULL;
+	gboolean success = TRUE;
+	GError *local_error = NULL;
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		CamelDList failed;
-		CamelIMAPXCommand *cw, *cn;
+	if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
+		GQueue failed = G_QUEUE_INIT;
+		GQueue trash = G_QUEUE_INIT;
+		GList *head, *link;
 
 		c(is->tagprefix, "Select failed\n");
-		camel_dlist_init (&failed);
 
 		QUEUE_LOCK (is);
-		cw = (CamelIMAPXCommand *) is->queue.head;
-		cn = cw->next;
+
+		head = g_queue_peek_head_link (&is->queue);
 
 		if (is->select_pending) {
-			while (cn) {
+			head = g_queue_peek_head_link (&is->queue);
+
+			for (link = head; link != NULL; link = g_list_next (link)) {
+				CamelIMAPXCommand *cw = link->data;
+
 				if (cw->select && cw->select == is->select_pending) {
 					c(is->tagprefix, "Cancelling command '%s'(%p) for folder '%s'\n",
 					  cw->name, cw, camel_folder_get_full_name (cw->select));
-					camel_dlist_remove ((CamelDListNode *) cw);
-					camel_dlist_addtail (&failed, (CamelDListNode *) cw);
+					g_queue_push_tail (&trash, link);
 				}
-				cw = cn;
-				cn = cn->next;
 			}
 		}
 
+		while ((link = g_queue_pop_head (&trash)) != NULL) {
+			CamelIMAPXCommand *cw = link->data;
+			g_queue_delete_link (&is->queue, link);
+			g_queue_push_tail (&failed, cw);
+		}
+
 		QUEUE_UNLOCK (is);
 
-		cw = (CamelIMAPXCommand *) failed.head;
-		if (cw) {
-			cn = cw->next;
-			while (cn) {
-				if (ic->status)
-					cw->status = imapx_copy_status (ic->status);
-				if (ic->error != NULL) {
-					g_propagate_error (&cw->error, ic->error);
-					ic->error = NULL;
-				} else {
-					if (ic->status == NULL)
-						/* FIXME: why is ic->status == NULL here? It shouldn't happen. */
-						g_debug ("imapx_command_select_done: ic->status is NULL.");
-					g_set_error (
-						&cw->error, CAMEL_IMAPX_ERROR, 1,
-						"SELECT %s failed: %s",
-						camel_folder_get_full_name (cw->select),
-						ic->status && ic->status->text? ic->status->text:"<unknown reason>");
-				}
-				cw->complete (is, cw);
-				cw = cn;
-				cn = cn->next;
+		while (!g_queue_is_empty (&failed)) {
+			CamelIMAPXCommand *cw;
+
+			cw = g_queue_pop_head (&failed);
+
+			if (ic->status)
+				cw->status = imapx_copy_status (ic->status);
+			if (cw->job->error == NULL) {
+				if (ic->status == NULL)
+					/* FIXME: why is ic->status == NULL here? It shouldn't happen. */
+					g_debug ("imapx_command_select_done: ic->status is NULL.");
+				g_set_error (
+					&cw->job->error,
+					CAMEL_IMAPX_ERROR, 1,
+					"SELECT %s failed: %s",
+					camel_folder_get_full_name (cw->select),
+					ic->status && ic->status->text? ic->status->text:"<unknown reason>");
 			}
+			cw->complete (is, cw, NULL);
 		}
+
 		if (is->select_pending)
 			g_object_unref (is->select_pending);
 
@@ -2806,6 +2372,10 @@ imapx_command_select_done (CamelIMAPXServer *is,
 			is->select_folder = NULL;
 
 		is->state = IMAPX_INITIALISED;
+
+		g_propagate_error (error, local_error);
+		success = FALSE;
+
 	} else {
 		CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) is->select_pending;
 		CamelFolder *cfolder = is->select_pending;
@@ -2841,9 +2411,11 @@ imapx_command_select_done (CamelIMAPXServer *is,
 	}
 
 	is->select_pending = NULL;
-	imapx_command_unref (ic);
+	camel_imapx_command_unref (ic);
 
 	g_signal_emit (is, signals[SELECT_CHANGED], 0, selected_folder);
+
+	return success;
 }
 
 /* Should have a queue lock. TODO Change the way select is written */
@@ -2874,7 +2446,7 @@ imapx_select (CamelIMAPXServer *is,
 	if (is->select_folder == folder && !forced)
 		return TRUE;
 
-	if (!camel_dlist_empty (&is->active))
+	if (!g_queue_is_empty (&is->active))
 		return TRUE;
 
 	is->select_pending = folder;
@@ -2900,8 +2472,8 @@ imapx_select (CamelIMAPXServer *is,
 	/* Hrm, what about reconnecting? */
 	is->state = IMAPX_INITIALISED;
 
-	ic = imapx_command_new (
-		is, "SELECT", NULL, cancellable, "SELECT %f", folder);
+	ic = camel_imapx_command_new (
+		is, "SELECT", NULL, "SELECT %f", folder);
 
 	if (is->use_qresync) {
 		CamelIMAPXSummary *isum = (CamelIMAPXSummary *) folder->summary;
@@ -2918,7 +2490,7 @@ imapx_select (CamelIMAPXServer *is,
 			  " %" G_GUINT64_FORMAT "\n",
 			  ifolder->uidvalidity_on_server, isum->modseq);
 
-			imapx_command_add (
+			camel_imapx_command_add (
 				ic, " (QRESYNC (%"
 				G_GUINT64_FORMAT " %"
 				G_GUINT64_FORMAT " %s:%s",
@@ -2966,19 +2538,19 @@ imapx_select (CamelIMAPXServer *is,
 				g_string_prepend(seqs, " (");
 
 				c(is->tagprefix, "adding QRESYNC seq/uidset %s%s\n", seqs->str, uids->str);
-				imapx_command_add (ic, seqs->str);
-				imapx_command_add (ic, uids->str);
+				camel_imapx_command_add (ic, seqs->str);
+				camel_imapx_command_add (ic, uids->str);
 
 				g_string_free (seqs, TRUE);
 				g_string_free (uids, TRUE);
 
 			}
-			imapx_command_add (ic, "))");
+			camel_imapx_command_add (ic, "))");
 		}
 	}
 
 	ic->complete = imapx_command_select_done;
-	imapx_command_start (is, ic);
+	imapx_command_start (is, ic, cancellable, error);
 
 	return TRUE;
 }
@@ -3222,28 +2794,26 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 	}
 
 	if (!is->cinfo) {
-		ic = imapx_command_new (
-			is, "CAPABILITY", NULL,
-			cancellable, "CAPABILITY");
-		imapx_command_run (is, ic);
-
-		if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-			if (ic->error == NULL)
-				g_set_error (
-					error, CAMEL_ERROR,
-					CAMEL_ERROR_GENERIC,
-					"%s", ic->status->text);
-			else {
-				g_propagate_error (error, ic->error);
-				ic->error = NULL;
-			}
-
-			imapx_command_unref (ic);
+		ic = camel_imapx_command_new (
+			is, "CAPABILITY", NULL, "CAPABILITY");
+		if (!imapx_command_run (is, ic, cancellable, error)) {
+			camel_imapx_command_unref (ic);
 			success = FALSE;
+			goto exit;
+		}
 
+		/* Server reported error. */
+		if (ic->status->result != IMAPX_OK) {
+			g_set_error (
+				error, CAMEL_ERROR,
+				CAMEL_ERROR_GENERIC,
+				"%s", ic->status->text);
+			camel_imapx_command_unref (ic);
+			success = FALSE;
 			goto exit;
 		}
-		imapx_command_unref (ic);
+
+		camel_imapx_command_unref (ic);
 	}
 
 	if (method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT) {
@@ -3257,23 +2827,22 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 			goto exit;
 		}
 
-		ic = imapx_command_new (
-			is, "STARTTLS", NULL,
-			cancellable, "STARTTLS");
-		imapx_command_run (is, ic);
-
-		if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-			if (ic->error == NULL)
-				g_set_error (
-					&local_error, CAMEL_ERROR,
-					CAMEL_ERROR_GENERIC,
-					"%s", ic->status->text);
-			else {
-				g_propagate_error (&local_error, ic->error);
-				ic->error = NULL;
-			}
+		ic = camel_imapx_command_new (
+			is, "STARTTLS", NULL, "STARTTLS");
+		if (!imapx_command_run (is, ic, cancellable, error)) {
+			camel_imapx_command_unref (ic);
+			success = FALSE;
+			goto exit;
+		}
 
-			imapx_command_unref (ic);
+		/* Server reported error. */
+		if (ic->status->result != IMAPX_OK) {
+			g_set_error (
+				error, CAMEL_ERROR,
+				CAMEL_ERROR_GENERIC,
+				"%s", ic->status->text);
+			camel_imapx_command_unref (ic);
+			success = FALSE;
 			goto exit;
 		}
 
@@ -3286,7 +2855,7 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 			c(is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
 		}
 
-		imapx_command_unref (ic);
+		camel_imapx_command_unref (ic);
 
 		if (camel_tcp_stream_ssl_enable_ssl (
 			CAMEL_TCP_STREAM_SSL (tcp_stream),
@@ -3299,35 +2868,29 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 		}
 		/* Get new capabilities if they weren't already given */
 		if (!is->cinfo) {
-			ic = imapx_command_new (
-				is, "CAPABILITY", NULL,
-				cancellable, "CAPABILITY");
-			if (!imapx_command_run (is, ic)) {
-				g_propagate_error (&local_error, ic->error);
-				ic->error = NULL;
-				imapx_command_unref (ic);
+			ic = camel_imapx_command_new (
+				is, "CAPABILITY", NULL, "CAPABILITY");
+			if (!imapx_command_run (is, ic, cancellable, error)) {
+				camel_imapx_command_unref (ic);
+				success = FALSE;
 				goto exit;
 			}
 
-			imapx_command_unref (ic);
+			camel_imapx_command_unref (ic);
 		}
 	}
 
 exit:
-	if (local_error != NULL) {
-		e(is->tagprefix, "Unable to connect %d %s \n",
-		  local_error->code, local_error->message);
-		g_propagate_error (error, local_error);
-		local_error = NULL;
-		g_object_unref (is->stream);
-		is->stream = NULL;
+	if (!success) {
+		if (is->stream != NULL) {
+			g_object_unref (is->stream);
+			is->stream = NULL;
+		}
 
-		if (is->cinfo) {
+		if (is->cinfo != NULL) {
 			imapx_free_capability (is->cinfo);
 			is->cinfo = NULL;
 		}
-
-		success = FALSE;
 	}
 
 	g_free (host);
@@ -3385,9 +2948,8 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
 	}
 
 	if (sasl != NULL) {
-		ic = imapx_command_new (
-			is, "AUTHENTICATE", NULL,cancellable,
-			"AUTHENTICATE %A", sasl);
+		ic = camel_imapx_command_new (
+			is, "AUTHENTICATE", NULL, "AUTHENTICATE %A", sasl);
 	} else {
 		const gchar *password;
 
@@ -3411,23 +2973,16 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
 			goto exit;
 		}
 
-		ic = imapx_command_new (
-			is, "LOGIN", NULL, cancellable,
-			"LOGIN %s %s", user, password);
+		ic = camel_imapx_command_new (
+			is, "LOGIN", NULL, "LOGIN %s %s", user, password);
 	}
 
-	imapx_command_run (is, ic);
-
-	if (ic->error == NULL) {
-		if (ic->status->result == IMAPX_OK)
-			result = CAMEL_AUTHENTICATION_ACCEPTED;
-		else
-			result = CAMEL_AUTHENTICATION_REJECTED;
-	} else {
-		g_propagate_error (error, ic->error);
-		ic->error = NULL;
+	if (!imapx_command_run (is, ic, cancellable, error))
 		result = CAMEL_AUTHENTICATION_ERROR;
-	}
+	else if (ic->status->result == IMAPX_OK)
+		result = CAMEL_AUTHENTICATION_ACCEPTED;
+	else
+		result = CAMEL_AUTHENTICATION_REJECTED;
 
 	/* Forget old capabilities after login. */
 	if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
@@ -3443,7 +2998,7 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
 		}
 	}
 
-	imapx_command_unref (ic);
+	camel_imapx_command_unref (ic);
 
 	if (sasl != NULL)
 		g_object_unref (sasl);
@@ -3493,17 +3048,14 @@ imapx_reconnect (CamelIMAPXServer *is,
 
 	/* After login we re-capa unless the server already told us */
 	if (!is->cinfo) {
-		ic = imapx_command_new (
-			is, "CAPABILITY", NULL,
-			cancellable, "CAPABILITY");
-		if (!imapx_command_run (is, ic)) {
-			g_propagate_error (error, ic->error);
-			ic->error = NULL;
-			imapx_command_unref (ic);
+		ic = camel_imapx_command_new (
+			is, "CAPABILITY", NULL, "CAPABILITY");
+		if (!imapx_command_run (is, ic, cancellable, error)) {
+			camel_imapx_command_unref (ic);
 			goto exception;
 		}
 
-		imapx_command_unref (ic);
+		camel_imapx_command_unref (ic);
 	}
 
 	is->state = IMAPX_AUTHENTICATED;
@@ -3516,31 +3068,25 @@ imapx_reconnect (CamelIMAPXServer *is,
 
 	/* Fetch namespaces */
 	if (is->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE) {
-		ic = imapx_command_new (
-			is, "NAMESPACE", NULL,
-			cancellable, "NAMESPACE");
-		if (!imapx_command_run (is, ic)) {
-			g_propagate_error (error, ic->error);
-			ic->error = NULL;
-			imapx_command_unref (ic);
+		ic = camel_imapx_command_new (
+			is, "NAMESPACE", NULL, "NAMESPACE");
+		if (!imapx_command_run (is, ic, cancellable, error)) {
+			camel_imapx_command_unref (ic);
 			goto exception;
 		}
 
-		imapx_command_unref (ic);
+		camel_imapx_command_unref (ic);
 	}
 
 	if (use_qresync && is->cinfo->capa & IMAPX_CAPABILITY_QRESYNC) {
-		ic = imapx_command_new (
-			is, "ENABLE", NULL, cancellable,
-			"ENABLE CONDSTORE QRESYNC");
-		if (!imapx_command_run (is, ic)) {
-			g_propagate_error (error, ic->error);
-			ic->error = NULL;
-			imapx_command_unref (ic);
+		ic = camel_imapx_command_new (
+			is, "ENABLE", NULL, "ENABLE CONDSTORE QRESYNC");
+		if (!imapx_command_run (is, ic, cancellable, error)) {
+			camel_imapx_command_unref (ic);
 			goto exception;
 		}
 
-		imapx_command_unref (ic);
+		camel_imapx_command_unref (ic);
 
 		is->use_qresync = TRUE;
 	} else
@@ -3586,12 +3132,18 @@ exception:
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_fetch_message_done (CamelIMAPXServer *is,
-                                  CamelIMAPXCommand *ic)
+                                  CamelIMAPXCommand *ic,
+                                  GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
-	gboolean failed = FALSE;
+	GetMessageData *data;
+	gboolean success = TRUE;
+	GError *local_error = NULL;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	/* We either have more to fetch (partial mode?), we are complete,
 	 * or we failed.  Failure is handled in the fetch code, so
@@ -3599,55 +3151,63 @@ imapx_command_fetch_message_done (CamelIMAPXServer *is,
 
 	job->commands--;
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		failed = TRUE;
-		job->u.get_message.body_len = -1;
-	} else  if (job->u.get_message.use_multi_fetch) {
-		gsize really_fetched = g_seekable_tell (G_SEEKABLE (job->u.get_message.stream));
+	if (camel_imapx_command_set_error_if_failed (ic, &local_error)) {
+		g_prefix_error (
+			&local_error, "%s: ",
+			_("Error fetching message"));
+		data->body_len = -1;
+
+	} 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 (job->u.get_message.fetch_offset < job->u.get_message.size ||
-		    job->u.get_message.fetch_offset == really_fetched) {
-			imapx_command_unref (ic);
+		if (data->fetch_offset < data->size ||
+		    data->fetch_offset == really_fetched) {
+			camel_imapx_command_unref (ic);
 			camel_operation_progress (
 				job->cancellable,
-				(job->u.get_message.fetch_offset *100) / job->u.get_message.size);
-
-			ic = imapx_command_new (
-				is, "FETCH", job->folder, job->cancellable,
-				"UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
-			imapx_command_add (ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
-			imapx_command_add (ic, ")");
+				(data->fetch_offset *100) / data->size);
+
+			ic = camel_imapx_command_new (
+				is, "FETCH", job->folder,
+				"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;
 			ic->job = job;
 			ic->pri = job->pri - 1;
-			job->u.get_message.fetch_offset += MULTI_SIZE;
+			data->fetch_offset += MULTI_SIZE;
 			job->commands++;
 			imapx_command_queue (is, ic);
-			return;
+			return TRUE;
 		}
 	}
 
 	if (job->commands == 0) {
 		CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
-		CamelStream *stream = job->u.get_message.stream;
+		CamelStream *stream = data->stream;
 
 		/* return the exception from last command */
-		if (failed || job->error) {
-			propagate_ic_error (job, ic, "Error fetching message: %s");
+		if (local_error != NULL) {
 			if (stream)
 				g_object_unref (stream);
-			job->u.get_message.stream = NULL;
+			data->stream = NULL;
+
+			g_propagate_error (error, local_error);
+			local_error = NULL;
+			success = FALSE;
+
 		} else {
 			CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
 
 			if (stream) {
-				gchar *tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", job->u.get_message.uid, NULL);
+				gchar *tmp = camel_data_cache_get_filename (ifolder->cache, "tmp", data->uid, NULL);
 
 				if (camel_stream_flush (stream, job->cancellable, &job->error) == 0 && camel_stream_close (stream, job->cancellable, &job->error) == 0) {
-					gchar *cache_file = camel_data_cache_get_filename  (ifolder->cache, "cur", job->u.get_message.uid, NULL);
+					gchar *cache_file = camel_data_cache_get_filename  (ifolder->cache, "cur", data->uid, NULL);
 					gchar *temp = g_strrstr (cache_file, "/"), *dir;
 
 					dir = g_strndup (cache_file, temp - cache_file);
@@ -3665,43 +3225,53 @@ imapx_command_fetch_message_done (CamelIMAPXServer *is,
 						_("Closing tmp stream failed: "));
 
 				g_free (tmp);
-				g_object_unref (job->u.get_message.stream);
-				job->u.get_message.stream = camel_data_cache_get (ifolder->cache, "cur", job->u.get_message.uid, NULL);
+				g_object_unref (data->stream);
+				data->stream = camel_data_cache_get (ifolder->cache, "cur", data->uid, NULL);
 			}
 		}
 
-		camel_data_cache_remove (ifolder->cache, "tmp", job->u.get_message.uid, NULL);
-		imapx_job_done (is, job);
+		camel_data_cache_remove (ifolder->cache, "tmp", data->uid, NULL);
+		imapx_unregister_job (is, job);
 	}
 
-	imapx_command_unref (ic);
+	camel_imapx_command_unref (ic);
+
+	g_clear_error (&local_error);
+
+	return success;
 }
 
 static void
-imapx_job_get_message_start (CamelIMAPXServer *is,
-                             CamelIMAPXJob *job)
+imapx_job_get_message_start (CamelIMAPXJob *job,
+                             CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	GetMessageData *data;
 	gint i;
 
-	if (job->u.get_message.use_multi_fetch) {
-		for (i = 0; i < 3 && job->u.get_message.fetch_offset < job->u.get_message.size; i++) {
-			ic = imapx_command_new (
-				is, "FETCH", job->folder, job->cancellable,
-				"UID FETCH %t (BODY.PEEK[]", job->u.get_message.uid);
-			imapx_command_add (ic, "<%u.%u>", job->u.get_message.fetch_offset, MULTI_SIZE);
-			imapx_command_add (ic, ")");
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
+	if (data->use_multi_fetch) {
+		for (i = 0; i < 3 && data->fetch_offset < data->size; i++) {
+			ic = camel_imapx_command_new (
+				is, "FETCH", job->folder,
+				"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;
 			ic->job = job;
 			ic->pri = job->pri;
-			job->u.get_message.fetch_offset += MULTI_SIZE;
+			data->fetch_offset += MULTI_SIZE;
 			job->commands++;
 			imapx_command_queue (is, ic);
 		}
 	} else {
-		ic = imapx_command_new (
-			is, "FETCH", job->folder, job->cancellable,
-			"UID FETCH %t (BODY.PEEK[])", job->u.get_message.uid);
+		ic = camel_imapx_command_new (
+			is, "FETCH", job->folder,
+			"UID FETCH %t (BODY.PEEK[])",
+			data->uid);
 		ic->complete = imapx_command_fetch_message_done;
 		ic->job = job;
 		ic->pri = job->pri;
@@ -3710,63 +3280,56 @@ imapx_job_get_message_start (CamelIMAPXServer *is,
 	}
 }
 
-/* ********************************************************************** */
-
-static void
-imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
-                                        CamelIMAPXJob *job,
-                                        gint index)
+static gboolean
+imapx_job_get_message_matches (CamelIMAPXJob *job,
+                               CamelFolder *folder,
+                               const gchar *uid)
 {
-	CamelIMAPXCommand *ic;
-	GPtrArray *uids = job->u.copy_messages.uids;
-	gint i = index;
+	GetMessageData *data;
 
-	ic = imapx_command_new (
-		is, "COPY", job->folder,
-		job->cancellable, "UID COPY ");
-	ic->complete = imapx_command_copy_messages_step_done;
-	ic->job = job;
-	ic->pri = job->pri;
-	job->u.copy_messages.last_index = i;
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	for (; i < uids->len; i++) {
-		gint res;
-		const gchar *uid = (gchar *) g_ptr_array_index (uids, i);
+	if (folder != job->folder)
+		return FALSE;
 
-		res = imapx_uidset_add (&job->u.copy_messages.uidset, ic, uid);
-		if (res == 1) {
-			imapx_command_add (ic, " %f", job->u.copy_messages.dest);
-			job->u.copy_messages.index = i;
-			imapx_command_queue (is, ic);
-			return;
-		}
-	}
+	if (g_strcmp0 (uid, data->uid) != 0)
+		return FALSE;
 
-	job->u.copy_messages.index = i;
-	if (imapx_uidset_done (&job->u.copy_messages.uidset, ic)) {
-		imapx_command_add (ic, " %f", job->u.copy_messages.dest);
-		imapx_command_queue (is, ic);
-		return;
-	}
+	return TRUE;
 }
 
-static void
+/* ********************************************************************** */
+
+static gboolean
 imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
-                                       CamelIMAPXCommand *ic)
+                                       CamelIMAPXCommand *ic,
+                                       GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
-	gint i = job->u.copy_messages.index;
-	GPtrArray *uids = job->u.copy_messages.uids;
+	CopyMessagesData *data;
+	GPtrArray *uids;
+	gint i;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (job, ic, "Error copying messages");
+	uids = data->uids;
+	i = data->index;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			&ic->job->error, "%s: ",
+			_("Error copying messages"));
+		success = FALSE;
 		goto cleanup;
 	}
 
-	if (job->u.copy_messages.delete_originals) {
+	if (data->delete_originals) {
 		gint j;
 
-		for (j = job->u.copy_messages.last_index; j < i; j++)
+		for (j = data->last_index; j < i; j++)
 			camel_folder_delete_message (job->folder, uids->pdata[j]);
 	}
 
@@ -3777,115 +3340,176 @@ imapx_command_copy_messages_step_done (CamelIMAPXServer *is,
 		for (i = 0; i < ic->status->u.copyuid.copied_uids->len; i++) {
 			guint32 uid = GPOINTER_TO_UINT (g_ptr_array_index (ic->status->u.copyuid.copied_uids, i));
 			gchar *str = g_strdup_printf ("%d",uid);
-			CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->u.copy_messages.dest;
+			CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) data->dest;
 
 			g_hash_table_insert (ifolder->ignore_recent, str, GINT_TO_POINTER (1));
 		}
-
+
+	}
+
+	if (i < uids->len) {
+		camel_imapx_command_unref (ic);
+		imapx_command_copy_messages_step_start (is, job, i);
+		return TRUE;
+	}
+
+cleanup:
+	g_object_unref (job->folder);
+
+	imapx_unregister_job (is, job);
+	camel_imapx_command_unref (ic);
+
+	return success;
+}
+
+static void
+imapx_command_copy_messages_step_start (CamelIMAPXServer *is,
+                                        CamelIMAPXJob *job,
+                                        gint index)
+{
+	CamelIMAPXCommand *ic;
+	CopyMessagesData *data;
+	GPtrArray *uids;
+	gint i = index;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
+	uids = data->uids;
+
+	ic = camel_imapx_command_new (
+		is, "COPY", job->folder, "UID COPY ");
+	ic->complete = imapx_command_copy_messages_step_done;
+	ic->job = job;
+	ic->pri = job->pri;
+	data->last_index = i;
+
+	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, " %f", data->dest);
+			data->index = i;
+			imapx_command_queue (is, ic);
+			return;
+		}
 	}
 
-	if (i < uids->len) {
-		imapx_command_unref (ic);
-		imapx_command_copy_messages_step_start (is, job, i);
+	data->index = i;
+	if (imapx_uidset_done (&data->uidset, ic)) {
+		camel_imapx_command_add (ic, " %f", data->dest);
+		imapx_command_queue (is, ic);
 		return;
 	}
-
-cleanup:
-	g_object_unref (job->u.copy_messages.dest);
-	g_object_unref (job->folder);
-
-	imapx_job_done (is, job);
-	imapx_command_unref (ic);
 }
 
 static void
-imapx_job_copy_messages_start (CamelIMAPXServer *is,
-                               CamelIMAPXJob *job)
+imapx_job_copy_messages_start (CamelIMAPXJob *job,
+                               CamelIMAPXServer *is)
 {
+	CopyMessagesData *data;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
 	if (!imapx_server_sync_changes (
 		is, job->folder, job->pri, job->cancellable, &job->error))
-		imapx_job_done (is, job);
+		imapx_unregister_job (is, job);
 
-	g_ptr_array_sort (job->u.copy_messages.uids, (GCompareFunc) imapx_uids_array_cmp);
-	imapx_uidset_init (&job->u.copy_messages.uidset, 0, MAX_COMMAND_LEN);
+	g_ptr_array_sort (data->uids, (GCompareFunc) imapx_uids_array_cmp);
+	imapx_uidset_init (&data->uidset, 0, MAX_COMMAND_LEN);
 	imapx_command_copy_messages_step_start (is, job, 0);
 }
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_append_message_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
+                                   CamelIMAPXCommand *ic,
+                                   GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
 	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
 	CamelMessageInfo *mi;
+	AppendMessageData *data;
 	gchar *cur, *old_uid;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, 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 less us know it was appended. */
 
-	mi = camel_message_info_clone (job->u.append_message.info);
-	old_uid = g_strdup (job->u.append_message.info->uid);
-
-	if (ic->error == NULL && ic->status->result == IMAPX_OK) {
-		if (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 == ifolder->uidvalidity_on_server) {
-				CamelFolderChangeInfo *changes;
-				gchar *uid;
-
-				uid = g_strdup_printf("%u", (guint)ic->status->u.appenduid.uid);
-				mi->uid = camel_pstring_add (uid, TRUE);
-
-				cur = camel_data_cache_get_filename  (ifolder->cache, "cur", mi->uid, NULL);
-				g_rename (job->u.append_message.path, cur);
-
-				/* should we update the message count ? */
-				camel_folder_summary_add (job->folder->summary, mi);
-				imapx_set_message_info_flags_for_new_message (mi,
-									      ((CamelMessageInfoBase *) job->u.append_message.info)->flags,
-									      ((CamelMessageInfoBase *) job->u.append_message.info)->user_flags,
-									      job->folder);
-				changes = camel_folder_change_info_new ();
-				camel_folder_change_info_add_uid (changes, mi->uid);
-				camel_folder_changed (job->folder, changes);
-				camel_folder_change_info_free (changes);
-
-				g_free (cur);
-			} else {
-				g_message ("but uidvalidity changed \n");
-			}
+	mi = camel_message_info_clone (data->info);
+	old_uid = g_strdup (data->info->uid);
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error appending message"));
+		success = FALSE;
+
+	} else if (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 == ifolder->uidvalidity_on_server) {
+			CamelFolderChangeInfo *changes;
+			gchar *uid;
+
+			uid = g_strdup_printf("%u", (guint)ic->status->u.appenduid.uid);
+			mi->uid = camel_pstring_add (uid, TRUE);
+
+			cur = camel_data_cache_get_filename  (ifolder->cache, "cur", mi->uid, NULL);
+			g_rename (data->path, cur);
+
+			/* should we update the message count ? */
+			camel_folder_summary_add (job->folder->summary, mi);
+			imapx_set_message_info_flags_for_new_message (mi,
+								      ((CamelMessageInfoBase *) data->info)->flags,
+								      ((CamelMessageInfoBase *) data->info)->user_flags,
+								      job->folder);
+			changes = camel_folder_change_info_new ();
+			camel_folder_change_info_add_uid (changes, mi->uid);
+			camel_folder_changed (job->folder, changes);
+			camel_folder_change_info_free (changes);
+
+			g_free (cur);
+		} else {
+			g_message ("but uidvalidity changed \n");
 		}
-	} else {
-		propagate_ic_error (job, ic, "Error appending message: %s");
 	}
 
 	camel_data_cache_remove (ifolder->cache, "new", old_uid, NULL);
 	g_free (old_uid);
-	camel_message_info_free (job->u.append_message.info);
-	g_free (job->u.append_message.path);
 	g_object_unref (job->folder);
 
-	imapx_job_done (is, job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_append_message_start (CamelIMAPXServer *is,
-                                CamelIMAPXJob *job)
+imapx_job_append_message_start (CamelIMAPXJob *job,
+                                CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	AppendMessageData *data;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
 
 	/* TODO: we could supply the original append date from the file timestamp */
-	ic = imapx_command_new (
-		is, "APPEND", NULL, job->cancellable,
+	ic = camel_imapx_command_new (
+		is, "APPEND", NULL,
 		"APPEND %f %F %P", job->folder,
-		((CamelMessageInfoBase *) job->u.append_message.info)->flags,
-		((CamelMessageInfoBase *) job->u.append_message.info)->user_flags,
-		job->u.append_message.path);
+		((CamelMessageInfoBase *) data->info)->flags,
+		((CamelMessageInfoBase *) data->info)->user_flags,
+		data->path);
 	ic->complete = imapx_command_append_message_done;
 	ic->job = job;
 	ic->pri = job->pri;
@@ -3974,60 +3598,69 @@ imapx_index_next (GPtrArray *uids,
 	return index;
 }
 
-static void
+static gboolean
 imapx_command_step_fetch_done (CamelIMAPXServer *is,
-                               CamelIMAPXCommand *ic)
+                               CamelIMAPXCommand *ic,
+                               GError **error)
 {
 	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) ic->job->folder;
 	CamelIMAPXSummary *isum = (CamelIMAPXSummary *) ic->job->folder->summary;
 	CamelIMAPXJob *job = ic->job;
-	gint i = job->u.refresh_info.index;
-	GArray *infos = job->u.refresh_info.infos;
+	RefreshInfoData *data;
+	gint i;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (job, ic, "Error fetching message headers");
+	i = data->index;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error fetching message headers"));
+		success = FALSE;
 		goto cleanup;
 	}
 
-	if (camel_folder_change_info_changed (job->u.refresh_info.changes)) {
+	if (camel_folder_change_info_changed (data->changes)) {
 		imapx_update_store_summary (job->folder);
 		camel_folder_summary_save_to_db (job->folder->summary, NULL);
-		camel_folder_changed (job->folder, job->u.refresh_info.changes);
+		camel_folder_changed (job->folder, data->changes);
 	}
 
-	camel_folder_change_info_clear (job->u.refresh_info.changes);
+	camel_folder_change_info_clear (data->changes);
 
-	if (i < infos->len) {
-		imapx_command_unref (ic);
+	if (i < data->infos->len) {
+		camel_imapx_command_unref (ic);
 
-		ic = imapx_command_new (
-			is, "FETCH", job->folder,
-			job->cancellable, "UID FETCH ");
+		ic = camel_imapx_command_new (
+			is, "FETCH", job->folder, "UID FETCH ");
 		ic->complete = imapx_command_step_fetch_done;
 		ic->job = job;
 		ic->pri = job->pri - 1;
-		job->u.refresh_info.last_index = i;
+		data->last_index = i;
 
-		for (; i < infos->len; i++) {
+		for (; i < data->infos->len; i++) {
 			gint res;
-			struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+			struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
 
 			if (!r->exists) {
-				res = imapx_uidset_add (&job->u.refresh_info.uidset, ic, r->uid);
+				res = imapx_uidset_add (&data->uidset, ic, r->uid);
 				if (res == 1) {
-					imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
-					job->u.refresh_info.index = i;
+					camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
+					data->index = i;
 					imapx_command_queue (is, ic);
-					return;
+					return TRUE;
 				}
 			}
 		}
 
-		job->u.refresh_info.index = i;
-		if (imapx_uidset_done (&job->u.refresh_info.uidset, ic)) {
-			imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
+		data->index = i;
+		if (imapx_uidset_done (&data->uidset, ic)) {
+			camel_imapx_command_add (ic, " (RFC822.SIZE RFC822.HEADER)");
 			imapx_command_queue (is, ic);
-			return;
+			return TRUE;
 		}
 	}
 
@@ -4048,18 +3681,18 @@ imapx_command_step_fetch_done (CamelIMAPXServer *is,
 	isum->uidnext = ifolder->uidnext_on_server;
 
  cleanup:
-	for (i = 0; i < infos->len; i++) {
-		struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+	for (i = 0; i < data->infos->len; i++) {
+		struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
 
 		camel_flag_list_free (&r->server_user_flags);
 		g_free (r->uid);
 	}
-	g_array_free (job->u.refresh_info.infos, TRUE);
-	if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES)
-		camel_folder_change_info_free (job->u.refresh_info.changes);
+	g_array_free (data->infos, TRUE);
+
+	imapx_unregister_job (is, job);
+	camel_imapx_command_unref (ic);
 
-	imapx_job_done (is, job);
-	imapx_command_unref (ic);
+	return success;
 }
 
 static gint
@@ -4087,16 +3720,21 @@ imapx_uid_cmp (gconstpointer ap,
 	return strcmp (ae, be);
 }
 
-static void
+static gboolean
 imapx_job_scan_changes_done (CamelIMAPXServer *is,
-                             CamelIMAPXCommand *ic)
+                             CamelIMAPXCommand *ic,
+                             GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
 	CamelService *service;
 	CamelSettings *settings;
-	gint i;
-	GArray *infos = job->u.refresh_info.infos;
+	RefreshInfoData *data;
 	guint uidset_size;
+	gint i;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	service = CAMEL_SERVICE (is->store);
 	settings = camel_service_get_settings (service);
@@ -4104,7 +3742,13 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 	uidset_size = camel_imapx_settings_get_batch_fetch_count (
 		CAMEL_IMAPX_SETTINGS (settings));
 
-	if (ic->error == NULL && ic->status->result == IMAPX_OK) {
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error retrieving message"));
+		success = FALSE;
+
+	} else {
 		GCompareDataFunc uid_cmp = imapx_uid_cmp;
 		CamelMessageInfo *s_minfo = NULL;
 		CamelIMAPXMessageInfo *info;
@@ -4133,19 +3777,19 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 		/* obtain a copy to be thread safe */
 		uids = camel_folder_summary_get_array (s);
 
-		qsort (infos->data, infos->len, sizeof (struct _refresh_info), imapx_refresh_info_cmp);
+		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 < infos->len; i++) {
-			struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+		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 (job->u.refresh_info.changes, uid);
+				camel_folder_change_info_remove_uid (data->changes, uid);
 				removed = g_list_prepend (removed, (gpointer ) g_strdup (uid));
 				camel_message_info_free (s_minfo);
 				s_minfo = NULL;
@@ -4160,7 +3804,7 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 				info = (CamelIMAPXMessageInfo *) s_minfo;
 
 				if (imapx_update_message_info_flags ((CamelMessageInfo *) info, r->server_flags, r->server_user_flags, is->permanentflags, job->folder, FALSE))
-					camel_folder_change_info_change_uid (job->u.refresh_info.changes, camel_message_info_uid (s_minfo));
+					camel_folder_change_info_change_uid (data->changes, camel_message_info_uid (s_minfo));
 				r->exists = TRUE;
 			} else
 				fetch_new = TRUE;
@@ -4198,51 +3842,45 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 		for (l = removed; l != NULL; l = g_list_next (l)) {
 			gchar *uid = (gchar *) l->data;
 
-			camel_folder_change_info_remove_uid (job->u.refresh_info.changes, uid);
+			camel_folder_change_info_remove_uid (data->changes, uid);
 			camel_folder_summary_remove_uid (s, uid);
 		}
 
-		if (removed) {
+		if (removed != NULL) {
 			const gchar *full_name;
 
 			full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (s));
 			camel_db_delete_uids (is->store->cdb_w, full_name, removed, NULL);
-			g_list_foreach (removed, (GFunc) g_free, NULL);
-			g_list_free (removed);
+			g_list_free_full (removed, (GDestroyNotify) g_free);
 		}
 
 		imapx_update_store_summary (job->folder);
 
-		if (camel_folder_change_info_changed (job->u.refresh_info.changes))
-			camel_folder_changed (job->folder, job->u.refresh_info.changes);
-		camel_folder_change_info_clear (job->u.refresh_info.changes);
+		if (camel_folder_change_info_changed (data->changes))
+			camel_folder_changed (job->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) {
-			if (imapx_job_can_operation_msg (job)) {
-				job->with_operation_msg = TRUE;
+			job->pop_operation_msg = TRUE;
 
-				camel_operation_push_message (
-					job->cancellable,
-					_("Fetching summary information for new messages in %s"),
-					camel_folder_get_display_name (job->folder));
-			}
+			camel_operation_push_message (
+				job->cancellable,
+				_("Fetching summary information for new messages in %s"),
+				camel_folder_get_display_name (job->folder));
 
-			imapx_uidset_init (&job->u.refresh_info.uidset, uidset_size, 0);
+			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. */
-			job->u.refresh_info.update_unseen = TRUE;
-			imapx_command_step_fetch_done (is, ic);
-			return;
+			data->update_unseen = TRUE;
+			return imapx_command_step_fetch_done (is, ic, error);
 		}
-	} else {
-		propagate_ic_error (job, ic, "Error retriving message: %s");
 	}
 
-	for (i = 0; i < infos->len; i++) {
-		struct _refresh_info *r = &g_array_index (infos, struct _refresh_info, i);
+	for (i = 0; i < data->infos->len; i++) {
+		struct _refresh_info *r = &g_array_index (data->infos, struct _refresh_info, i);
 
 		camel_flag_list_free (&r->server_user_flags);
 		g_free (r->uid);
@@ -4252,58 +3890,72 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 	 * select mailbox. So just work it out from the flags */
 	((CamelIMAPXFolder *) job->folder)->unread_on_server = camel_folder_summary_get_unread_count (job->folder->summary);
 
-	g_array_free (job->u.refresh_info.infos, TRUE);
-	imapx_job_done (is, job);
-	imapx_command_unref (ic);
+	g_array_free (data->infos, TRUE);
+	imapx_unregister_job (is, job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_scan_changes_start (CamelIMAPXServer *is,
-                              CamelIMAPXJob *job)
+imapx_job_scan_changes_start (CamelIMAPXJob *job,
+                              CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	RefreshInfoData *data;
 
-	if (imapx_job_can_operation_msg (job)) {
-		job->with_operation_msg = TRUE;
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
 
-		camel_operation_push_message (
-			job->cancellable,
-			_("Scanning for changed messages in %s"),
-			camel_folder_get_display_name (job->folder));
-	}
+	job->pop_operation_msg = TRUE;
 
-	ic = imapx_command_new (
-		is, "FETCH", job->folder, job->cancellable,
+	camel_operation_push_message (
+		job->cancellable,
+		_("Scanning for changed messages in %s"),
+		camel_folder_get_display_name (job->folder));
+
+	ic = camel_imapx_command_new (
+		is, "FETCH", job->folder,
 		"UID FETCH 1:* (UID FLAGS)");
 	ic->job = job;
 	ic->complete = imapx_job_scan_changes_done;
 	ic->pri = job->pri;
-	job->u.refresh_info.infos = g_array_new (0, 0, sizeof (struct _refresh_info));
+	data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
 	imapx_command_queue (is, ic);
 }
 
-static void
+static gboolean
 imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
-                                       CamelIMAPXCommand *ic)
+                                       CamelIMAPXCommand *ic,
+                                       GError **error)
 {
-	CamelIMAPXSummary *isum = (CamelIMAPXSummary *) ic->job->folder->summary;
-	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) ic->job->folder;
+	CamelIMAPXJob *job = ic->job;
+	CamelIMAPXSummary *isum = (CamelIMAPXSummary *) job->folder->summary;
+	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
+	RefreshInfoData *data;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error fetching new messages: %s");
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error fetching new messages"));
+		success = FALSE;
 		goto exception;
 	}
 
-	if (camel_folder_change_info_changed (ic->job->u.refresh_info.changes)) {
-		imapx_update_store_summary (ic->job->folder);
-		camel_folder_summary_save_to_db (ic->job->folder->summary, NULL);
-		camel_folder_changed (ic->job->folder, ic->job->u.refresh_info.changes);
-		camel_folder_change_info_clear (ic->job->u.refresh_info.changes);
+	if (camel_folder_change_info_changed (data->changes)) {
+		imapx_update_store_summary (job->folder);
+		camel_folder_summary_save_to_db (job->folder->summary, NULL);
+		camel_folder_changed (job->folder, data->changes);
+		camel_folder_change_info_clear (data->changes);
 	}
 
-	if (camel_folder_summary_count (ic->job->folder->summary)) {
-		gchar *uid = imapx_get_uid_from_index (ic->job->folder->summary,
-						       camel_folder_summary_count (ic->job->folder->summary) - 1);
+	if (camel_folder_summary_count (job->folder->summary)) {
+		gchar *uid = imapx_get_uid_from_index (job->folder->summary,
+						       camel_folder_summary_count (job->folder->summary) - 1);
 		guint64 uidl = strtoull (uid, NULL, 10);
 		g_free (uid);
 
@@ -4311,7 +3963,7 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
 
 		if (uidl > ifolder->uidnext_on_server) {
 			c(is->tagprefix, "Updating uidnext_on_server for '%s' to %" G_GUINT64_FORMAT "\n",
-			  camel_folder_get_full_name (ic->job->folder), uidl);
+			  camel_folder_get_full_name (job->folder), uidl);
 			ifolder->uidnext_on_server = uidl;
 		}
 	}
@@ -4319,26 +3971,35 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is,
 	isum->uidnext = ifolder->uidnext_on_server;
 
 exception:
-	camel_folder_change_info_free (ic->job->u.refresh_info.changes);
+	imapx_unregister_job (is, job);
+	camel_imapx_command_unref (ic);
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	return success;
 }
 
-static void
+static gboolean
 imapx_command_fetch_new_uids_done (CamelIMAPXServer *is,
-                                   CamelIMAPXCommand *ic)
+                                   CamelIMAPXCommand *ic,
+                                   GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
-	GArray *infos = job->u.refresh_info.infos;
+	RefreshInfoData *data;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
-	qsort (infos->data, infos->len, sizeof (struct _refresh_info), imapx_refresh_info_cmp_descending);
-	imapx_command_step_fetch_done (is, ic);
+	qsort (
+		data->infos->data,
+		data->infos->len,
+		sizeof (struct _refresh_info),
+		imapx_refresh_info_cmp_descending);
+
+	return imapx_command_step_fetch_done (is, ic, error);
 }
 
 static void
-imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
-                                    CamelIMAPXJob *job)
+imapx_job_fetch_new_messages_start (CamelIMAPXJob *job,
+                                    CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
 	CamelFolder *folder = job->folder;
@@ -4346,10 +4007,14 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
 	CamelService *service;
 	CamelSettings *settings;
 	CamelSortType fetch_order;
+	RefreshInfoData *data;
 	guint32 total, diff;
 	guint uidset_size;
 	gchar *uid = NULL;
 
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
 	service = CAMEL_SERVICE (is->store);
 	settings = camel_service_get_settings (service);
 
@@ -4371,21 +4036,19 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
 	} else
 		uid = g_strdup ("1");
 
-	if (imapx_job_can_operation_msg (job)) {
-		job->with_operation_msg = TRUE;
+	job->pop_operation_msg = TRUE;
 
-		camel_operation_push_message (
-			job->cancellable,
-			_("Fetching summary information for new messages in %s"),
-			camel_folder_get_display_name (folder));
-	}
+	camel_operation_push_message (
+		job->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 = imapx_command_new (
-			is, "FETCH", job->folder, job->cancellable,
+		ic = camel_imapx_command_new (
+			is, "FETCH", job->folder,
 			"UID FETCH %s:* (UID FLAGS)", uid);
-		imapx_uidset_init (&job->u.refresh_info.uidset, uidset_size, 0);
-		job->u.refresh_info.infos = g_array_new (0, 0, sizeof (struct _refresh_info));
+		imapx_uidset_init (&data->uidset, uidset_size, 0);
+		data->infos = g_array_new (0, 0, sizeof (struct _refresh_info));
 		ic->pri = job->pri;
 
 		if (fetch_order == CAMEL_SORT_DESCENDING)
@@ -4393,8 +4056,8 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
 		else
 			ic->complete = imapx_command_step_fetch_done;
 	} else {
-		ic = imapx_command_new (
-			is, "FETCH", job->folder, job->cancellable,
+		ic = camel_imapx_command_new (
+			is, "FETCH", job->folder,
 			"UID FETCH %s:* (RFC822.SIZE RFC822.HEADER FLAGS)", uid);
 		ic->pri = job->pri;
 		ic->complete = imapx_command_fetch_new_messages_done;
@@ -4406,8 +4069,8 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
 }
 
 static void
-imapx_job_refresh_info_start (CamelIMAPXServer *is,
-                              CamelIMAPXJob *job)
+imapx_job_refresh_info_start (CamelIMAPXJob *job,
+                              CamelIMAPXServer *is)
 {
 	guint32 total;
 	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) job->folder;
@@ -4479,25 +4142,33 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
 			}
 		} else {
 			if (is->cinfo->capa & IMAPX_CAPABILITY_CONDSTORE)
-				ic = imapx_command_new (
-					is, "STATUS", NULL, job->cancellable,
+				ic = camel_imapx_command_new (
+					is, "STATUS", NULL,
 					"STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT HIGHESTMODSEQ)", folder);
 			else
-				ic = imapx_command_new (
-					is, "STATUS", NULL, job->cancellable,
+				ic = camel_imapx_command_new (
+					is, "STATUS", NULL,
 					"STATUS %f (MESSAGES UNSEEN UIDVALIDITY UIDNEXT)", folder);
 
 			ic->job = job;
 			ic->pri = job->pri;
 
-			imapx_command_run_sync (is, ic);
+			imapx_command_run_sync (
+				is, ic, job->cancellable, &job->error);
+
+			if (ic->job->error == NULL)
+				camel_imapx_command_set_error_if_failed (ic, &ic->job->error);
 
-			if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-				propagate_ic_error (job, ic, "Error refreshing folder: %s");
-				imapx_command_unref (ic);
+			g_prefix_error (
+				&ic->job->error, "%s: ",
+				_("Error refreshing folder"));
+
+			if (ic->job->error != NULL) {
+				camel_imapx_command_unref (ic);
 				goto done;
 			}
-			imapx_command_unref (ic);
+
+			camel_imapx_command_unref (ic);
 		}
 
 		/* Recalulate need_rescan */
@@ -4561,21 +4232,36 @@ imapx_job_refresh_info_start (CamelIMAPXServer *is,
 		}
 	}
 
-	imapx_job_scan_changes_start (is, job);
+	imapx_job_scan_changes_start (job, is);
 	return;
 
 done:
-	imapx_job_done (is, job);
+	imapx_unregister_job (is, job);
+}
+
+static gboolean
+imapx_job_refresh_info_matches (CamelIMAPXJob *job,
+                                CamelFolder *folder,
+                                const gchar *uid)
+{
+	return (folder == job->folder);
 }
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_expunge_done (CamelIMAPXServer *is,
-                            CamelIMAPXCommand *ic)
+                            CamelIMAPXCommand *ic,
+                            GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error expunging message: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error expunging message"));
+		success = FALSE;
+
 	} else {
 		GPtrArray *uids;
 		CamelFolder *folder = ic->job->folder;
@@ -4613,13 +4299,15 @@ imapx_command_expunge_done (CamelIMAPXServer *is,
 		}
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_expunge_start (CamelIMAPXServer *is,
-                         CamelIMAPXJob *job)
+imapx_job_expunge_start (CamelIMAPXJob *job,
+                         CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
 
@@ -4628,52 +4316,80 @@ imapx_job_expunge_start (CamelIMAPXServer *is,
 		job->cancellable, &job->error);
 
 	/* TODO handle UIDPLUS capability */
-	ic = imapx_command_new (
-		is, "EXPUNGE", job->folder,
-		job->cancellable, "EXPUNGE");
+	ic = camel_imapx_command_new (
+		is, "EXPUNGE", job->folder, "EXPUNGE");
 	ic->job = job;
 	ic->pri = job->pri;
 	ic->complete = imapx_command_expunge_done;
 	imapx_command_queue (is, ic);
 }
 
+static gboolean
+imapx_job_expunge_matches (CamelIMAPXJob *job,
+                           CamelFolder *folder,
+                           const gchar *uid)
+{
+	return (folder == job->folder);
+}
+
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_list_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
+                         CamelIMAPXCommand *ic,
+                         GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error fetching folders: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error fetching folders"));
+		success = FALSE;
 	}
 
 	e (is->tagprefix, "==== list or lsub completed ==== \n");
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_list_start (CamelIMAPXServer *is,
-                      CamelIMAPXJob *job)
+imapx_job_list_start (CamelIMAPXJob *job,
+                      CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	ListData *data;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
 
-	ic = imapx_command_new (
-		is, "LIST", NULL, job->cancellable,
+	ic = camel_imapx_command_new (
+		is, "LIST", NULL,
 		"%s \"\" %s",
-		(job->u.list.flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ?
+		(data->flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) ?
 			"LSUB" : "LIST",
-		job->u.list.pattern);
-	if (job->u.list.ext) {
+		data->pattern);
+	if (data->ext) {
 		/* Hm, we need a way to add atoms _without_ quoting or using literals */
-		imapx_command_add (ic, " ");
-		imapx_command_add (ic, job->u.list.ext);
+		camel_imapx_command_add (ic, " ");
+		camel_imapx_command_add (ic, data->ext);
 	}
 	ic->pri = job->pri;
 	ic->job = job;
 	ic->complete = imapx_command_list_done;
 	imapx_command_queue (is, ic);
 }
+
+static gboolean
+imapx_job_list_matches (CamelIMAPXJob *job,
+                        CamelFolder *folder,
+                        const gchar *uid)
+{
+	return TRUE;  /* matches everything */
+}
+
 /* ********************************************************************** */
 
 static gchar *
@@ -4692,37 +4408,48 @@ imapx_encode_folder_name (CamelIMAPXStore *istore,
 	return encoded;
 }
 
-static void
+static gboolean
 imapx_command_subscription_done (CamelIMAPXServer *is,
-                                 CamelIMAPXCommand *ic)
+                                 CamelIMAPXCommand *ic,
+                                 GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error subscribing to folder: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error subscribing to folder"));
+		success = FALSE;
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_manage_subscription_start (CamelIMAPXServer *is,
-                                     CamelIMAPXJob *job)
+imapx_job_manage_subscription_start (CamelIMAPXJob *job,
+                                     CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
-	const gchar *str = NULL;
+	ManageSubscriptionsData *data;
 	gchar *encoded_fname = NULL;
 
-	if (job->u.manage_subscriptions.subscribe)
-		str = "SUBSCRIBE";
-	else
-		str = "UNSUBSCRIBE";
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
 
 	encoded_fname = imapx_encode_folder_name (
 		(CamelIMAPXStore *) is->store,
-		job->u.manage_subscriptions.folder_name);
-	ic = imapx_command_new (
-		is, str, NULL, job->cancellable,
-		"%s %s", str, encoded_fname);
+		data->folder_name);
+	if (data->subscribe)
+		ic = camel_imapx_command_new (
+			is, "SUBSCRIBE", NULL,
+			"SUBSCRIBE %s", encoded_fname);
+	else
+		ic = camel_imapx_command_new (
+			is, "UNSUBSCRIBE", NULL,
+			"UNSUBSCRIBE %s", encoded_fname);
 
 	ic->pri = job->pri;
 	ic->job = job;
@@ -4734,28 +4461,40 @@ imapx_job_manage_subscription_start (CamelIMAPXServer *is,
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_create_folder_done (CamelIMAPXServer *is,
-                                  CamelIMAPXCommand *ic)
+                                  CamelIMAPXCommand *ic,
+                                  GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error creating to folder: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error creating folder"));
+		success = FALSE;
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_create_folder_start (CamelIMAPXServer *is,
-                               CamelIMAPXJob *job)
+imapx_job_create_folder_start (CamelIMAPXJob *job,
+                               CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	CreateFolderData *data;
 	gchar *encoded_fname = NULL;
 
-	encoded_fname = camel_utf8_utf7 (job->u.folder_name);
-	ic = imapx_command_new (
-		is, "CREATE", NULL, job->cancellable,
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
+	encoded_fname = camel_utf8_utf7 (data->folder_name);
+	ic = camel_imapx_command_new (
+		is, "CREATE", NULL,
 		"CREATE %s", encoded_fname);
 	ic->pri = job->pri;
 	ic->job = job;
@@ -4767,33 +4506,45 @@ imapx_job_create_folder_start (CamelIMAPXServer *is,
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_delete_folder_done (CamelIMAPXServer *is,
-                                  CamelIMAPXCommand *ic)
+                                  CamelIMAPXCommand *ic,
+                                  GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error deleting to folder: %s");
+	gboolean success;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error deleting folder"));
+		success = FALSE;
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_delete_folder_start (CamelIMAPXServer *is,
-                               CamelIMAPXJob *job)
+imapx_job_delete_folder_start (CamelIMAPXJob *job,
+                               CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	DeleteFolderData *data;
 	gchar *encoded_fname = NULL;
 
-	encoded_fname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.folder_name);
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
+	encoded_fname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->folder_name);
 
 	job->folder = camel_store_get_folder_sync (
 		is->store, "INBOX", 0, job->cancellable, &job->error);
 
 	/* make sure to-be-deleted folder is not selected by selecting INBOX for this operation */
-	ic = imapx_command_new (
-		is, "DELETE", job->folder, job->cancellable,
+	ic = camel_imapx_command_new (
+		is, "DELETE", job->folder,
 		"DELETE %s", encoded_fname);
 	ic->pri = job->pri;
 	ic->job = job;
@@ -4805,33 +4556,45 @@ imapx_job_delete_folder_start (CamelIMAPXServer *is,
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_rename_folder_done (CamelIMAPXServer *is,
-                                  CamelIMAPXCommand *ic)
+                                  CamelIMAPXCommand *ic,
+                                  GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error renaming folder: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error renaming folder"));
+		success = FALSE;
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_rename_folder_start (CamelIMAPXServer *is,
-                               CamelIMAPXJob *job)
+imapx_job_rename_folder_start (CamelIMAPXJob *job,
+                               CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
+	RenameFolderData *data;
 	gchar *en_ofname = NULL, *en_nfname = NULL;
 
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
 	job->folder = camel_store_get_folder_sync (
 		is->store, "INBOX", 0, job->cancellable, &job->error);
 
-	en_ofname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.ofolder_name);
-	en_nfname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, job->u.rename_folder.nfolder_name);
+	en_ofname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->old_folder_name);
+	en_nfname = imapx_encode_folder_name ((CamelIMAPXStore *) is->store, data->new_folder_name);
 
-	ic = imapx_command_new (
-		is, "RENAME", job->folder, job->cancellable,
+	ic = camel_imapx_command_new (
+		is, "RENAME", job->folder,
 		"RENAME %s %s", en_ofname, en_nfname);
 	ic->pri = job->pri;
 	ic->job = job;
@@ -4844,26 +4607,34 @@ imapx_job_rename_folder_start (CamelIMAPXServer *is,
 
 /* ********************************************************************** */
 
-static void
+static gboolean
 imapx_command_noop_done (CamelIMAPXServer *is,
-                         CamelIMAPXCommand *ic)
+                         CamelIMAPXCommand *ic,
+                         GError **error)
 {
-	if (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		propagate_ic_error (ic->job, ic, "Error performing NOOP: %s");
+	gboolean success = TRUE;
+
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error performing NOOP"));
+		success = FALSE;
 	}
 
-	imapx_job_done (is, ic->job);
-	imapx_command_unref (ic);
+	imapx_unregister_job (is, ic->job);
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_noop_start (CamelIMAPXServer *is,
-                      CamelIMAPXJob *job)
+imapx_job_noop_start (CamelIMAPXJob *job,
+                      CamelIMAPXServer *is)
 {
 	CamelIMAPXCommand *ic;
 
-	ic = imapx_command_new (
-		is, "NOOP", job->folder, job->cancellable, "NOOP");
+	ic = camel_imapx_command_new (
+		is, "NOOP", job->folder, "NOOP");
 
 	ic->job = job;
 	ic->complete = imapx_command_noop_done;
@@ -4901,14 +4672,19 @@ static struct {
  * &flags 00100000
  */
 
-static void
+static gboolean
 imapx_command_sync_changes_done (CamelIMAPXServer *is,
-                                 CamelIMAPXCommand *ic)
+                                 CamelIMAPXCommand *ic,
+                                 GError **error)
 {
 	CamelIMAPXJob *job = ic->job;
 	CamelStore *parent_store;
+	SyncChangesData *data;
 	const gchar *full_name;
-	gboolean failed = FALSE;
+	gboolean success = TRUE;
+
+	data = camel_imapx_job_get_data (job);
+	g_return_val_if_fail (data != NULL, FALSE);
 
 	job->commands--;
 
@@ -4925,24 +4701,19 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
 	 * 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 (ic->error != NULL || ic->status->result != IMAPX_OK) {
-		if (!job->error) {
-			propagate_ic_error (job, ic, "Error syncing changes: %s");
-		} else if (ic->error) {
-			g_clear_error (&ic->error);
-		}
-
-		failed = TRUE;
-	}
+	if (camel_imapx_command_set_error_if_failed (ic, error)) {
+		g_prefix_error (
+			error, "%s: ",
+			_("Error syncing changes"));
+		success = FALSE;
 
 	/* lock cache ? */
-	if (!failed)
-	{
+	} else {
 		gint i;
 
-		for (i = 0; i < job->u.sync_changes.changed_uids->len; i++) {
+		for (i = 0; i < data->changed_uids->len; i++) {
 			CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) camel_folder_summary_get (job->folder->summary,
-					job->u.sync_changes.changed_uids->pdata[i]);
+					data->changed_uids->pdata[i]);
 
 			if (!xinfo)
 				continue;
@@ -4957,7 +4728,7 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
 		}
 		/* Apply the changes to server-side unread count; it won't tell
 		 * us of these changes, of course. */
-		((CamelIMAPXFolder *) job->folder)->unread_on_server += job->u.sync_changes.unread_change;
+		((CamelIMAPXFolder *) job->folder)->unread_on_server += data->unread_change;
 	}
 
 	if (job->commands == 0) {
@@ -4981,23 +4752,32 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
 		camel_folder_summary_save_to_db (job->folder->summary, &job->error);
 		camel_store_summary_save ((CamelStoreSummary *)((CamelIMAPXStore *) parent_store)->summary);
 
-		imapx_job_done (is, job);
+		imapx_unregister_job (is, job);
 	}
-	imapx_command_unref (ic);
+
+	camel_imapx_command_unref (ic);
+
+	return success;
 }
 
 static void
-imapx_job_sync_changes_start (CamelIMAPXServer *is,
-                              CamelIMAPXJob *job)
+imapx_job_sync_changes_start (CamelIMAPXJob *job,
+                              CamelIMAPXServer *is)
 {
+	SyncChangesData *data;
 	guint32 i, j;
 	struct _uidset_state ss;
-	GPtrArray *uids = job->u.sync_changes.changed_uids;
+	GPtrArray *uids;
 	gint on;
 
+	data = camel_imapx_job_get_data (job);
+	g_return_if_fail (data != NULL);
+
+	uids = data->changed_uids;
+
 	for (on = 0; on < 2; on++) {
-		guint32 orset = on ? job->u.sync_changes.on_set : job->u.sync_changes.off_set;
-		GArray *user_set = on ? job->u.sync_changes.on_user : job->u.sync_changes.off_user;
+		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;
@@ -5025,9 +4805,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 				if ( (on && (((flags ^ sflags) & flags) & flag))
 				     || (!on && (((flags ^ sflags) & ~flags) & flag))) {
 					if (ic == NULL) {
-						ic = imapx_command_new (
+						ic = camel_imapx_command_new (
 							is, "STORE", job->folder,
-							job->cancellable, "UID STORE ");
+							"UID STORE ");
 						ic->complete = imapx_command_sync_changes_done;
 						ic->job = job;
 						ic->pri = job->pri;
@@ -5036,7 +4816,7 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 				}
 				if (send || (i == uids->len - 1 && imapx_uidset_done (&ss, ic))) {
 					job->commands++;
-					imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
+					camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", flags_table[j].name);
 					imapx_command_queue (is, ic);
 					ic = NULL;
 				}
@@ -5044,9 +4824,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 					/* Remember how the server's unread count will change if this
 					 * command succeeds */
 					if (on)
-						job->u.sync_changes.unread_change--;
+						data->unread_change--;
 					else
-						job->u.sync_changes.unread_change++;
+						data->unread_change++;
 				}
 				camel_message_info_free (info);
 			}
@@ -5063,9 +4843,9 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 					CamelIMAPXMessageInfo *info = c->infos->pdata[i];
 
 					if (ic == NULL) {
-						ic = imapx_command_new (
+						ic = camel_imapx_command_new (
 							is, "STORE", job->folder,
-							job->cancellable, "UID STORE ");
+							"UID STORE ");
 						ic->complete = imapx_command_sync_changes_done;
 						ic->job = job;
 						ic->pri = job->pri;
@@ -5074,7 +4854,7 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 					if (imapx_uidset_add (&ss, ic, camel_message_info_uid (info))
 					    || (i == c->infos->len - 1 && imapx_uidset_done (&ss, ic))) {
 						job->commands++;
-						imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
+						camel_imapx_command_add (ic, " %tFLAGS.SILENT (%t)", on?"+":"-", c->name);
 						imapx_command_queue (is, ic);
 						ic = NULL;
 					}
@@ -5087,37 +4867,44 @@ imapx_job_sync_changes_start (CamelIMAPXServer *is,
 	 * lock the commands count, ho hum */
 
 	if (job->commands == 0) {
-		imapx_job_done (is, job);
+		imapx_unregister_job (is, job);
 	}
 }
 
+static gboolean
+imapx_job_sync_changes_matches (CamelIMAPXJob *job,
+                                CamelFolder *folder,
+                                const gchar *uid)
+{
+	return (folder == job->folder);
+}
+
 /* we cancel all the commands and their jobs, so associated jobs will be notified */
 static void
 cancel_all_jobs (CamelIMAPXServer *is,
                  GError *error)
 {
-	CamelIMAPXCommand **cw, *ic;
-	gint i = 0;
+	CamelIMAPXCommand *ic;
+	GQueue queue = G_QUEUE_INIT;
 
-	while (i < 2) {
-		QUEUE_LOCK (is);
-		if (i == 1)
-			cw = (CamelIMAPXCommand **) &is->queue.head;
-		else
-			cw = (CamelIMAPXCommand **) &is->active.head;
+	QUEUE_LOCK (is);
 
-		while ((*cw)->next) {
-			ic = *cw;
-			camel_dlist_remove ((CamelDListNode *) ic);
-			QUEUE_UNLOCK (is);
+	while ((ic = g_queue_pop_head (&is->queue)) != NULL)
+		g_queue_push_tail (&queue, ic);
 
-			ic->error = g_error_copy (error);
-			ic->complete (is, ic);
+	while ((ic = g_queue_pop_head (&is->active)) != NULL)
+		g_queue_push_tail (&queue, ic);
 
-			QUEUE_LOCK (is);
-		}
-		QUEUE_UNLOCK (is);
-		i++;
+	QUEUE_UNLOCK (is);
+
+	while ((ic = g_queue_pop_head (&queue)) != NULL) {
+		if (ic->job->error == NULL)
+			ic->job->error = g_error_copy (error);
+
+		/* Send a NULL GError since we've already set
+		 * the job's GError, and we're not interested
+		 * in individual command errors. */
+		ic->complete (is, ic, NULL);
 	}
 }
 
@@ -5128,18 +4915,9 @@ parse_contents (CamelIMAPXServer *is,
                 GCancellable *cancellable,
                 GError **error)
 {
-	gint buffered = 0;
-	GError *local_error = NULL;
-
-	do {
-		imapx_step (is, cancellable, &local_error);
-
-		buffered = camel_imapx_stream_buffered (is->stream);
-
-	} while (buffered && local_error == NULL);
-
-	if (local_error != NULL)
-		g_propagate_error (error, local_error);
+	while (imapx_step (is, cancellable, error))
+		if (camel_imapx_stream_buffered (is->stream) == 0)
+			break;
 }
 
 /*
@@ -5194,7 +4972,7 @@ imapx_parser_thread (gpointer d)
 			gint is_empty;
 
 			QUEUE_LOCK (is);
-			is_empty = camel_dlist_empty (&is->active);
+			is_empty = g_queue_is_empty (&is->active);
 			QUEUE_UNLOCK (is);
 
 			if (is_empty || (imapx_idle_supported (is) && imapx_in_idle (is))) {
@@ -5356,9 +5134,9 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
 static void
 camel_imapx_server_init (CamelIMAPXServer *is)
 {
-	camel_dlist_init (&is->queue);
-	camel_dlist_init (&is->active);
-	camel_dlist_init (&is->done);
+	g_queue_init (&is->queue);
+	g_queue_init (&is->active);
+	g_queue_init (&is->done);
 	g_queue_init (&is->jobs);
 
 	/* not used at the moment. Use it in future */
@@ -5467,10 +5245,11 @@ imapx_server_get_message (CamelIMAPXServer *is,
                           GCancellable *cancellable,
                           GError **error)
 {
-	CamelStream *stream = NULL, *tmp_stream;
+	CamelStream *stream = NULL;
 	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
 	CamelIMAPXJob *job;
 	CamelMessageInfo *mi;
+	GetMessageData *data;
 	gboolean registered;
 	gboolean success;
 
@@ -5522,33 +5301,34 @@ imapx_server_get_message (CamelIMAPXServer *is,
 		return NULL;
 	}
 
-	tmp_stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
+	data = g_slice_new0 (GetMessageData);
+	data->uid = g_strdup (uid);
+	data->stream = camel_data_cache_add (ifolder->cache, "tmp", uid, NULL);
+	data->size = ((CamelMessageInfoBase *) mi)->size;
+	if (data->size > MULTI_SIZE)
+		data->use_multi_fetch = TRUE;
 
-	job = imapx_job_new (cancellable);
+	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;
 	job->folder = folder;
-	job->u.get_message.uid = (gchar *) uid;
-	job->u.get_message.stream = tmp_stream;
 
-	if (((CamelMessageInfoBase *) mi)->size > MULTI_SIZE)
-		job->u.get_message.use_multi_fetch = TRUE;
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) get_message_data_free);
 
-	job->u.get_message.size = ((CamelMessageInfoBase *) mi)->size;
 	camel_message_info_free (mi);
 	registered = imapx_register_job (is, job, error);
 
 	QUEUE_UNLOCK (is);
 
-	success = registered && imapx_run_job (is, job, error);
+	success = registered && camel_imapx_job_run (job, is, error);
 
 	if (success)
-		stream = job->u.get_message.stream;
-	else if (job->u.get_message.stream != NULL)
-		g_object_unref (job->u.get_message.stream);
+		stream = g_object_ref (data->stream);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	g_mutex_lock (is->fetch_mutex);
 	is->fetch_count++;
@@ -5620,18 +5400,25 @@ camel_imapx_server_copy_message (CamelIMAPXServer *is,
                                  GError **error)
 {
 	CamelIMAPXJob *job;
+	CopyMessagesData *data;
+	gint ii;
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (CopyMessagesData);
+	data->dest = g_object_ref (dest);
+	data->uids = g_ptr_array_new ();
+	data->delete_originals = delete_originals;
+
+	for (ii = 0; ii < uids->len; ii++)
+		g_ptr_array_add (data->uids, g_strdup (uids->pdata[ii]));
+
+	job = camel_imapx_job_new (cancellable);
 	job->pri = IMAPX_PRIORITY_APPEND_MESSAGE;
 	job->type = IMAPX_JOB_COPY_MESSAGE;
 	job->start = imapx_job_copy_messages_start;
-	job->folder = source;
-	job->u.copy_messages.dest = dest;
-	job->u.copy_messages.uids = uids;
-	job->u.copy_messages.delete_originals = delete_originals;
+	job->folder = g_object_ref (source);
 
-	g_object_ref (source);
-	g_object_ref (dest);
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) copy_messages_data_free);
 
 	return imapx_submit_job (is, job, error);
 }
@@ -5644,12 +5431,13 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
                                    GCancellable *cancellable,
                                    GError **error)
 {
-	gchar *uid = NULL, *tmp = NULL;
+	gchar *uid = NULL, *path = NULL;
 	CamelStream *stream, *filter;
 	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
 	CamelMimeFilter *canon;
 	CamelIMAPXJob *job;
 	CamelMessageInfo *info;
+	AppendMessageData *data;
 	gint res;
 	gboolean success;
 
@@ -5683,7 +5471,7 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 		return FALSE;
 	}
 
-	tmp = camel_data_cache_get_filename (ifolder->cache, "new", uid, NULL);
+	path = camel_data_cache_get_filename (ifolder->cache, "new", uid, NULL);
 	info = camel_folder_summary_info_new_from_message ((CamelFolderSummary *) folder->summary, message, NULL);
 	info->uid = camel_pstring_strdup (uid);
 	if (mi)
@@ -5695,18 +5483,23 @@ camel_imapx_server_append_message (CamelIMAPXServer *is,
 	 * mechanism is used for normal uploading as well as
 	 * offline re-syncing when we go back online */
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (AppendMessageData);
+	data->info = info;  /* takes ownership */
+	data->path = path;  /* takes ownership */
+
+	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->folder = g_object_ref (folder);
 	job->noreply = FALSE;
-	job->u.append_message.info = info;
-	job->u.append_message.path = tmp;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) append_message_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -5720,7 +5513,7 @@ camel_imapx_server_noop (CamelIMAPXServer *is,
 	CamelIMAPXJob *job;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_NOOP;
 	job->start = imapx_job_noop_start;
 	job->folder = folder;
@@ -5728,7 +5521,7 @@ camel_imapx_server_noop (CamelIMAPXServer *is,
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -5740,6 +5533,7 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
                                  GError **error)
 {
 	CamelIMAPXJob *job;
+	RefreshInfoData *data;
 	gboolean registered = TRUE;
 	const gchar *full_name;
 	gboolean success = TRUE;
@@ -5753,28 +5547,32 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is,
 		return TRUE;
 	}
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (RefreshInfoData);
+	data->changes = camel_folder_change_info_new ();
+
+	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->folder = folder;
-	job->u.refresh_info.changes = camel_folder_change_info_new ();
 	job->pri = IMAPX_PRIORITY_REFRESH_INFO;
 
 	if (g_ascii_strcasecmp(full_name, "INBOX") == 0)
 		job->pri += 10;
 
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) refresh_info_data_free);
+
 	registered = imapx_register_job (is, job, error);
 
 	QUEUE_UNLOCK (is);
 
-	success = registered && imapx_run_job (is, job, error);
+	success = registered && camel_imapx_job_run (job, is, error);
 
-	if (success && camel_folder_change_info_changed (job->u.refresh_info.changes))
-		camel_folder_changed (folder, job->u.refresh_info.changes);
+	if (success && camel_folder_change_info_changed (data->changes))
+		camel_folder_changed (folder, data->changes);
 
-	camel_folder_change_info_free (job->u.refresh_info.changes);
-
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -5815,6 +5613,7 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 	GArray *on_user = NULL, *off_user = NULL;
 	CamelIMAPXMessageInfo *info;
 	CamelIMAPXJob *job;
+	SyncChangesData *data;
 	gboolean registered;
 	gboolean success = TRUE;
 
@@ -5917,8 +5716,11 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 	}
 
 	if ((on_orset | off_orset) == 0 && on_user == NULL && off_user == NULL) {
-		success = TRUE;
-		goto done;
+		imapx_sync_free_user (on_user);
+		imapx_sync_free_user (off_user);
+		camel_folder_free_uids (folder, uids);
+
+		return TRUE;
 	}
 
 	/* TODO above code should go into changes_start */
@@ -5930,33 +5732,39 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
 			job->pri = pri;
 
 		QUEUE_UNLOCK (is);
-		goto done;
+
+		imapx_sync_free_user (on_user);
+		imapx_sync_free_user (off_user);
+		camel_folder_free_uids (folder, uids);
+
+		return TRUE;
 	}
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (SyncChangesData);
+	data->folder = g_object_ref (folder);
+	data->changed_uids = uids;  /* takes ownership */
+	data->on_set = on_orset;
+	data->off_set = off_orset;
+	data->on_user = on_user;  /* takes ownership */
+	data->off_user = off_user;  /* takes ownership */
+
+	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;
 	job->folder = folder;
-	job->u.sync_changes.changed_uids = uids;
-	job->u.sync_changes.on_set = on_orset;
-	job->u.sync_changes.off_set = off_orset;
-	job->u.sync_changes.on_user = on_user;
-	job->u.sync_changes.off_user = off_user;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) sync_changes_data_free);
 
 	registered = imapx_register_job (is, job, error);
 
 	QUEUE_UNLOCK (is);
 
-	success = registered && imapx_run_job (is, job, error);
-
-	imapx_job_unref (job);
-
-done:
-	imapx_sync_free_user (on_user);
-	imapx_sync_free_user (off_user);
+	success = registered && camel_imapx_job_run (job, is, error);
 
-	camel_folder_free_uids (folder, uids);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -5991,9 +5799,10 @@ camel_imapx_server_expunge (CamelIMAPXServer *is,
 		return TRUE;
 	}
 
-	job = imapx_job_new (cancellable);
+	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;
 	job->folder = folder;
 
@@ -6001,9 +5810,9 @@ camel_imapx_server_expunge (CamelIMAPXServer *is,
 
 	QUEUE_UNLOCK (is);
 
-	success = registered && imapx_run_job (is, job, error);
+	success = registered && camel_imapx_job_run (job, is, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -6060,22 +5869,29 @@ camel_imapx_server_list (CamelIMAPXServer *is,
 {
 	CamelIMAPXJob *job;
 	GPtrArray *folders = NULL;
+	ListData *data;
 	gchar *encoded_name;
 
 	encoded_name = camel_utf8_utf7 (top);
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (ListData);
+	data->flags = flags;
+	data->ext = g_strdup (ext);
+	data->folders = g_hash_table_new (imapx_name_hash, imapx_name_equal);
+
+	if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
+		data->pattern = g_strdup_printf ("%s*", encoded_name);
+	else
+		data->pattern = g_strdup (encoded_name);
+
+	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;
-	job->u.list.ext = ext;
-	job->u.list.flags = flags;
-	job->u.list.folders = g_hash_table_new (imapx_name_hash, imapx_name_equal);
-	job->u.list.pattern = g_alloca (strlen (encoded_name) + 5);
-	if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
-		sprintf(job->u.list.pattern, "%s*", encoded_name);
-	else
-		sprintf(job->u.list.pattern, "%s", encoded_name);
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) list_data_free);
 
 	/* sync operation which is triggered by user */
 	if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST)
@@ -6083,13 +5899,12 @@ camel_imapx_server_list (CamelIMAPXServer *is,
 
 	if (imapx_submit_job (is, job, error)) {
 		folders = g_ptr_array_new ();
-		g_hash_table_foreach (job->u.list.folders, imapx_list_flatten, folders);
+		g_hash_table_foreach (data->folders, imapx_list_flatten, folders);
 		qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), imapx_list_cmp);
 	}
 
-	g_hash_table_destroy (job->u.list.folders);
 	g_free (encoded_name);
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return folders;
 }
@@ -6102,18 +5917,24 @@ camel_imapx_server_manage_subscription (CamelIMAPXServer *is,
                                         GError **error)
 {
 	CamelIMAPXJob *job;
+	ManageSubscriptionsData *data;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (ManageSubscriptionsData);
+	data->folder_name = g_strdup (folder_name);
+	data->subscribe = subscribe;
+
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_MANAGE_SUBSCRIPTION;
 	job->start = imapx_job_manage_subscription_start;
 	job->pri = IMAPX_PRIORITY_MANAGE_SUBSCRIPTION;
-	job->u.manage_subscriptions.subscribe = subscribe;
-	job->u.manage_subscriptions.folder_name = folder_name;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) manage_subscriptions_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -6125,17 +5946,23 @@ camel_imapx_server_create_folder (CamelIMAPXServer *is,
                                   GError **error)
 {
 	CamelIMAPXJob *job;
+	CreateFolderData *data;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (CreateFolderData);
+	data->folder_name = g_strdup (folder_name);
+
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_CREATE_FOLDER;
 	job->start = imapx_job_create_folder_start;
 	job->pri = IMAPX_PRIORITY_CREATE_FOLDER;
-	job->u.folder_name = folder_name;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) create_folder_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -6147,17 +5974,23 @@ camel_imapx_server_delete_folder (CamelIMAPXServer *is,
                                   GError **error)
 {
 	CamelIMAPXJob *job;
+	DeleteFolderData *data;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (DeleteFolderData);
+	data->folder_name = g_strdup (folder_name);
+
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_DELETE_FOLDER;
 	job->start = imapx_job_delete_folder_start;
 	job->pri = IMAPX_PRIORITY_DELETE_FOLDER;
-	job->u.folder_name = folder_name;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) delete_folder_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
@@ -6170,18 +6003,24 @@ camel_imapx_server_rename_folder (CamelIMAPXServer *is,
                                   GError **error)
 {
 	CamelIMAPXJob *job;
+	RenameFolderData *data;
 	gboolean success;
 
-	job = imapx_job_new (cancellable);
+	data = g_slice_new0 (RenameFolderData);
+	data->old_folder_name = g_strdup (old_name);
+	data->new_folder_name = g_strdup (new_name);
+
+	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_RENAME_FOLDER;
 	job->start = imapx_job_rename_folder_start;
 	job->pri = IMAPX_PRIORITY_RENAME_FOLDER;
-	job->u.rename_folder.ofolder_name = old_name;
-	job->u.rename_folder.nfolder_name = new_name;
+
+	camel_imapx_job_set_data (
+		job, data, (GDestroyNotify) rename_folder_data_free);
 
 	success = imapx_submit_job (is, job, error);
 
-	imapx_job_unref (job);
+	camel_imapx_job_unref (job);
 
 	return success;
 }
diff --git a/src/camel/providers/imapx/camel-imapx-server.h b/src/camel/providers/imapx/camel-imapx-server.h
index f7ed66d..a5de8a6 100644
--- a/src/camel/providers/imapx/camel-imapx-server.h
+++ b/src/camel/providers/imapx/camel-imapx-server.h
@@ -82,9 +82,9 @@ struct _CamelIMAPXServer {
 	 * all the time, so they can be cleaned up in exception cases */
 	GStaticRecMutex queue_lock;
 	CamelIMAPXCommand *literal;
-	CamelDList queue;
-	CamelDList active;
-	CamelDList done;
+	GQueue queue;
+	GQueue active;
+	GQueue done;
 
 	/* info on currently selected folder */
 	CamelFolder *select_folder;
@@ -127,8 +127,9 @@ struct _CamelIMAPXServerClass {
 	CamelObjectClass parent_class;
 
 	/* Signals */
-	void	(*select_changed)	(CamelIMAPXServer *server, const gchar *selected_folder);
-	void	(*shutdown)		(CamelIMAPXServer *server);
+	void	(*select_changed)	(CamelIMAPXServer *is,
+					 const gchar *selected_folder);
+	void	(*shutdown)		(CamelIMAPXServer *is);
 
 	gchar tagprefix;
 };
@@ -188,7 +189,7 @@ gboolean	camel_imapx_server_append_message
 						 const CamelMessageInfo *mi,
 						 GCancellable *cancellable,
 						 GError **error);
-gboolean	camel_imapx_server_sync_message (CamelIMAPXServer *is,
+gboolean	camel_imapx_server_sync_message	(CamelIMAPXServer *is,
 						 CamelFolder *folder,
 						 const gchar *uid,
 						 GCancellable *cancellable,
@@ -199,15 +200,18 @@ gboolean	camel_imapx_server_manage_subscription
 						 gboolean subscribe,
 						 GCancellable *cancellable,
 						 GError **error);
-gboolean	camel_imapx_server_create_folder (CamelIMAPXServer *is,
+gboolean	camel_imapx_server_create_folder
+						(CamelIMAPXServer *is,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
-gboolean	camel_imapx_server_delete_folder (CamelIMAPXServer *is,
+gboolean	camel_imapx_server_delete_folder
+						(CamelIMAPXServer *is,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
-gboolean	camel_imapx_server_rename_folder (CamelIMAPXServer *is,
+gboolean	camel_imapx_server_rename_folder
+						(CamelIMAPXServer *is,
 						 const gchar *old_name,
 						 const gchar *new_name,
 						 GCancellable *cancellable,
diff --git a/src/camel/providers/imapx/camel-imapx-store.c b/src/camel/providers/imapx/camel-imapx-store.c
index 1cc4b1f..0ed414d 100644
--- a/src/camel/providers/imapx/camel-imapx-store.c
+++ b/src/camel/providers/imapx/camel-imapx-store.c
@@ -1053,16 +1053,29 @@ imapx_refresh_finfo (CamelSession *session,
                      CamelIMAPXStore *store,
                      GError **error)
 {
+	CamelService *service;
+	const gchar *display_name;
+
+	service = CAMEL_SERVICE (store);
+	display_name = camel_service_get_display_name (service);
+
+	camel_operation_push_message (
+		cancellable, _("Retrieving folder list for %s"),
+		display_name);
+
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
-		return;
+		goto exit;
 
 	if (!camel_service_connect_sync (CAMEL_SERVICE (store), error))
-		return;
+		goto exit;
 
 	/* look in all namespaces */
 	sync_folders (store, "", FALSE, cancellable, error);
 
 	camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
+
+exit:
+	camel_operation_pop_message (cancellable);
 }
 
 static void
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index a9cf44c..b04c01e 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.c
+++ b/src/camel/providers/imapx/camel-imapx-utils.c
@@ -184,53 +184,43 @@ rename_label_flag (const gchar *flag,
 }
 
 void
-imapx_write_flags (CamelStream *stream,
+imapx_write_flags (GString *string,
                    guint32 flags,
-                   CamelFlag *user_flags,
-                   GCancellable *cancellable,
-                   GError **error)
-/* throws IO exception */
+                   CamelFlag *user_flags)
 {
 	gint i;
 	gboolean first = TRUE;
 
-	if (camel_stream_write(stream, "(", 1, cancellable, error) == -1) {
-		return;
-	}
+	g_string_append_c (string, '(');
 
 	for (i = 0; flags != 0 && i< G_N_ELEMENTS (flag_table); i++) {
 		if (flag_table[i].flag & flags) {
 			if (flags & CAMEL_IMAPX_MESSAGE_RECENT)
 				continue;
-			if (!first && camel_stream_write(stream, " ", 1, cancellable, error) == -1) {
-				return;
-			}
+			if (!first)
+				g_string_append_c (string, ' ');
 			first = FALSE;
-			if (camel_stream_write (stream, flag_table[i].name, strlen (flag_table[i].name), cancellable, error) == -1) {
-				return;
-			}
+			g_string_append (string, flag_table[i].name);
 
 			flags &= ~flag_table[i].flag;
 		}
 	}
 
 	while (user_flags) {
-		const gchar *flag_name = rename_label_flag (user_flags->name, strlen (user_flags->name), FALSE);
+		const gchar *flag_name;
 
-		if (!first && camel_stream_write(stream, " ", 1, cancellable, error) == -1) {
-			return;
-		}
+		flag_name = rename_label_flag (
+			user_flags->name, strlen (user_flags->name), FALSE);
+
+		if (!first)
+			g_string_append_c (string, ' ');
 		first = FALSE;
-		if (camel_stream_write (stream, flag_name, strlen (flag_name), cancellable, error) == -1) {
-			return;
-		}
+		g_string_append (string, flag_name);
 
 		user_flags = user_flags->next;
 	}
 
-	if (camel_stream_write(stream, ")", 1, cancellable, error) == -1) {
-		return;
-	}
+	g_string_append_c (string, ')');
 }
 
 static gboolean
diff --git a/src/camel/providers/imapx/camel-imapx-utils.h b/src/camel/providers/imapx/camel-imapx-utils.h
index 848c01a..e4bafa4 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.h
+++ b/src/camel/providers/imapx/camel-imapx-utils.h
@@ -85,7 +85,7 @@ enum {
 
 GPtrArray *imapx_parse_uids (struct _CamelIMAPXStream *is, GCancellable *cancellable, GError **error);
 void imapx_parse_flags (struct _CamelIMAPXStream *stream, guint32 *flagsp, struct _CamelFlag **user_flagsp, GCancellable *cancellable, GError **error);
-void imapx_write_flags (CamelStream *stream, guint32 flags, struct _CamelFlag *user_flags, GCancellable *cancellable, GError **error);
+void imapx_write_flags (GString *string, guint32 flags, struct _CamelFlag *user_flags);
 gboolean imapx_update_message_info_flags (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags, guint32 permanent_flags, CamelFolder *folder, gboolean unsolicited);
 void imapx_set_message_info_flags_for_new_message (CamelMessageInfo *info, guint32 server_flags, CamelFlag *server_user_flags,
 							CamelFolder *folder);



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