[evolution-data-server] Camel: Add an asynchronous API.



commit cea02d071c2e5334d5f38b802d32e47bf06766cc
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Sep 23 14:04:32 2010 -0400

    Camel: Add an asynchronous API.
    
    Add pairs of asynchronous "dispatch" and "finish" methods for most
    blocking "sync" methods in Camel's public API.  All asynchronous methods
    have default implementations that just call its synchronous counterpart
    from a thread in GIO's thread pool (which is roughly equivalent to what
    Evolution is doing from its own thread pool).
    
    The possibility for Camel providers to implement an asynchronous
    architecture by overriding the asynchronous methods exists, but first
    requires some cleanup in the synchronous dispatching functions, many of
    which are not "pure" in the sense that they do extra stuff before and
    after calling the class method they wrap.  That extra logic needs to
    somehow run as part of the class method itself, either via chaining up
    from subclasses or some other means.
    
    In simpler terms, the following invariant must hold before providers can
    override asynchronous methods and expect correct behavior from Camel:
    
        Calling camel_foo_frobnicate_sync(foo) is equivalent to calling
        CAMEL_FOO_GET_CLASS (foo)->frobnicate_sync (foo), just with fewer
        runtime checks.

 camel/camel-cipher-context.c                       | 1281 ++++++++--
 camel/camel-cipher-context.h                       |  172 +-
 camel/camel-data-wrapper.c                         |  573 ++++-
 camel/camel-data-wrapper.h                         |   81 +-
 camel/camel-db.h                                   |    2 +-
 camel/camel-disco-diary.c                          |    9 +-
 camel/camel-disco-folder.c                         |   14 +-
 camel/camel-filter-driver.c                        |   18 +-
 camel/camel-folder-search.c                        |    3 +-
 camel/camel-folder-summary.c                       |    5 +-
 camel/camel-folder-summary.h                       |    2 +-
 camel/camel-folder.c                               | 1732 +++++++++---
 camel/camel-folder.h                               |  176 ++-
 camel/camel-gpg-context.c                          |   59 +-
 camel/camel-mime-message.c                         |   25 +-
 camel/camel-mime-message.h                         |  102 +-
 camel/camel-mime-part-utils.c                      |   18 +-
 camel/camel-mime-part.c                            |  736 +++--
 camel/camel-mime-part.h                            |   33 +-
 camel/camel-multipart-signed.c                     |    6 +-
 camel/camel-net-utils.c                            |    8 +-
 camel/camel-offline-folder.c                       |  193 ++-
 camel/camel-offline-folder.h                       |   29 +-
 camel/camel-operation.c                            |  249 +--
 camel/camel-operation.h                            |   11 +-
 camel/camel-sasl.c                                 |  321 ++-
 camel/camel-sasl.h                                 |   32 +
 camel/camel-smime-context.c                        |   26 +-
 camel/camel-store.c                                | 3012 +++++++++++++++-----
 camel/camel-store.h                                |  246 ++-
 camel/camel-transport.c                            |  238 ++-
 camel/camel-transport.h                            |   32 +-
 camel/camel-vee-folder.c                           |    4 +-
 camel/camel-vtrash-folder.c                        |    6 +-
 camel/providers/groupwise/camel-groupwise-folder.c |   26 +-
 .../providers/groupwise/camel-groupwise-journal.c  |    4 +-
 camel/providers/groupwise/camel-groupwise-store.c  |   10 +-
 .../groupwise/camel-groupwise-transport.c          |    8 +-
 camel/providers/imap/camel-imap-folder.c           |  119 +-
 camel/providers/imap/camel-imap-folder.h           |    4 +-
 camel/providers/imap/camel-imap-journal.c          |    2 +-
 camel/providers/imapx/camel-imapx-folder.c         |    8 +-
 camel/providers/imapx/camel-imapx-server.c         |    6 +-
 camel/providers/local/camel-maildir-folder.c       |   17 +-
 camel/providers/local/camel-maildir-summary.c      |   17 +-
 camel/providers/local/camel-mbox-folder.c          |    6 +-
 camel/providers/local/camel-mbox-summary.c         |   22 +-
 camel/providers/local/camel-mh-folder.c            |    6 +-
 camel/providers/local/camel-spool-summary.c        |    8 +-
 camel/providers/nntp/camel-nntp-folder.c           |    2 +-
 camel/providers/nntp/camel-nntp-summary.c          |   10 +-
 camel/providers/pop3/camel-pop3-folder.c           |   30 +-
 camel/providers/smtp/camel-smtp-transport.c        |   32 +-
 docs/reference/camel/camel-docs.sgml               |    4 +
 docs/reference/camel/camel-sections.txt            |   92 +-
 .../reference/camel/tmpl/camel-cipher-context.sgml |  206 ++-
 docs/reference/camel/tmpl/camel-data-wrapper.sgml  |   72 +
 docs/reference/camel/tmpl/camel-db.sgml            |    4 +-
 .../reference/camel/tmpl/camel-folder-summary.sgml |    1 +
 docs/reference/camel/tmpl/camel-folder.sgml        |  179 ++-
 docs/reference/camel/tmpl/camel-mime-message.sgml  |   12 +-
 docs/reference/camel/tmpl/camel-mime-part.sgml     |   29 +-
 .../reference/camel/tmpl/camel-offline-folder.sgml |   30 +-
 docs/reference/camel/tmpl/camel-operation.sgml     |   18 +-
 docs/reference/camel/tmpl/camel-sasl.sgml          |   48 +
 docs/reference/camel/tmpl/camel-store.sgml         |  290 ++-
 docs/reference/camel/tmpl/camel-transport.sgml     |   48 +-
 docs/reference/camel/tmpl/camel-unused.sgml        |  346 +--
 68 files changed, 8702 insertions(+), 2468 deletions(-)
---
diff --git a/camel/camel-cipher-context.c b/camel/camel-cipher-context.c
index 3ffa355..782e997 100644
--- a/camel/camel-cipher-context.c
+++ b/camel/camel-cipher-context.c
@@ -50,11 +50,26 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_CIPHER_CONTEXT, CamelCipherContextPrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelCipherContextPrivate {
 	CamelSession *session;
 	GMutex *lock;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	CamelCipherHash hash;
+	CamelMimePart *ipart;
+	CamelMimePart *opart;
+	CamelStream *stream;
+	GPtrArray *strings;
+	gchar *userid;
+
+	/* results */
+	CamelCipherValidity *validity;
+};
+
 enum {
 	PROP_0,
 	PROP_SESSION
@@ -63,6 +78,32 @@ enum {
 G_DEFINE_TYPE (CamelCipherContext, camel_cipher_context, CAMEL_TYPE_OBJECT)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->ipart != NULL)
+		g_object_unref (async_context->ipart);
+
+	if (async_context->opart != NULL)
+		g_object_unref (async_context->opart);
+
+	if (async_context->stream != NULL)
+		g_object_unref (async_context->stream);
+
+	if (async_context->strings != NULL) {
+		g_ptr_array_foreach (
+			async_context->strings, (GFunc) g_free, NULL);
+		g_ptr_array_free (async_context->strings, TRUE);
+	}
+
+	if (async_context->validity != NULL)
+		camel_cipher_validity_free (async_context->validity);
+
+	g_free (async_context->userid);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 cipher_context_set_session (CamelCipherContext *context,
                             CamelSession *session)
 {
@@ -136,40 +177,40 @@ cipher_context_finalize (GObject *object)
 }
 
 static const gchar *
-cipher_hash_to_id (CamelCipherContext *context,
-                   CamelCipherHash hash)
+cipher_context_hash_to_id (CamelCipherContext *context,
+                           CamelCipherHash hash)
 {
 	return NULL;
 }
 
 static CamelCipherHash
-cipher_id_to_hash (CamelCipherContext *context,
-                   const gchar *id)
+cipher_context_id_to_hash (CamelCipherContext *context,
+                           const gchar *id)
 {
 	return CAMEL_CIPHER_HASH_DEFAULT;
 }
 
-static gint
-cipher_sign_sync (CamelCipherContext *ctx,
-                  const gchar *userid,
-                  CamelCipherHash hash,
-                  CamelMimePart *ipart,
-                  CamelMimePart *opart,
-                  GCancellable *cancellable,
-                  GError **error)
+static gboolean
+cipher_context_sign_sync (CamelCipherContext *ctx,
+                          const gchar *userid,
+                          CamelCipherHash hash,
+                          CamelMimePart *ipart,
+                          CamelMimePart *opart,
+                          GCancellable *cancellable,
+                          GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
 		_("Signing is not supported by this cipher"));
 
-	return -1;
+	return FALSE;
 }
 
 static CamelCipherValidity *
-cipher_verify_sync (CamelCipherContext *context,
-                    CamelMimePart *sigpart,
-                    GCancellable *cancellable,
-                    GError **error)
+cipher_context_verify_sync (CamelCipherContext *context,
+                            CamelMimePart *sigpart,
+                            GCancellable *cancellable,
+                            GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
@@ -178,28 +219,28 @@ cipher_verify_sync (CamelCipherContext *context,
 	return NULL;
 }
 
-static gint
-cipher_encrypt_sync (CamelCipherContext *context,
-                     const gchar *userid,
-                     GPtrArray *recipients,
-                     CamelMimePart *ipart,
-                     CamelMimePart *opart,
-                     GCancellable *cancellable,
-                     GError **error)
+static gboolean
+cipher_context_encrypt_sync (CamelCipherContext *context,
+                             const gchar *userid,
+                             GPtrArray *recipients,
+                             CamelMimePart *ipart,
+                             CamelMimePart *opart,
+                             GCancellable *cancellable,
+                             GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
 		_("Encryption is not supported by this cipher"));
 
-	return -1;
+	return FALSE;
 }
 
 static CamelCipherValidity *
-cipher_decrypt_sync (CamelCipherContext *context,
-                     CamelMimePart *ipart,
-                     CamelMimePart *opart,
-                     GCancellable *cancellable,
-                     GError **error)
+cipher_context_decrypt_sync (CamelCipherContext *context,
+                             CamelMimePart *ipart,
+                             CamelMimePart *opart,
+                             GCancellable *cancellable,
+                             GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
@@ -208,31 +249,469 @@ cipher_decrypt_sync (CamelCipherContext *context,
 	return NULL;
 }
 
-static gint
-cipher_import_keys_sync (CamelCipherContext *context,
-                         CamelStream *istream,
-                         GCancellable *cancellable,
-                         GError **error)
+static gboolean
+cipher_context_import_keys_sync (CamelCipherContext *context,
+                                 CamelStream *istream,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
 		_("You may not import keys with this cipher"));
 
-	return -1;
+	return FALSE;
 }
 
 static gint
-cipher_export_keys_sync (CamelCipherContext *context,
-                         GPtrArray *keys,
-                         CamelStream *ostream,
-                         GCancellable *cancellable,
-                         GError **error)
+cipher_context_export_keys_sync (CamelCipherContext *context,
+                                 GPtrArray *keys,
+                                 CamelStream *ostream,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
 	g_set_error (
 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
 		_("You may not export keys with this cipher"));
 
-	return -1;
+	return FALSE;
+}
+
+static void
+cipher_context_sign_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_cipher_context_sign_sync (
+		CAMEL_CIPHER_CONTEXT (object),
+		async_context->userid, async_context->hash,
+		async_context->ipart, async_context->opart,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_sign (CamelCipherContext *context,
+                     const gchar *userid,
+                     CamelCipherHash hash,
+                     CamelMimePart *ipart,
+                     CamelMimePart *opart,
+                     gint io_priority,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->userid = g_strdup (userid);
+	async_context->hash = hash;
+	async_context->ipart = g_object_ref (ipart);
+	async_context->opart = g_object_ref (opart);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback, user_data, cipher_context_sign);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_sign_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+cipher_context_sign_finish (CamelCipherContext *context,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context), cipher_context_sign), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+cipher_context_verify_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->validity = camel_cipher_context_verify_sync (
+		CAMEL_CIPHER_CONTEXT (object), async_context->ipart,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_verify (CamelCipherContext *context,
+                       CamelMimePart *ipart,
+                       gint io_priority,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->ipart = g_object_ref (ipart);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback,
+		user_data, cipher_context_verify);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_verify_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelCipherValidity *
+cipher_context_verify_finish (CamelCipherContext *context,
+                              GAsyncResult *result,
+                              GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	CamelCipherValidity *validity;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context), cipher_context_verify), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	validity = async_context->validity;
+	async_context->validity = NULL;
+
+	return validity;
+}
+
+static void
+cipher_context_encrypt_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_cipher_context_encrypt_sync (
+		CAMEL_CIPHER_CONTEXT (object),
+		async_context->userid, async_context->strings,
+		async_context->ipart, async_context->opart,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_encrypt (CamelCipherContext *context,
+                        const gchar *userid,
+                        GPtrArray *recipients,
+                        CamelMimePart *ipart,
+                        CamelMimePart *opart,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	guint ii;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->userid = g_strdup (userid);
+	async_context->strings = g_ptr_array_new ();
+	async_context->ipart = g_object_ref (ipart);
+	async_context->opart = g_object_ref (opart);
+
+	for (ii = 0; ii < recipients->len; ii++)
+		g_ptr_array_add (
+			async_context->strings,
+			g_strdup (recipients->pdata[ii]));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback,
+		user_data, cipher_context_encrypt);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_encrypt_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+cipher_context_encrypt_finish (CamelCipherContext *context,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context), cipher_context_encrypt), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+cipher_context_decrypt_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->validity = camel_cipher_context_decrypt_sync (
+		CAMEL_CIPHER_CONTEXT (object), async_context->ipart,
+		async_context->opart, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_decrypt (CamelCipherContext *context,
+                        CamelMimePart *ipart,
+                        CamelMimePart *opart,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->ipart = g_object_ref (ipart);
+	async_context->opart = g_object_ref (opart);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback,
+		user_data, cipher_context_decrypt);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_decrypt_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelCipherValidity *
+cipher_context_decrypt_finish (CamelCipherContext *context,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	CamelCipherValidity *validity;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context), cipher_context_decrypt), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	validity = async_context->validity;
+	async_context->validity = NULL;
+
+	return validity;
+}
+
+static void
+cipher_context_import_keys_thread (GSimpleAsyncResult *simple,
+                                   GObject *object,
+                                   GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_cipher_context_import_keys_sync (
+		CAMEL_CIPHER_CONTEXT (object), async_context->stream,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_import_keys (CamelCipherContext *context,
+                            CamelStream *istream,
+                            gint io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->stream = g_object_ref (istream);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback,
+		user_data, cipher_context_import_keys);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_import_keys_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+cipher_context_import_keys_finish (CamelCipherContext *context,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context),
+		cipher_context_import_keys), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+cipher_context_export_keys_thread (GSimpleAsyncResult *simple,
+                                   GObject *object,
+                                   GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_cipher_context_export_keys_sync (
+		CAMEL_CIPHER_CONTEXT (object), async_context->strings,
+		async_context->stream, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+cipher_context_export_keys (CamelCipherContext *context,
+                            GPtrArray *keys,
+                            CamelStream *ostream,
+                            gint io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	guint ii;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->strings = g_ptr_array_new ();
+	async_context->stream = g_object_ref (ostream);
+
+	for (ii = 0; ii < keys->len; ii++)
+		g_ptr_array_add (
+			async_context->strings,
+			g_strdup (keys->pdata[ii]));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (context), callback,
+		user_data, cipher_context_export_keys);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cipher_context_export_keys_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+cipher_context_export_keys_finish (CamelCipherContext *context,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (context),
+		cipher_context_export_keys), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 static void
@@ -248,14 +727,28 @@ camel_cipher_context_class_init (CamelCipherContextClass *class)
 	object_class->dispose = cipher_context_dispose;
 	object_class->finalize = cipher_context_finalize;
 
-	class->hash_to_id = cipher_hash_to_id;
-	class->id_to_hash = cipher_id_to_hash;
-	class->sign_sync = cipher_sign_sync;
-	class->verify_sync = cipher_verify_sync;
-	class->encrypt_sync = cipher_encrypt_sync;
-	class->decrypt_sync = cipher_decrypt_sync;
-	class->import_keys_sync = cipher_import_keys_sync;
-	class->export_keys_sync = cipher_export_keys_sync;
+	class->hash_to_id = cipher_context_hash_to_id;
+	class->id_to_hash = cipher_context_id_to_hash;
+
+	class->sign_sync = cipher_context_sign_sync;
+	class->verify_sync = cipher_context_verify_sync;
+	class->encrypt_sync = cipher_context_encrypt_sync;
+	class->decrypt_sync = cipher_context_decrypt_sync;
+	class->import_keys_sync = cipher_context_import_keys_sync;
+	class->export_keys_sync = cipher_context_export_keys_sync;
+
+	class->sign = cipher_context_sign;
+	class->sign_finish = cipher_context_sign_finish;
+	class->verify = cipher_context_verify;
+	class->verify_finish = cipher_context_verify_finish;
+	class->encrypt = cipher_context_encrypt;
+	class->encrypt_finish = cipher_context_encrypt_finish;
+	class->decrypt = cipher_context_decrypt;
+	class->decrypt_finish = cipher_context_decrypt_finish;
+	class->import_keys = cipher_context_import_keys;
+	class->import_keys_finish = cipher_context_import_keys_finish;
+	class->export_keys = cipher_context_export_keys;
+	class->export_keys_finish = cipher_context_export_keys_finish;
 
 	g_object_class_install_property (
 		object_class,
@@ -277,81 +770,169 @@ camel_cipher_context_init (CamelCipherContext *context)
 }
 
 /**
- * camel_cipher_sign_sync:
- * @context: Cipher Context
- * @userid: private key to use to sign the stream
+ * camel_cipher_context_sign_sync:
+ * @context: a #CamelCipherContext
+ * @userid: a private key to use to sign the stream
  * @hash: preferred Message-Integrity-Check hash algorithm
- * @ipart: Input part.
- * @opart: output part.
+ * @ipart: input #CamelMimePart
+ * @opart: output #CamelMimePart
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Converts the (unsigned) part @ipart into a new self-contained mime
+ * Converts the (unsigned) part @ipart into a new self-contained MIME
  * part @opart.  This may be a multipart/signed part, or a simple part
  * for enveloped types.
  *
- * Returns: 0 for success or -1 for failure.
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-gint
-camel_cipher_sign_sync (CamelCipherContext *context,
-                        const gchar *userid,
-                        CamelCipherHash hash,
-                        CamelMimePart *ipart,
-                        CamelMimePart *opart,
-                        GCancellable *cancellable,
-                        GError **error)
+gboolean
+camel_cipher_context_sign_sync (CamelCipherContext *context,
+                                const gchar *userid,
+                                CamelCipherHash hash,
+                                CamelMimePart *ipart,
+                                CamelMimePart *opart,
+                                GCancellable *cancellable,
+                                GError **error)
 {
 	CamelCipherContextClass *class;
-	gint retval;
+	gboolean success;
 
-	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
-	g_return_val_if_fail (class->sign_sync != NULL, -1);
+	g_return_val_if_fail (class->sign_sync != NULL, FALSE);
 
 	CIPHER_LOCK (context);
 
-	retval = class->sign_sync (
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		CIPHER_UNLOCK (context);
+		return FALSE;
+	}
+
+	camel_operation_push_message (cancellable, _("Signing message"));
+
+	success = class->sign_sync (
 		context, userid, hash, ipart, opart, cancellable, error);
-	CAMEL_CHECK_GERROR (context, sign_sync, retval == 0, error);
+	CAMEL_CHECK_GERROR (context, sign_sync, success, error);
+
+	camel_operation_pop_message (cancellable);
 
 	CIPHER_UNLOCK (context);
 
-	return retval;
+	return success;
+}
+
+/**
+ * camel_cipher_context_sign:
+ * @context: a #CamelCipherContext
+ * @userid: a private key to use to sign the stream
+ * @hash: preferred Message-Integrity-Check hash algorithm
+ * @ipart: input #CamelMimePart
+ * @opart: output #CamelMimePart
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously converts the (unsigned) part @ipart into a new
+ * self-contained MIME part @opart.  This may be a multipart/signed part,
+ * or a simple part for enveloped types.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_cipher_context_sign_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_sign (CamelCipherContext *context,
+                           const gchar *userid,
+                           CamelCipherHash hash,
+                           CamelMimePart *ipart,
+                           CamelMimePart *opart,
+                           gint io_priority,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->sign != NULL);
+
+	class->sign (
+		context, userid, hash, ipart, opart, io_priority,
+		cancellable, callback, user_data);
 }
 
 /**
- * camel_cipher_verify_sync:
- * @context: Cipher Context
- * @ipart: part to verify
+ * camel_cipher_context_sign_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_cipher_context_sign().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_cipher_context_sign_finish (CamelCipherContext *context,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->sign_finish != NULL, FALSE);
+
+	return class->sign_finish (context, result, error);
+}
+
+/**
+ * camel_cipher_context_verify_sync:
+ * @context: a #CamelCipherContext
+ * @ipart: the #CamelMimePart to verify
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Verifies the signature. If @istream is a clearsigned stream,
- * you should pass %NULL as the sigstream parameter. Otherwise
- * @sigstream is assumed to be the signature stream and is used to
- * verify the integirity of the @istream.
+ * Verifies the signature.
  *
- * Returns: a CamelCipherValidity structure containing information
- * about the integrity of the input stream or %NULL on failure to
- * execute at all.
+ * Returns: a #CamelCipherValidity structure containing information
+ * about the integrity of the input stream, or %NULL on failure to
+ * execute at all
  **/
 CamelCipherValidity *
-camel_cipher_verify_sync (CamelCipherContext *context,
-                          CamelMimePart *ipart,
-                          GCancellable *cancellable,
-                          GError **error)
+camel_cipher_context_verify_sync (CamelCipherContext *context,
+                                  CamelMimePart *ipart,
+                                  GCancellable *cancellable,
+                                  GError **error)
 {
 	CamelCipherContextClass *class;
 	CamelCipherValidity *valid;
 
 	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 	g_return_val_if_fail (class->verify_sync != NULL, NULL);
 
 	CIPHER_LOCK (context);
 
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		CIPHER_UNLOCK (context);
+		return NULL;
+	}
+
 	valid = class->verify_sync (context, ipart, cancellable, error);
 	CAMEL_CHECK_GERROR (context, verify_sync, valid != NULL, error);
 
@@ -361,162 +942,542 @@ camel_cipher_verify_sync (CamelCipherContext *context,
 }
 
 /**
- * camel_cipher_encrypt_sync:
- * @context: Cipher Context
- * @userid: key id (or email address) to use when signing, or NULL to not sign.
- * @recipients: an array of recipient key ids and/or email addresses
- * @ipart: cleartext input stream
- * @opart: ciphertext output stream
+ * camel_cipher_context_verify:
+ * @context: a #CamelCipherContext
+ * @ipart: the #CamelMimePart to verify
+ * @io_priority: the I/O priority of the request
  * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously verifies the signature.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_cipher_context_verify_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_verify (CamelCipherContext *context,
+                             CamelMimePart *ipart,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+	g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->verify != NULL);
+
+	class->verify (
+		context, ipart, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_cipher_context_verify_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
  * @error: return location for a #GError, or %NULL
  *
- * Encrypts (and optionally signs) the cleartext input stream and
- * writes the resulting ciphertext to the output stream.
+ * Finishes the operation started with camel_cipher_context_verify().
  *
- * Returns: 0 for success or -1 for failure.
+ * Returns: a #CamelCipherValidity structure containing information
+ * about the integrity of the input stream, or %NULL on failure to
+ * execute at all
+ *
+ * Since: 2.34
  **/
-gint
-camel_cipher_encrypt_sync (CamelCipherContext *context,
-                           const gchar *userid,
-                           GPtrArray *recipients,
-                           CamelMimePart *ipart,
-                           CamelMimePart *opart,
-                           GCancellable *cancellable,
-                           GError **error)
+CamelCipherValidity *
+camel_cipher_context_verify_finish (CamelCipherContext *context,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (context), NULL);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->verify_finish != NULL, NULL);
+
+	return class->verify_finish (context, result, error);
+}
+
+/**
+ * camel_cipher_context_encrypt_sync:
+ * @context: a #CamelCipherContext
+ * @userid: key ID (or email address) to use when signing, or %NULL to not sign
+ * @recipients: an array of recipient key IDs and/or email addresses
+ * @ipart: clear-text #CamelMimePart
+ * @opart: cipher-text #CamelMimePart
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Encrypts (and optionally signs) the clear-text @ipart and writes the
+ * resulting cipher-text to @opart.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_cipher_context_encrypt_sync (CamelCipherContext *context,
+                                   const gchar *userid,
+                                   GPtrArray *recipients,
+                                   CamelMimePart *ipart,
+                                   CamelMimePart *opart,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
 	CamelCipherContextClass *class;
-	gint retval;
+	gboolean success;
 
-	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), FALSE);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), FALSE);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
-	g_return_val_if_fail (class->encrypt_sync != NULL, -1);
+	g_return_val_if_fail (class->encrypt_sync != NULL, FALSE);
 
 	CIPHER_LOCK (context);
 
-	retval = class->encrypt_sync (
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		CIPHER_UNLOCK (context);
+		return FALSE;
+	}
+
+	camel_operation_push_message (cancellable, _("Encrypting message"));
+
+	success = class->encrypt_sync (
 		context, userid, recipients,
 		ipart, opart, cancellable, error);
-	CAMEL_CHECK_GERROR (context, encrypt_sync, retval == 0, error);
+	CAMEL_CHECK_GERROR (context, encrypt_sync, success, error);
+
+	camel_operation_pop_message (cancellable);
 
 	CIPHER_UNLOCK (context);
 
-	return retval;
+	return success;
 }
 
 /**
- * camel_cipher_decrypt_sync:
- * @context:
- * @ipart:
- * @opart:
+ * camel_cipher_context_encrypt:
+ * @context: a #CamelCipherContext
+ * @userid: key id (or email address) to use when signing, or %NULL to not sign
+ * @recipients: an array of recipient key IDs and/or email addresses
+ * @ipart: clear-text #CamelMimePart
+ * @opart: cipher-text #CamelMimePart
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously encrypts (and optionally signs) the clear-text @ipart and
+ * writes the resulting cipher-text to @opart.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_cipher_context_encrypt_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_encrypt (CamelCipherContext *context,
+                              const gchar *userid,
+                              GPtrArray *recipients,
+                              CamelMimePart *ipart,
+                              CamelMimePart *opart,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+	g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
+	g_return_if_fail (CAMEL_IS_MIME_PART (opart));
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->encrypt != NULL);
+
+	class->encrypt (
+		context, userid, recipients, ipart, opart,
+		io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_cipher_context_encrypt_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_cipher_context_encrypt().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_cipher_context_encrypt_finish (CamelCipherContext *context,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->encrypt_finish != NULL, FALSE);
+
+	return class->encrypt_finish (context, result, error);
+}
+
+/**
+ * camel_cipher_context_decrypt_sync:
+ * @context: a #CamelCipherContext
+ * @ipart: cipher-text #CamelMimePart
+ * @opart: clear-text #CamelMimePart
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Decrypts @ipart into @opart.
  *
- * Returns: A validity/encryption status.
+ * Returns: a validity/encryption status, or %NULL on error
+ *
+ * Since: 2.34
  **/
 CamelCipherValidity *
-camel_cipher_decrypt_sync (CamelCipherContext *context,
-                           CamelMimePart *ipart,
-                           CamelMimePart *opart,
-                           GCancellable *cancellable,
-                           GError **error)
+camel_cipher_context_decrypt_sync (CamelCipherContext *context,
+                                   CamelMimePart *ipart,
+                                   CamelMimePart *opart,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
 	CamelCipherContextClass *class;
 	CamelCipherValidity *valid;
 
 	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (ipart), NULL);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (opart), NULL);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 	g_return_val_if_fail (class->decrypt_sync != NULL, NULL);
 
 	CIPHER_LOCK (context);
 
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		CIPHER_UNLOCK (context);
+		return NULL;
+	}
+
+	camel_operation_push_message (cancellable, _("Decrypting message"));
+
 	valid = class->decrypt_sync (
 		context, ipart, opart, cancellable, error);
 	CAMEL_CHECK_GERROR (context, decrypt_sync, valid != NULL, error);
 
+	camel_operation_pop_message (cancellable);
+
 	CIPHER_UNLOCK (context);
 
 	return valid;
 }
 
 /**
- * camel_cipher_import_keys_sync:
- * @context: Cipher Context
- * @istream: input stream (containing keys)
+ * camel_cipher_context_decrypt:
+ * @context: a #CamelCipherContext
+ * @ipart: cipher-text #CamelMimePart
+ * @opart: clear-text #CamelMimePart
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously decrypts @ipart into @opart.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_cipher_context_decrypt_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_decrypt (CamelCipherContext *context,
+                              CamelMimePart *ipart,
+                              CamelMimePart *opart,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+	g_return_if_fail (CAMEL_IS_MIME_PART (ipart));
+	g_return_if_fail (CAMEL_IS_MIME_PART (opart));
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->decrypt != NULL);
+
+	class->decrypt (
+		context, ipart, opart, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_cipher_context_decrypt_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_cipher_context_decrypt().
+ *
+ * Returns: a validity/encryption status, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelCipherValidity *
+camel_cipher_context_decrypt_finish (CamelCipherContext *context,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->decrypt_finish != NULL, NULL);
+
+	return class->decrypt_finish (context, result, error);
+}
+
+/**
+ * camel_cipher_context_import_keys_sync:
+ * @context: a #CamelCipherContext
+ * @istream: an input stream containing keys
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Imports a stream of keys/certificates contained within @istream
- * into the key/certificate database controlled by @ctx.
+ * into the key/certificate database controlled by @context.
  *
- * Returns: 0 on success or -1 on fail.
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-gint
-camel_cipher_import_keys_sync (CamelCipherContext *context,
-                               CamelStream *istream,
-                               GCancellable *cancellable,
-                               GError **error)
+gboolean
+camel_cipher_context_import_keys_sync (CamelCipherContext *context,
+                                       CamelStream *istream,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
 	CamelCipherContextClass *class;
-	gint retval;
+	gboolean success;
 
-	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
-	g_return_val_if_fail (CAMEL_IS_STREAM (istream), -1);
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (CAMEL_IS_STREAM (istream), FALSE);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
-	g_return_val_if_fail (class->import_keys_sync != NULL, -1);
+	g_return_val_if_fail (class->import_keys_sync != NULL, FALSE);
 
-	retval = class->import_keys_sync (
+	success = class->import_keys_sync (
 		context, istream, cancellable, error);
-	CAMEL_CHECK_GERROR (context, import_keys_sync, retval == 0, error);
+	CAMEL_CHECK_GERROR (context, import_keys_sync, success, error);
+
+	return success;
+}
+
+/**
+ * camel_cipher_context_import_keys:
+ * @context: a #CamelCipherContext
+ * @istream: an input stream containing keys
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously imports a stream of keys/certificates contained within
+ * @istream into the key/certificate database controlled by @context.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_cipher_context_import_keys_finish() to get the result
+ * of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_import_keys (CamelCipherContext *context,
+                                  CamelStream *istream,
+                                  gint io_priority,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+	g_return_if_fail (CAMEL_IS_STREAM (istream));
 
-	return retval;
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->import_keys != NULL);
+
+	class->import_keys (
+		context, istream, io_priority,
+		cancellable, callback, user_data);
 }
 
 /**
- * camel_cipher_export_keys_sync:
- * @context: Cipher Context
- * @keys: an array of key ids
- * @ostream: output stream
+ * camel_cipher_context_import_keys_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_cipher_context_import_keys().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_cipher_context_import_keys_finish (CamelCipherContext *context,
+                                         GAsyncResult *result,
+                                         GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->import_keys_finish != NULL, FALSE);
+
+	return class->import_keys_finish (context, result, error);
+}
+
+/**
+ * camel_cipher_context_export_keys_sync:
+ * @context: a #CamelCipherContext
+ * @keys: an array of key IDs
+ * @ostream: an output stream
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Exports the keys/certificates in @keys to the stream @ostream from
- * the key/certificate database controlled by @ctx.
+ * the key/certificate database controlled by @context.
  *
- * Returns: 0 on success or -1 on fail.
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-gint
-camel_cipher_export_keys_sync (CamelCipherContext *context,
-                               GPtrArray *keys,
-                               CamelStream *ostream,
-                               GCancellable *cancellable,
-                               GError **error)
+gboolean
+camel_cipher_context_export_keys_sync (CamelCipherContext *context,
+                                       GPtrArray *keys,
+                                       CamelStream *ostream,
+                                       GCancellable *cancellable,
+                                       GError **error)
 {
 	CamelCipherContextClass *class;
-	gint retval;
+	gboolean success;
 
-	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
-	g_return_val_if_fail (CAMEL_IS_STREAM (ostream), -1);
-	g_return_val_if_fail (keys != NULL, -1);
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (keys != NULL, FALSE);
+	g_return_val_if_fail (CAMEL_IS_STREAM (ostream), FALSE);
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
-	g_return_val_if_fail (class->export_keys_sync != NULL, -1);
+	g_return_val_if_fail (class->export_keys_sync != NULL, FALSE);
 
-	retval = class->export_keys_sync (
+	success = class->export_keys_sync (
 		context, keys, ostream, cancellable, error);
-	CAMEL_CHECK_GERROR (context, export_keys_sync, retval == 0, error);
+	CAMEL_CHECK_GERROR (context, export_keys_sync, success, error);
+
+	return success;
+}
+
+/**
+ * camel_cipher_context_export_keys:
+ * @context: a #CamelCipherContext
+ * @keys: an array of key IDs
+ * @ostream: an output stream
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously exports the keys/certificates in @keys to the stream
+ * @ostream from the key/certificate database controlled by @context.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_cipher_context_export_keys_finish() to get the result of the
+ * operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_cipher_context_export_keys (CamelCipherContext *context,
+                                  GPtrArray *keys,
+                                  CamelStream *ostream,
+                                  gint io_priority,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	CamelCipherContextClass *class;
+
+	g_return_if_fail (CAMEL_IS_CIPHER_CONTEXT (context));
+	g_return_if_fail (keys != NULL);
+	g_return_if_fail (CAMEL_IS_STREAM (ostream));
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_if_fail (class->export_keys != NULL);
+
+	class->export_keys (
+		context, keys, ostream, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_cipher_context_export_keys_finish:
+ * @context: a #CamelCipherContext
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_cipher_context_export_keys().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_cipher_context_export_keys_finish (CamelCipherContext *context,
+                                         GAsyncResult *result,
+                                         GError **error)
+{
+	CamelCipherContextClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->export_keys_finish != NULL, FALSE);
 
-	return retval;
+	return class->export_keys_finish (context, result, error);
 }
 
 /* a couple of util functions */
 CamelCipherHash
-camel_cipher_id_to_hash (CamelCipherContext *context,
-                         const gchar *id)
+camel_cipher_context_id_to_hash (CamelCipherContext *context,
+                                 const gchar *id)
 {
 	CamelCipherContextClass *class;
 
@@ -532,8 +1493,8 @@ camel_cipher_id_to_hash (CamelCipherContext *context,
 }
 
 const gchar *
-camel_cipher_hash_to_id (CamelCipherContext *context,
-                         CamelCipherHash hash)
+camel_cipher_context_hash_to_id (CamelCipherContext *context,
+                                 CamelCipherHash hash)
 {
 	CamelCipherContextClass *class;
 
diff --git a/camel/camel-cipher-context.h b/camel/camel-cipher-context.h
index e3d231a..71da9d6 100644
--- a/camel/camel-cipher-context.h
+++ b/camel/camel-cipher-context.h
@@ -134,12 +134,14 @@ struct _CamelCipherContextClass {
 	const gchar *encrypt_protocol;
 	const gchar *key_protocol;
 
+	/* Non-Blocking Methods */
 	CamelCipherHash	(*id_to_hash)		(CamelCipherContext *context,
 						 const gchar *id);
 	const gchar *	(*hash_to_id)		(CamelCipherContext *context,
 						 CamelCipherHash hash);
 
-	gint		(*sign_sync)		(CamelCipherContext *context,
+	/* Synchronous I/O Methods */
+	gboolean	(*sign_sync)		(CamelCipherContext *context,
 						 const gchar *userid,
 						 CamelCipherHash hash,
 						 CamelMimePart *ipart,
@@ -151,7 +153,7 @@ struct _CamelCipherContextClass {
 						 CamelMimePart *ipart,
 						 GCancellable *cancellable,
 						 GError **error);
-	gint		(*encrypt_sync)		(CamelCipherContext *context,
+	gboolean	(*encrypt_sync)		(CamelCipherContext *context,
 						 const gchar *userid,
 						 GPtrArray *recipients,
 						 CamelMimePart *ipart,
@@ -164,26 +166,93 @@ struct _CamelCipherContextClass {
 						 CamelMimePart *opart,
 						 GCancellable *cancellable,
 						 GError **error);
-	gint		(*import_keys_sync)	(CamelCipherContext *context,
+	gboolean	(*import_keys_sync)	(CamelCipherContext *context,
 						 CamelStream *istream,
 						 GCancellable *cancellable,
 						 GError **error);
-	gint		(*export_keys_sync)	(CamelCipherContext *context,
+	gboolean	(*export_keys_sync)	(CamelCipherContext *context,
 						 GPtrArray *keys,
 						 CamelStream *ostream,
 						 GCancellable *cancellable,
 						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*sign)			(CamelCipherContext *context,
+						 const gchar *userid,
+						 CamelCipherHash hash,
+						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*sign_finish)		(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*verify)		(CamelCipherContext *context,
+						 CamelMimePart *ipart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelCipherValidity *
+			(*verify_finish)	(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*encrypt)		(CamelCipherContext *context,
+						 const gchar *user_id,
+						 GPtrArray *recipients,
+						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*encrypt_finish)	(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*decrypt)		(CamelCipherContext *context,
+						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelCipherValidity *
+			(*decrypt_finish)	(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*import_keys)		(CamelCipherContext *context,
+						 CamelStream *istream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*import_keys_finish)	(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*export_keys)		(CamelCipherContext *context,
+						 GPtrArray *keys,
+						 CamelStream *ostream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*export_keys_finish)	(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
 };
 
 GType		camel_cipher_context_get_type	(void);
 CamelCipherContext *
 		camel_cipher_context_new	(CamelSession *session);
-CamelSession *	camel_cipher_context_get_session (CamelCipherContext *context);
+CamelSession *	camel_cipher_context_get_session
+						(CamelCipherContext *context);
 
 /* cipher context util routines */
-CamelCipherHash	camel_cipher_id_to_hash		(CamelCipherContext *context,
+CamelCipherHash	camel_cipher_context_id_to_hash	(CamelCipherContext *context,
 						 const gchar *id);
-const gchar *	camel_cipher_hash_to_id		(CamelCipherContext *context,
+const gchar *	camel_cipher_context_hash_to_id	(CamelCipherContext *context,
 						 CamelCipherHash hash);
 
 /* FIXME:
@@ -192,41 +261,118 @@ const gchar *	camel_cipher_hash_to_id		(CamelCipherContext *context,
    to the cipher, etc etc. */
 
 /* cipher routines */
-gint		camel_cipher_sign_sync		(CamelCipherContext *context,
+gboolean	camel_cipher_context_sign_sync	(CamelCipherContext *context,
 						 const gchar *userid,
 						 CamelCipherHash hash,
 						 CamelMimePart *ipart,
 						 CamelMimePart *opart,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_cipher_context_sign	(CamelCipherContext *context,
+						 const gchar *userid,
+						 CamelCipherHash hash,
+						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_cipher_context_sign_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+CamelCipherValidity *
+		camel_cipher_context_verify_sync
+						(CamelCipherContext *context,
+						 CamelMimePart *ipart,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_cipher_context_verify	(CamelCipherContext *context,
+						 CamelMimePart *ipart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
 CamelCipherValidity *
-		camel_cipher_verify_sync	(CamelCipherContext *context,
+		camel_cipher_context_verify_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	camel_cipher_context_encrypt_sync
+						(CamelCipherContext *context,
+						 const gchar *userid,
+						 GPtrArray *recipients,
 						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
 						 GCancellable *cancellable,
 						 GError **error);
-gint		camel_cipher_encrypt_sync	(CamelCipherContext *context,
+void		camel_cipher_context_encrypt	(CamelCipherContext *context,
 						 const gchar *userid,
 						 GPtrArray *recipients,
 						 CamelMimePart *ipart,
 						 CamelMimePart *opart,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_cipher_context_encrypt_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
 						 GError **error);
 CamelCipherValidity *
-		camel_cipher_decrypt_sync	(CamelCipherContext *context,
+		camel_cipher_context_decrypt_sync
+						(CamelCipherContext *context,
 						 CamelMimePart *ipart,
 						 CamelMimePart *opart,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_cipher_context_decrypt	(CamelCipherContext *context,
+						 CamelMimePart *ipart,
+						 CamelMimePart *opart,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelCipherValidity *
+		camel_cipher_context_decrypt_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
 
 /* key/certificate routines */
-gint		camel_cipher_import_keys_sync	(CamelCipherContext *context,
+gboolean	camel_cipher_context_import_keys_sync
+						(CamelCipherContext *context,
 						 CamelStream *istream,
 						 GCancellable *cancellable,
 						 GError **error);
-gint		camel_cipher_export_keys_sync	(CamelCipherContext *context,
+void		camel_cipher_context_import_keys
+						(CamelCipherContext *context,
+						 CamelStream *istream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_cipher_context_import_keys_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	camel_cipher_context_export_keys_sync
+						(CamelCipherContext *context,
+						 GPtrArray *keys,
+						 CamelStream *ostream,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_cipher_context_export_keys
+						(CamelCipherContext *context,
 						 GPtrArray *keys,
 						 CamelStream *ostream,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_cipher_context_export_keys_finish
+						(CamelCipherContext *context,
+						 GAsyncResult *result,
 						 GError **error);
 
 /* CamelCipherValidity utility functions */
diff --git a/camel/camel-data-wrapper.c b/camel/camel-data-wrapper.c
index 4969f78..a9f9a0b 100644
--- a/camel/camel-data-wrapper.c
+++ b/camel/camel-data-wrapper.c
@@ -40,10 +40,29 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_DATA_WRAPPER, CamelDataWrapperPrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelDataWrapperPrivate {
 	GStaticMutex stream_lock;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	CamelStream *stream;
+
+	/* results */
+	gssize bytes_written;
+};
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->stream != NULL)
+		g_object_unref (async_context->stream);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
 G_DEFINE_TYPE (CamelDataWrapper, camel_data_wrapper, CAMEL_TYPE_OBJECT)
 
 static void
@@ -130,8 +149,17 @@ data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
 	}
 
 	camel_data_wrapper_lock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_data_wrapper_unlock (
+			data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
+		return -1;
+	}
+
 	if (camel_stream_reset (data_wrapper->stream, error) == -1) {
-		camel_data_wrapper_unlock (data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
+		camel_data_wrapper_unlock (
+			data_wrapper, CAMEL_DATA_WRAPPER_STREAM_LOCK);
 		return -1;
 	}
 
@@ -191,7 +219,7 @@ data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
 	return ret;
 }
 
-static gint
+static gboolean
 data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
                                          CamelStream *stream,
                                          GCancellable *cancellable,
@@ -202,7 +230,217 @@ data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
 
 	data_wrapper->stream = g_object_ref (stream);
 
-	return 0;
+	return TRUE;
+}
+
+static void
+data_wrapper_write_to_stream_thread (GSimpleAsyncResult *simple,
+                                     GObject *object,
+                                     GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->bytes_written =
+		camel_data_wrapper_write_to_stream_sync (
+			CAMEL_DATA_WRAPPER (object),
+			async_context->stream,
+			cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
+                              CamelStream *stream,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->stream = g_object_ref (stream);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (data_wrapper), callback,
+		user_data, data_wrapper_write_to_stream);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, data_wrapper_write_to_stream_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gssize
+data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (data_wrapper),
+		data_wrapper_write_to_stream), -1);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return -1;
+
+	return async_context->bytes_written;
+}
+
+static void
+data_wrapper_decode_to_stream_thread (GSimpleAsyncResult *simple,
+                                      GObject *object,
+                                      GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->bytes_written =
+		camel_data_wrapper_decode_to_stream_sync (
+			CAMEL_DATA_WRAPPER (object),
+			async_context->stream,
+			cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
+                               CamelStream *stream,
+                               gint io_priority,
+                               GCancellable *cancellable,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->stream = g_object_ref (stream);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (data_wrapper), callback,
+		user_data, data_wrapper_decode_to_stream);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, data_wrapper_decode_to_stream_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gssize
+data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper,
+                                      GAsyncResult *result,
+                                      GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (data_wrapper),
+		data_wrapper_decode_to_stream), -1);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return -1;
+
+	return async_context->bytes_written;
+}
+
+static void
+data_wrapper_construct_from_stream_thread (GSimpleAsyncResult *simple,
+                                           GObject *object,
+                                           GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_data_wrapper_construct_from_stream_sync (
+		CAMEL_DATA_WRAPPER (object), async_context->stream,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
+                                    CamelStream *stream,
+                                    gint io_priority,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->stream = g_object_ref (stream);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (data_wrapper), callback, user_data,
+		data_wrapper_construct_from_stream);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, data_wrapper_construct_from_stream_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper,
+                                           GAsyncResult *result,
+                                           GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (data_wrapper),
+		data_wrapper_construct_from_stream), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 static void
@@ -221,9 +459,17 @@ camel_data_wrapper_class_init (CamelDataWrapperClass *class)
 	class->get_mime_type_field = data_wrapper_get_mime_type_field;
 	class->set_mime_type_field = data_wrapper_set_mime_type_field;
 	class->is_offline = data_wrapper_is_offline;
+
 	class->write_to_stream_sync = data_wrapper_write_to_stream_sync;
 	class->decode_to_stream_sync = data_wrapper_decode_to_stream_sync;
 	class->construct_from_stream_sync = data_wrapper_construct_from_stream_sync;
+
+	class->write_to_stream = data_wrapper_write_to_stream;
+	class->write_to_stream_finish = data_wrapper_write_to_stream_finish;
+	class->decode_to_stream = data_wrapper_decode_to_stream;
+	class->decode_to_stream_finish = data_wrapper_decode_to_stream_finish;
+	class->construct_from_stream = data_wrapper_construct_from_stream;
+	class->construct_from_stream_finish = data_wrapper_construct_from_stream_finish;
 }
 
 static void
@@ -254,7 +500,7 @@ camel_data_wrapper_new (void)
 
 /**
  * camel_data_wrapper_set_mime_type:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  * @mime_type: a MIME type
  *
  * This sets the data wrapper's MIME type.
@@ -282,7 +528,7 @@ camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper,
 
 /**
  * camel_data_wrapper_get_mime_type:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  *
  * Returns: the MIME type which must be freed by the caller
  **/
@@ -301,7 +547,7 @@ camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper)
 
 /**
  * camel_data_wrapper_get_mime_type_field:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  *
  * Returns: the parsed form of the data wrapper's MIME type
  **/
@@ -320,7 +566,7 @@ camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper)
 
 /**
  * camel_data_wrapper_set_mime_type_field:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  * @mime_type: a #CamelContentType
  *
  * This sets the data wrapper's MIME type. It suffers from the same
@@ -343,7 +589,7 @@ camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper,
 
 /**
  * camel_data_wrapper_is_offline:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  *
  * Returns: whether @data_wrapper is "offline" (data stored
  * remotely) or not. Some optional code paths may choose to not
@@ -363,18 +609,77 @@ camel_data_wrapper_is_offline (CamelDataWrapper *data_wrapper)
 }
 
 /**
+ * camel_data_wrapper_lock:
+ * @data_wrapper: a #CamelDataWrapper
+ * @lock: lock type to lock
+ *
+ * Locks #data_wrapper's #lock. Unlock it with camel_data_wrapper_unlock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_data_wrapper_lock (CamelDataWrapper *data_wrapper,
+                         CamelDataWrapperLock lock)
+{
+	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+
+	switch (lock) {
+	case CAMEL_DATA_WRAPPER_STREAM_LOCK:
+		g_static_mutex_lock (&data_wrapper->priv->stream_lock);
+		break;
+	default:
+		g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_data_wrapper_unlock:
+ * @data_wrapper: a #CamelDataWrapper
+ * @lock: lock type to unlock
+ *
+ * Unlocks #data_wrapper's #lock, previously locked with
+ * camel_data_wrapper_lock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper,
+                           CamelDataWrapperLock lock)
+{
+	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+
+	switch (lock) {
+	case CAMEL_DATA_WRAPPER_STREAM_LOCK:
+		g_static_mutex_unlock (&data_wrapper->priv->stream_lock);
+		break;
+	default:
+		g_return_if_reached ();
+	}
+}
+
+/**
  * camel_data_wrapper_write_to_stream_sync:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  * @stream: a #CamelStream for output
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Writes the content of @data_wrapper to @stream in a machine-independent
- * format appropriate for the data. It should be possible to construct an
+ * format appropriate for the data.  It should be possible to construct an
  * equivalent data wrapper object later by passing this stream to
- * #camel_data_wrapper_construct_from_stream.
+ * camel_data_wrapper_construct_from_stream_sync().
+ *
+ * <note>
+ *   <para>
+ *     This function may block even if the given output stream does not.
+ *     For example, the content may have to be fetched across a network
+ *     before it can be written to @stream.
+ *   </para>
+ * </note>
  *
- * Returns: the number of bytes written, or %-1 on fail
+ * Returns: the number of bytes written, or %-1 on error
+ *
+ * Since: 2.34
  **/
 gssize
 camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
@@ -400,15 +705,94 @@ camel_data_wrapper_write_to_stream_sync (CamelDataWrapper *data_wrapper,
 }
 
 /**
+ * camel_data_wrapper_write_to_stream:
+ * @data_wrapper: a #CamelDataWrapper
+ * @stream: a #CamelStream for writed data to be written to
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously writes the content of @data_wrapper to @stream in a
+ * machine-independent format appropriate for the data.  It should be
+ * possible to construct an equivalent data wrapper object later by
+ * passing this stream to camel_data_wrapper_construct_from_stream().
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_data_wrapper_write_to_stream_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper,
+                                    CamelStream *stream,
+                                    gint io_priority,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+	CamelDataWrapperClass *class;
+
+	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_if_fail (class->write_to_stream != NULL);
+
+	class->write_to_stream (
+		data_wrapper, stream, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_data_wrapper_write_to_stream_finish:
+ * @data_wrapper: a #CamelDataWrapper
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_data_wrapper_write_to_stream().
+ *
+ * Returns: the number of bytes written, or %-1 or error
+ *
+ * Since: 2.34
+ **/
+gssize
+camel_data_wrapper_write_to_stream_finish (CamelDataWrapper *data_wrapper,
+                                           GAsyncResult *result,
+                                           GError **error)
+{
+	CamelDataWrapperClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1);
+
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_val_if_fail (class->write_to_stream_finish != NULL, -1);
+
+	return class->write_to_stream_finish (data_wrapper, result, error);
+}
+
+/**
  * camel_data_wrapper_decode_to_stream_sync:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  * @stream: a #CamelStream for decoded data to be written to
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Writes the decoded data content to @stream.
  *
- * Returns: the number of bytes written, or %-1 on fail
+ * <note>
+ *   <para>
+ *     This function may block even if the given output stream does not.
+ *     For example, the content may have to be fetched across a network
+ *     before it can be written to @stream.
+ *   </para>
+ * </note>
+ *
+ * Returns: the number of bytes written, or %-1 on error
+ *
+ * Since: 2.34
  **/
 gssize
 camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
@@ -434,24 +818,92 @@ camel_data_wrapper_decode_to_stream_sync (CamelDataWrapper *data_wrapper,
 }
 
 /**
+ * camel_data_wrapper_decode_to_stream:
+ * @data_wrapper: a #CamelDataWrapper
+ * @stream: a #CamelStream for decoded data to be written to
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously writes the decoded data content to @stream.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_data_wrapper_decode_to_stream_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_data_wrapper_decode_to_stream (CamelDataWrapper *data_wrapper,
+                                     CamelStream *stream,
+                                     gint io_priority,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+	CamelDataWrapperClass *class;
+
+	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_if_fail (class->decode_to_stream != NULL);
+
+	class->decode_to_stream (
+		data_wrapper, stream, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_data_wrapper_decode_to_stream_finish:
+ * @data_wrapper: a #CamelDataWrapper
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_data_wrapper_decode_to_stream().
+ *
+ * Returns: the number of bytes written, or %-1 on error
+ *
+ * Since: 2.34
+ **/
+gssize
+camel_data_wrapper_decode_to_stream_finish (CamelDataWrapper *data_wrapper,
+                                            GAsyncResult *result,
+                                            GError **error)
+{
+	CamelDataWrapperClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1);
+
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_val_if_fail (class->decode_to_stream_finish != NULL, -1);
+
+	return class->decode_to_stream_finish (data_wrapper, result, error);
+}
+
+/**
  * camel_data_wrapper_construct_from_stream_sync:
- * @data_wrapper: a #CamelDataWrapper object
+ * @data_wrapper: a #CamelDataWrapper
  * @stream: an input #CamelStream
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Constructs the content of @data_wrapper from the supplied @stream.
+ * Constructs the content of @data_wrapper from the given @stream.
+ *
+ * Returns: %TRUE on success, %FALSE on error
  *
- * Returns: %0 on success or %-1 on fail
+ * Since: 2.34
  **/
-gint
+gboolean
 camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
                                                CamelStream *stream,
                                                GCancellable *cancellable,
                                                GError **error)
 {
 	CamelDataWrapperClass *class;
-	gint retval;
+	gboolean success;
 
 	g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), -1);
 	g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
@@ -459,59 +911,78 @@ camel_data_wrapper_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
 	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
 	g_return_val_if_fail (class->construct_from_stream_sync != NULL, -1);
 
-	retval = class->construct_from_stream_sync (
+	success = class->construct_from_stream_sync (
 		data_wrapper, stream, cancellable, error);
 	CAMEL_CHECK_GERROR (
-		data_wrapper, construct_from_stream_sync, retval == 0, error);
+		data_wrapper, construct_from_stream_sync, success, error);
 
-	return retval;
+	return success;
 }
 
 /**
- * camel_data_wrapper_lock:
+ * camel_data_wrapper_construct_from_stream:
  * @data_wrapper: a #CamelDataWrapper
- * @lock: lock type to lock
+ * @stream: an input #CamelStream
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
  *
- * Locks #data_wrapper's #lock. Unlock it with camel_data_wrapper_unlock().
+ * Asynchronously constructs the content of @data_wrapper from the given
+ * @stream.
  *
- * Since: 2.32
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_data_wrapper_construct_from_stream_finish() to get the result
+ * of the operation.
+ *
+ * Since: 2.34
  **/
 void
-camel_data_wrapper_lock (CamelDataWrapper *data_wrapper,
-                         CamelDataWrapperLock lock)
+camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper,
+                                          CamelStream *stream,
+                                          gint io_priority,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data)
 {
+	CamelDataWrapperClass *class;
+
 	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
 
-	switch (lock) {
-	case CAMEL_DATA_WRAPPER_STREAM_LOCK:
-		g_static_mutex_lock (&data_wrapper->priv->stream_lock);
-		break;
-	default:
-		g_return_if_reached ();
-	}
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_if_fail (class->construct_from_stream != NULL);
+
+	class->construct_from_stream (
+		data_wrapper, stream, io_priority,
+		cancellable, callback, user_data);
 }
 
 /**
- * camel_data_wrapper_unlock:
+ * camel_data_wrapper_construct_from_stream_finish:
  * @data_wrapper: a #CamelDataWrapper
- * @lock: lock type to unlock
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
  *
- * Unlocks #data_wrapper's #lock, previously locked with
- * camel_data_wrapper_lock().
+ * Finishes the operation started with
+ * camel_data_wrapper_construct_from_stream().
  *
- * Since: 2.32
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-void
-camel_data_wrapper_unlock (CamelDataWrapper *data_wrapper,
-                           CamelDataWrapperLock lock)
+gboolean
+camel_data_wrapper_construct_from_stream_finish (CamelDataWrapper *data_wrapper,
+                                                 GAsyncResult *result,
+                                                 GError **error)
 {
-	g_return_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper));
+	CamelDataWrapperClass *class;
 
-	switch (lock) {
-	case CAMEL_DATA_WRAPPER_STREAM_LOCK:
-		g_static_mutex_unlock (&data_wrapper->priv->stream_lock);
-		break;
-	default:
-		g_return_if_reached ();
-	}
+	g_return_val_if_fail (CAMEL_IS_DATA_WRAPPER (data_wrapper), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_DATA_WRAPPER_GET_CLASS (data_wrapper);
+	g_return_val_if_fail (class->construct_from_stream_finish != NULL, FALSE);
+
+	return class->construct_from_stream_finish (data_wrapper, result, error);
 }
diff --git a/camel/camel-data-wrapper.h b/camel/camel-data-wrapper.h
index adde135..d363456 100644
--- a/camel/camel-data-wrapper.h
+++ b/camel/camel-data-wrapper.h
@@ -83,6 +83,7 @@ struct _CamelDataWrapper {
 struct _CamelDataWrapperClass {
 	CamelObjectClass parent_class;
 
+	/* Non-Blocking Methods */
 	void		(*set_mime_type)	(CamelDataWrapper *data_wrapper,
 						 const gchar *mime_type);
 	gchar *		(*get_mime_type)	(CamelDataWrapper *data_wrapper);
@@ -92,6 +93,7 @@ struct _CamelDataWrapperClass {
 						 CamelContentType *mime_type_field);
 	gboolean	(*is_offline)		(CamelDataWrapper *data_wrapper);
 
+	/* Synchronous I/O Methods */
 	gssize		(*write_to_stream_sync)	(CamelDataWrapper *data_wrapper,
 						 CamelStream *stream,
 						 GCancellable *cancellable,
@@ -100,11 +102,44 @@ struct _CamelDataWrapperClass {
 						 CamelStream *stream,
 						 GCancellable *cancellable,
 						 GError **error);
-	gint		(*construct_from_stream_sync)
+	gboolean	(*construct_from_stream_sync)
 						(CamelDataWrapper *data_wrapper,
 						 CamelStream *stream,
 						 GCancellable *cancellable,
 						 GError **error);
+
+	/* Asyncrhonous I/O Methods (all have defaults) */
+	void		(*write_to_stream)	(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gssize		(*write_to_stream_finish)
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*decode_to_stream)	(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gssize		(*decode_to_stream_finish)
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*construct_from_stream)
+						(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*construct_from_stream_finish)
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
+						 GError **error);
 };
 
 GType		camel_data_wrapper_get_type	(void);
@@ -120,25 +155,59 @@ void		camel_data_wrapper_set_mime_type_field
 						(CamelDataWrapper *data_wrapper,
 						 CamelContentType *mime_type);
 gboolean	camel_data_wrapper_is_offline	(CamelDataWrapper *data_wrapper);
+void		camel_data_wrapper_lock		(CamelDataWrapper *data_wrapper,
+						 CamelDataWrapperLock lock);
+void		camel_data_wrapper_unlock	(CamelDataWrapper *data_wrapper,
+						 CamelDataWrapperLock lock);
+
 gssize		camel_data_wrapper_write_to_stream_sync
 						(CamelDataWrapper *data_wrapper,
 						 CamelStream *stream,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_data_wrapper_write_to_stream
+						(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gssize		camel_data_wrapper_write_to_stream_finish
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
+						 GError **error);
 gssize		camel_data_wrapper_decode_to_stream_sync
 						(CamelDataWrapper *data_wrapper,
 						 CamelStream *stream,
 						 GCancellable *cancellable,
 						 GError **error);
-gint		camel_data_wrapper_construct_from_stream_sync
+void		camel_data_wrapper_decode_to_stream
 						(CamelDataWrapper *data_wrapper,
 						 CamelStream *stream,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gssize		camel_data_wrapper_decode_to_stream_finish
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	camel_data_wrapper_construct_from_stream_sync
+						(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_data_wrapper_construct_from_stream
+						(CamelDataWrapper *data_wrapper,
+						 CamelStream *stream,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_data_wrapper_construct_from_stream_finish
+						(CamelDataWrapper *data_wrapper,
+						 GAsyncResult *result,
 						 GError **error);
-void		camel_data_wrapper_lock		(CamelDataWrapper *data_wrapper,
-						 CamelDataWrapperLock lock);
-void		camel_data_wrapper_unlock	(CamelDataWrapper *data_wrapper,
-						 CamelDataWrapperLock lock);
 
 G_END_DECLS
 
diff --git a/camel/camel-db.h b/camel/camel-db.h
index a2d7148..bf047ff 100644
--- a/camel/camel-db.h
+++ b/camel/camel-db.h
@@ -47,7 +47,7 @@ typedef struct _CamelDBPrivate CamelDBPrivate;
  *
  * Since: 2.24
  **/
-typedef gint (*CamelDBCollate)(gpointer ,int,gconstpointer ,int,gconstpointer );
+typedef gint (*CamelDBCollate)(gpointer, gint, gconstpointer, gint, gconstpointer );
 
 /**
  * CamelDB:
diff --git a/camel/camel-disco-diary.c b/camel/camel-disco-diary.c
index 530d386..9c48a6a 100644
--- a/camel/camel-disco-diary.c
+++ b/camel/camel-disco-diary.c
@@ -300,7 +300,8 @@ camel_disco_diary_replay (CamelDiscoDiary *diary,
 	g_return_if_fail (size != 0);
 	rewind (diary->file);
 
-	camel_operation_start (cancellable, _("Resynchronizing with server"));
+	camel_operation_push_message (
+		cancellable, _("Resynchronizing with server"));
 
 	while (local_error == NULL) {
 		camel_operation_progress (
@@ -390,8 +391,8 @@ camel_disco_diary_replay (CamelDiscoDiary *diary,
 			}
 
 			camel_folder_transfer_messages_to_sync (
-				source, uids, destination, &ret_uids,
-				delete_originals, cancellable, &local_error);
+				source, uids, destination, delete_originals,
+				&ret_uids, cancellable, &local_error);
 
 			if (ret_uids) {
 				for (i = 0; i < uids->len; i++) {
@@ -410,7 +411,7 @@ camel_disco_diary_replay (CamelDiscoDiary *diary,
 	}
 
  lose:
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	/* Close folders */
 	g_hash_table_foreach (
diff --git a/camel/camel-disco-folder.c b/camel/camel-disco-folder.c
index 6fd9009..65e1031 100644
--- a/camel/camel-disco-folder.c
+++ b/camel/camel-disco-folder.c
@@ -62,7 +62,7 @@ cdf_sync_offline (CamelSession *session, CamelSessionThreadMsg *mm)
 	struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
 	gint i;
 
-	camel_operation_start (
+	camel_operation_push_message (
 		mm->cancellable,
 		_("Downloading new messages for offline mode"));
 
@@ -81,7 +81,7 @@ cdf_sync_offline (CamelSession *session, CamelSessionThreadMsg *mm)
 						       NULL, &mm->error);
 	}
 
-	camel_operation_end (mm->cancellable);
+	camel_operation_pop_message (mm->cancellable);
 }
 
 static void
@@ -203,7 +203,7 @@ disco_expunge_uids (CamelFolder *folder,
 static gboolean
 disco_append_message_sync (CamelFolder *folder,
                            CamelMimeMessage *message,
-                           const CamelMessageInfo *info,
+                           CamelMessageInfo *info,
                            gchar **appended_uid,
                            GCancellable *cancellable,
                            GError **error)
@@ -336,8 +336,8 @@ static gboolean
 disco_transfer_messages_to_sync (CamelFolder *source,
                                  GPtrArray *uids,
                                  CamelFolder *dest,
-                                 GPtrArray **transferred_uids,
                                  gboolean delete_originals,
+                                 GPtrArray **transferred_uids,
                                  GCancellable *cancellable,
                                  GError **error)
 {
@@ -385,7 +385,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
 	gint i;
 	gboolean success = TRUE;
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable, _("Preparing folder '%s' for offline"),
 		camel_folder_get_full_name (folder));
 
@@ -395,7 +395,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
 		uids = camel_folder_get_uids (folder);
 
 	if (!uids) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return FALSE;
 	}
 
@@ -411,7 +411,7 @@ disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
 	else
 		camel_folder_free_uids (folder, uids);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return success;
 }
diff --git a/camel/camel-filter-driver.c b/camel/camel-filter-driver.c
index 9a4a77c..2c876cd 100644
--- a/camel/camel-filter-driver.c
+++ b/camel/camel-filter-driver.c
@@ -506,8 +506,8 @@ do_copy (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFilterDri
 				g_ptr_array_add (uids, (gchar *) p->uid);
 				/* FIXME Pass a GCancellable */
 				camel_folder_transfer_messages_to_sync (
-					p->source, uids, outbox, NULL,
-					FALSE, NULL, &p->error);
+					p->source, uids, outbox, FALSE,
+					NULL, NULL, &p->error);
 				g_ptr_array_free (uids, TRUE);
 			} else {
 				if (p->message == NULL)
@@ -567,8 +567,8 @@ do_move (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFilterDri
 				g_ptr_array_add (uids, (gchar *) p->uid);
 				/* FIXME Pass a GCancellable */
 				camel_folder_transfer_messages_to_sync (
-					p->source, uids, outbox, NULL,
-					last, NULL, &p->error);
+					p->source, uids, outbox, last,
+					NULL, NULL, &p->error);
 				g_ptr_array_free (uids, TRUE);
 			} else {
 				if (p->message == NULL)
@@ -877,8 +877,8 @@ pipe_to_system (struct _ESExp *f, gint argc, struct _ESExpResult **argv, CamelFi
 	g_object_unref (mem);
 
 	message = camel_mime_message_new ();
-	if (camel_mime_part_construct_from_parser_sync (
-		(CamelMimePart *) message, parser, NULL, NULL) == -1) {
+	if (!camel_mime_part_construct_from_parser_sync (
+		(CamelMimePart *) message, parser, NULL, NULL)) {
 		gint err = camel_mime_parser_errno (parser);
 		g_set_error (
 			&p->error, G_IO_ERROR,
@@ -1309,8 +1309,8 @@ camel_filter_driver_filter_mbox (CamelFilterDriver *driver,
 		message = camel_mime_message_new ();
 		mime_part = CAMEL_MIME_PART (message);
 
-		if (camel_mime_part_construct_from_parser_sync (
-			mime_part, mp, cancellable, error) == -1) {
+		if (!camel_mime_part_construct_from_parser_sync (
+			mime_part, mp, cancellable, error)) {
 			report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed on message %d"), i);
 			g_object_unref (message);
 			goto fail;
@@ -1672,7 +1672,7 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver,
 			g_ptr_array_add (uids, (gchar *) p->uid);
 			camel_folder_transfer_messages_to_sync (
 				p->source, uids, p->defaultfolder,
-				NULL, FALSE, cancellable, &p->error);
+				FALSE, NULL, cancellable, &p->error);
 			g_ptr_array_free (uids, TRUE);
 		} else {
 			if (p->message == NULL) {
diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c
index 399980e..05c1351 100644
--- a/camel/camel-folder-search.c
+++ b/camel/camel-folder-search.c
@@ -1432,7 +1432,8 @@ match_words_1message (CamelDataWrapper *object, struct _camel_search_words *word
 		byte_array = g_byte_array_new ();
 		stream = camel_stream_mem_new_with_byte_array (byte_array);
 
-		/* FIXME: The match should be part of a stream op */
+		/* FIXME The match should be part of a stream op */
+		/* FIXME Pass a GCancellable and GError here. */
 		camel_data_wrapper_decode_to_stream_sync (
 			containee, stream, NULL, NULL);
 		camel_stream_write (stream, "", 1, NULL, NULL);
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 489d1c0..1382fd5 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -4043,6 +4043,7 @@ summary_build_content_info_message (CamelFolderSummary *s, CamelMessageInfo *msg
 			CAMEL_STREAM_FILTER (p->filter_stream),
 			p->filter_index);
 
+		/* FIXME Pass a GCancellable and GError here. */
 		camel_data_wrapper_decode_to_stream_sync (
 			containee, p->filter_stream, NULL, NULL);
 		camel_stream_flush (p->filter_stream, NULL, NULL);
@@ -4452,7 +4453,7 @@ camel_message_info_new (CamelFolderSummary *s)
  *
  * Reference an info.
  **/
-void
+gpointer
 camel_message_info_ref (gpointer o)
 {
 	CamelMessageInfo *mi = o;
@@ -4468,6 +4469,8 @@ camel_message_info_ref (gpointer o)
 		mi->refcount++;
 		GLOBAL_INFO_UNLOCK (info);
 	}
+
+	return o;
 }
 
 /**
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index 5dcd835..c4e565f 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -435,7 +435,7 @@ void		camel_tag_list_free (CamelTag **list);
 /* Summary may be null */
 /* Use anonymous pointers to avoid tons of cast crap */
 gpointer camel_message_info_new (CamelFolderSummary *summary);
-void camel_message_info_ref (gpointer info);
+gpointer camel_message_info_ref (gpointer info);
 CamelMessageInfo *camel_message_info_new_from_header (CamelFolderSummary *summary, struct _camel_header_raw *header);
 void camel_message_info_free (gpointer info);
 gpointer camel_message_info_clone (gconstpointer info);
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 2863942..66cda68 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -49,6 +49,8 @@
 #define d(x)
 #define w(x)
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelFolderPrivate {
 	GStaticRecMutex lock;
 	GStaticMutex change_lock;
@@ -64,6 +66,20 @@ struct _CamelFolderPrivate {
 	gchar *description;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	CamelMimeMessage *message;  /* also a result */
+	CamelMessageInfo *info;
+	CamelFolder *destination;
+	GPtrArray *message_uids;
+	gchar *message_uid;         /* also a result */
+	gboolean delete_originals;
+	gboolean expunge;
+
+	/* results */
+	GPtrArray *transferred_uids;
+};
+
 struct _CamelFolderChangeInfoPrivate {
 	GHashTable *uid_stored;	/* what we have stored, which array they're in */
 	GHashTable *uid_source;	/* used to create unique lists */
@@ -102,6 +118,37 @@ static guint signals[LAST_SIGNAL];
 G_DEFINE_ABSTRACT_TYPE (CamelFolder, camel_folder, CAMEL_TYPE_OBJECT)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->message != NULL)
+		g_object_unref (async_context->message);
+
+	/* XXX This is actually an unref.  Good god, no wonder we
+	 *     have so many crashes involving CamelMessageInfos! */
+	if (async_context->info != NULL)
+		camel_message_info_free (async_context->info);
+
+	if (async_context->destination != NULL)
+		g_object_unref (async_context->destination);
+
+	if (async_context->message_uids != NULL) {
+		g_ptr_array_foreach (
+			async_context->message_uids, (GFunc) g_free, NULL);
+		g_ptr_array_free (async_context->message_uids, TRUE);
+	}
+
+	if (async_context->transferred_uids != NULL) {
+		g_ptr_array_foreach (
+			async_context->transferred_uids, (GFunc) g_free, NULL);
+		g_ptr_array_free (async_context->transferred_uids, TRUE);
+	}
+
+	g_free (async_context->message_uid);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 filter_filter (CamelSession *session,
                CamelSessionThreadMsg *tmsg)
 {
@@ -121,7 +168,7 @@ filter_filter (CamelSession *session,
 
 	if (m->junk) {
 		/* Translators: The %s is replaced with a folder name where the operation is running. */
-		camel_operation_start (
+		camel_operation_push_message (
 			tmsg->cancellable, ngettext (
 			"Learning new spam message in '%s'",
 			"Learning new spam messages in '%s'",
@@ -140,12 +187,12 @@ filter_filter (CamelSession *session,
 				g_object_unref (msg);
 			}
 		}
-		camel_operation_end (tmsg->cancellable);
+		camel_operation_pop_message (tmsg->cancellable);
 	}
 
 	if (m->notjunk) {
 		/* Translators: The %s is replaced with a folder name where the operation is running. */
-		camel_operation_start (
+		camel_operation_push_message (
 			tmsg->cancellable, ngettext (
 			"Learning new ham message in '%s'",
 			"Learning new ham messages in '%s'",
@@ -163,7 +210,7 @@ filter_filter (CamelSession *session,
 				g_object_unref (msg);
 			}
 		}
-		camel_operation_end (tmsg->cancellable);
+		camel_operation_pop_message (tmsg->cancellable);
 	}
 
 	if (m->junk || m->notjunk)
@@ -171,7 +218,7 @@ filter_filter (CamelSession *session,
 
 	if (m->driver && m->recents) {
 		/* Translators: The %s is replaced with a folder name where the operation is running. */
-		camel_operation_start (
+		camel_operation_push_message (
 			tmsg->cancellable, ngettext (
 			"Filtering new message in '%s'",
 			"Filtering new messages in '%s'",
@@ -218,7 +265,7 @@ filter_filter (CamelSession *session,
 
 		g_free (source_url);
 
-		camel_operation_end (tmsg->cancellable);
+		camel_operation_pop_message (tmsg->cancellable);
 	}
 }
 
@@ -755,8 +802,8 @@ static gboolean
 folder_transfer_messages_to_sync (CamelFolder *source,
                                   GPtrArray *uids,
                                   CamelFolder *dest,
-                                  GPtrArray **transferred_uids,
                                   gboolean delete_originals,
+                                  GPtrArray **transferred_uids,
                                   GCancellable *cancellable,
                                   GError **error)
 {
@@ -770,10 +817,10 @@ folder_transfer_messages_to_sync (CamelFolder *source,
 	}
 
 	if (delete_originals)
-		camel_operation_start (
+		camel_operation_push_message (
 			cancellable, _("Moving messages"));
 	else
-		camel_operation_start (
+		camel_operation_push_message (
 			cancellable, _("Copying messages"));
 
 	if (uids->len > 1) {
@@ -798,7 +845,7 @@ folder_transfer_messages_to_sync (CamelFolder *source,
 			camel_folder_thaw (source);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	if (local_error != NULL)
 		g_propagate_error (error, local_error);
@@ -806,6 +853,465 @@ folder_transfer_messages_to_sync (CamelFolder *source,
 	return TRUE;
 }
 
+static void
+folder_append_message_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_folder_append_message_sync (
+		CAMEL_FOLDER (object), async_context->message,
+		async_context->info, &async_context->message_uid,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_append_message (CamelFolder *folder,
+                       CamelMimeMessage *message,
+                       CamelMessageInfo *info,
+                       gint io_priority,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->message = g_object_ref (message);
+	async_context->info = camel_message_info_ref (info);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback,
+		user_data, folder_append_message);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_append_message_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_append_message_finish (CamelFolder *folder,
+                              GAsyncResult *result,
+                              gchar **appended_uid,
+                              GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), folder_append_message), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (appended_uid != NULL) {
+		*appended_uid = async_context->message_uid;
+		async_context->message_uid = NULL;
+	}
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+folder_expunge_thread (GSimpleAsyncResult *simple,
+                       GObject *object,
+                       GCancellable *cancellable)
+{
+	GError *error = NULL;
+
+	camel_folder_expunge_sync (
+		CAMEL_FOLDER (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_expunge (CamelFolder *folder,
+                gint io_priority,
+                GCancellable *cancellable,
+                GAsyncReadyCallback callback,
+                gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback, user_data, folder_expunge);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_expunge_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_expunge_finish (CamelFolder *folder,
+                       GAsyncResult *result,
+                       GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), folder_expunge), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+folder_get_message_thread (GSimpleAsyncResult *simple,
+                           GObject *object,
+                           GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->message = camel_folder_get_message_sync (
+		CAMEL_FOLDER (object), async_context->message_uid,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_get_message (CamelFolder *folder,
+                    const gchar *message_uid,
+                    gint io_priority,
+                    GCancellable *cancellable,
+                    GAsyncReadyCallback callback,
+                    gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->message_uid = g_strdup (message_uid);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback, user_data, folder_get_message);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_get_message_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelMimeMessage *
+folder_get_message_finish (CamelFolder *folder,
+                           GAsyncResult *result,
+                           GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), folder_get_message), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	return g_object_ref (async_context->message);
+}
+
+static void
+folder_refresh_info_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	GError *error = NULL;
+
+	camel_folder_refresh_info_sync (
+		CAMEL_FOLDER (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_refresh_info (CamelFolder *folder,
+                     gint io_priority,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback, user_data, folder_refresh_info);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_refresh_info_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_refresh_info_finish (CamelFolder *folder,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), folder_refresh_info), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+folder_synchronize_thread (GSimpleAsyncResult *simple,
+                           GObject *object,
+                           GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_folder_synchronize_sync (
+		CAMEL_FOLDER (object), async_context->expunge,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_synchronize (CamelFolder *folder,
+                    gboolean expunge,
+                    gint io_priority,
+                    GCancellable *cancellable,
+                    GAsyncReadyCallback callback,
+                    gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->expunge = expunge;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback, user_data, folder_synchronize);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_synchronize_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_synchronize_finish (CamelFolder *folder,
+                           GAsyncResult *result,
+                           GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), folder_synchronize), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+folder_synchronize_message_thread (GSimpleAsyncResult *simple,
+                                   GObject *object,
+                                   GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_folder_synchronize_message_sync (
+		CAMEL_FOLDER (object), async_context->message_uid,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_synchronize_message (CamelFolder *folder,
+                            const gchar *message_uid,
+                            gint io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->message_uid = g_strdup (message_uid);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback,
+		user_data, folder_synchronize_message);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_synchronize_message_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_synchronize_message_finish (CamelFolder *folder,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder),
+		folder_synchronize_message), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+folder_transfer_messages_to_thread (GSimpleAsyncResult *simple,
+                                    GObject *object,
+                                    GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_folder_transfer_messages_to_sync (
+		CAMEL_FOLDER (object), async_context->message_uids,
+		async_context->destination, async_context->delete_originals,
+		&async_context->transferred_uids, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+folder_transfer_messages_to (CamelFolder *source,
+                             GPtrArray *message_uids,
+                             CamelFolder *destination,
+                             gboolean delete_originals,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	guint ii;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->message_uids = g_ptr_array_new ();
+	async_context->destination = g_object_ref (destination);
+	async_context->delete_originals = delete_originals;
+
+	for (ii = 0; ii < message_uids->len; ii++)
+		g_ptr_array_add (
+			async_context->message_uids,
+			g_strdup (message_uids->pdata[ii]));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, folder_transfer_messages_to);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, folder_transfer_messages_to_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+folder_transfer_messages_to_finish (CamelFolder *source,
+                                    GAsyncResult *result,
+                                    GPtrArray **transferred_uids,
+                                    GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source),
+		folder_transfer_messages_to), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (transferred_uids != NULL) {
+		*transferred_uids = async_context->transferred_uids;
+		async_context->transferred_uids = NULL;
+	}
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
 /* Signal callback that stops emission when folder is frozen. */
 static void
 folder_changed (CamelFolder *folder,
@@ -936,6 +1442,21 @@ camel_folder_class_init (CamelFolderClass *class)
 	class->transfer_messages_to_sync = folder_transfer_messages_to_sync;
 	class->changed = folder_changed;
 
+	class->append_message = folder_append_message;
+	class->append_message_finish = folder_append_message_finish;
+	class->expunge = folder_expunge;
+	class->expunge_finish = folder_expunge_finish;
+	class->get_message = folder_get_message;
+	class->get_message_finish = folder_get_message_finish;
+	class->refresh_info = folder_refresh_info;
+	class->refresh_info_finish = folder_refresh_info_finish;
+	class->synchronize = folder_synchronize;
+	class->synchronize_finish = folder_synchronize_finish;
+	class->synchronize_message = folder_synchronize_message;
+	class->synchronize_message_finish = folder_synchronize_message_finish;
+	class->transfer_messages_to = folder_transfer_messages_to;
+	class->transfer_messages_to_finish = folder_transfer_messages_to_finish;
+
 	/**
 	 * CamelFolder:description
 	 *
@@ -1112,78 +1633,6 @@ camel_folder_get_filename (CamelFolder *folder,
 }
 
 /**
- * camel_folder_synchronize_sync:
- * @folder: a #CamelFolder
- * @expunge: whether or not to expunge deleted messages
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Sync changes made to a folder to its backing store, possibly
- * expunging deleted messages as well.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_folder_synchronize_sync (CamelFolder *folder,
-                               gboolean expunge,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success = TRUE;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
-		success = class->synchronize_sync (
-			folder, expunge, cancellable, error);
-		CAMEL_CHECK_GERROR (folder, synchronize_sync, success, error);
-	}
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	return success;
-}
-
-/**
- * camel_folder_refresh_info_sync:
- * @folder: a #CamelFolder
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Updates a folder's summary to be in sync with its backing store.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_folder_refresh_info_sync (CamelFolder *folder,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->refresh_info_sync != NULL, FALSE);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	success = class->refresh_info_sync (folder, cancellable, error);
-	CAMEL_CHECK_GERROR (folder, refresh_info_sync, success, error);
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	return success;
-}
-
-/**
  * camel_folder_get_name:
  * @folder: a #CamelFolder
  *
@@ -1316,41 +1765,6 @@ camel_folder_get_parent_store (CamelFolder *folder)
 }
 
 /**
- * camel_folder_expunge_sync:
- * @folder: a #CamelFolder
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Delete messages which have been marked as "DELETED"
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_folder_expunge_sync (CamelFolder *folder,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success = TRUE;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->expunge_sync != NULL, FALSE);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
-		success = class->expunge_sync (folder, cancellable, error);
-		CAMEL_CHECK_GERROR (folder, expunge_sync, success, error);
-	}
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	return success;
-}
-
-/**
  * camel_folder_get_message_count:
  * @folder: a #CamelFolder
  *
@@ -1404,50 +1818,6 @@ camel_folder_get_deleted_message_count (CamelFolder *folder)
 }
 
 /**
- * camel_folder_append_message_sync:
- * @folder: a #CamelFolder
- * @message: a #CamelMimeMessage object
- * @info: a #CamelMessageInfo with additional flags/etc to set on
- * new message, or %NULL
- * @appended_uid: if non-%NULL, the UID of the appended message will
- * be returned here, if it is known.
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Append @message to @folder. Only the flag and tag data from @info
- * are used. If @info is %NULL, no flags or tags will be set.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_folder_append_message_sync (CamelFolder *folder,
-                                  CamelMimeMessage *message,
-                                  const CamelMessageInfo *info,
-                                  gchar **appended_uid,
-                                  GCancellable *cancellable,
-                                  GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
-	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->append_message_sync != NULL, FALSE);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	success = class->append_message_sync (
-		folder, message, info, appended_uid, cancellable, error);
-	CAMEL_CHECK_GERROR (folder, append_message_sync, success, error);
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	return success;
-}
-
-/**
  * camel_folder_get_permanent_flags:
  * @folder: a #CamelFolder
  *
@@ -1750,110 +2120,6 @@ camel_folder_has_summary_capability (CamelFolder *folder)
 /* UIDs stuff */
 
 /**
- * camel_folder_get_message_sync:
- * @folder: a #CamelFolder
- * @uid: the UID
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Get a message from its UID in the folder.
- *
- * Returns: a #CamelMimeMessage corresponding to @uid
- **/
-CamelMimeMessage *
-camel_folder_get_message_sync (CamelFolder *folder,
-                               const gchar *uid,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-	CamelFolderClass *class;
-	CamelMimeMessage *ret;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
-	g_return_val_if_fail (uid != NULL, NULL);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->get_message_sync != NULL, NULL);
-
-	camel_operation_start (
-		cancellable, _("Retrieving message '%s'"), uid);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	ret = class->get_message_sync (folder, uid, cancellable, error);
-	CAMEL_CHECK_GERROR (folder, get_message_sync, ret != NULL, error);
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	camel_operation_end (cancellable);
-
-	if (ret && camel_debug_start (":folder")) {
-		printf ("CamelFolder:get_message ('%s', '%s') =\n",
-			camel_folder_get_full_name (folder), uid);
-		camel_mime_message_dump (ret, FALSE);
-		camel_debug_end ();
-	}
-
-	return ret;
-}
-
-/**
- * camel_folder_synchronize_message_sync:
- * @folder: a #CamelFolder
- * @uid: the UID
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Ensure that a message identified by UID has been synced in the folder (so
- * that camel_folder_get_message on it later will work in offline mode).
- *
- * Returns: %TRUE on success, %FALSE on failure
- *
- * Since: 2.26
- **/
-gboolean
-camel_folder_synchronize_message_sync (CamelFolder *folder,
-                                       const gchar *uid,
-                                       GCancellable *cancellable,
-                                       GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success = FALSE;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
-	g_return_val_if_fail (uid != NULL, FALSE);
-
-	class = CAMEL_FOLDER_GET_CLASS (folder);
-	g_return_val_if_fail (class->get_message_sync != NULL, FALSE);
-
-	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	/* Use the sync_message method if the class implements it. */
-	if (class->synchronize_message_sync != NULL) {
-		success = class->synchronize_message_sync (
-			folder, uid, cancellable, error);
-		CAMEL_CHECK_GERROR (
-			folder, synchronize_message_sync, success, error);
-	} else {
-		CamelMimeMessage *message;
-
-		message = class->get_message_sync (
-			folder, uid, cancellable, error);
-		CAMEL_CHECK_GERROR (
-			folder, get_message_sync, message != NULL, error);
-
-		if (message != NULL) {
-			g_object_unref (message);
-			success = TRUE;
-		}
-	}
-
-	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-
-	return success;
-}
-
-/**
  * camel_folder_get_uids:
  * @folder: a #CamelFolder
  *
@@ -2171,62 +2437,6 @@ camel_folder_search_free (CamelFolder *folder,
 }
 
 /**
- * camel_folder_transfer_messages_to_sync:
- * @source: the source #CamelFolder object
- * @uids: message UIDs in @source
- * @dest: the destination #CamelFolder object
- * @transferred_uids: if non-%NULL, the UIDs of the resulting messages
- * in @dest will be stored here, if known.
- * @delete_originals: whether or not to delete the original messages
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * This copies or moves messages from one folder to another. If the
- * @source and @dest folders have the same parent_store, this may be
- * more efficient than using #camel_folder_append_message.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_folder_transfer_messages_to_sync (CamelFolder *source,
-                                        GPtrArray *uids,
-                                        CamelFolder *dest,
-                                        GPtrArray **transferred_uids,
-                                        gboolean delete_originals,
-                                        GCancellable *cancellable,
-                                        GError **error)
-{
-	CamelFolderClass *class;
-	gboolean success;
-
-	g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE);
-	g_return_val_if_fail (CAMEL_IS_FOLDER (dest), FALSE);
-	g_return_val_if_fail (uids != NULL, FALSE);
-
-	if (source == dest || uids->len == 0) {
-		/* source and destination folders are the same, or no work to do, do nothing. */
-		return TRUE;
-	}
-
-	if (source->priv->parent_store == dest->priv->parent_store) {
-		/* If either folder is a vtrash, we need to use the
-		 * vtrash transfer method. */
-		if (CAMEL_IS_VTRASH_FOLDER (dest))
-			class = CAMEL_FOLDER_GET_CLASS (dest);
-		else
-			class = CAMEL_FOLDER_GET_CLASS (source);
-		success = class->transfer_messages_to_sync (
-			source, uids, dest, transferred_uids,
-			delete_originals, cancellable, error);
-	} else
-		success = folder_transfer_messages_to_sync (
-			source, uids, dest, transferred_uids,
-			delete_originals, cancellable, error);
-
-	return success;
-}
-
-/**
  * camel_folder_delete:
  * @folder: a #CamelFolder
  *
@@ -2551,6 +2761,830 @@ camel_folder_free_deep (CamelFolder *folder,
 }
 
 /**
+ * camel_folder_lock:
+ * @folder: a #CamelFolder
+ * @lock: lock type to lock
+ *
+ * Locks #folder's #lock. Unlock it with camel_folder_unlock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_folder_lock (CamelFolder *folder,
+                   CamelFolderLock lock)
+{
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+	switch (lock) {
+		case CAMEL_FOLDER_CHANGE_LOCK:
+			g_static_mutex_lock (&folder->priv->change_lock);
+			break;
+		case CAMEL_FOLDER_REC_LOCK:
+			if (folder->priv->skip_folder_lock == FALSE)
+				g_static_rec_mutex_lock (&folder->priv->lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_folder_unlock:
+ * @folder: a #CamelFolder
+ * @lock: lock type to unlock
+ *
+ * Unlocks #folder's #lock, previously locked with camel_folder_lock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_folder_unlock (CamelFolder *folder,
+                     CamelFolderLock lock)
+{
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+	switch (lock) {
+		case CAMEL_FOLDER_CHANGE_LOCK:
+			g_static_mutex_unlock (&folder->priv->change_lock);
+			break;
+		case CAMEL_FOLDER_REC_LOCK:
+			if (folder->priv->skip_folder_lock == FALSE)
+				g_static_rec_mutex_unlock (&folder->priv->lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_folder_append_message_sync:
+ * @folder: a #CamelFolder
+ * @message: a #CamelMimeMessage
+ * @info: a #CamelMessageInfo with additional flags/etc to set on the
+ *        new message, or %NULL
+ * @appended_uid: if non-%NULL, the UID of the appended message will
+ *                be returned here, if it is known
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Appends @message to @folder.  Only the flag and tag data from @info
+ * are used.  If @info is %NULL, no flags or tags will be set.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_append_message_sync (CamelFolder *folder,
+                                  CamelMimeMessage *message,
+                                  CamelMessageInfo *info,
+                                  gchar **appended_uid,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->append_message_sync != NULL, FALSE);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return FALSE;
+	}
+
+	success = class->append_message_sync (
+		folder, message, info, appended_uid, cancellable, error);
+	CAMEL_CHECK_GERROR (folder, append_message_sync, success, error);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_folder_append_message:
+ * @folder a #CamelFolder
+ * @message: a #CamelMimeMessage
+ * @info: a #CamelMessageInfo with additional flags/etc to set on the
+ *        new message, or %NULL
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Appends @message to @folder asynchronously.  Only the flag and tag data
+ * from @info are used.  If @info is %NULL, no flags or tags will be set.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_folder_append_message_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_append_message (CamelFolder *folder,
+                             CamelMimeMessage *message,
+                             CamelMessageInfo *info,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->append_message != NULL);
+
+	class->append_message (
+		folder, message, info, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_append_message_finish:
+ * @folder: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @appended_uid: if non-%NULL, the UID of the appended message will
+ *                be returned here, if it is known
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_folder_append_message_finish().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_append_message_finish (CamelFolder *folder,
+                                    GAsyncResult *result,
+                                    gchar **appended_uid,
+                                    GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->append_message_finish != NULL, FALSE);
+
+	return class->append_message_finish (
+		folder, result, appended_uid, error);
+}
+
+/**
+ * camel_folder_expunge_sync:
+ * @folder: a #CamelFolder
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes messages which have been marked as "DELETED".
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_expunge_sync (CamelFolder *folder,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success = TRUE;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->expunge_sync != NULL, FALSE);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return FALSE;
+	}
+
+	if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
+		success = class->expunge_sync (folder, cancellable, error);
+		CAMEL_CHECK_GERROR (folder, expunge_sync, success, error);
+	}
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_folder_expunge:
+ * @folder: a #CamelFolder
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes messages which have been marked as "DELETED".
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_folder_expunge_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_expunge (CamelFolder *folder,
+                      gint io_priority,
+                      GCancellable *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->expunge != NULL);
+
+	class->expunge (folder, io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_expunge_finish:
+ * @folder: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_folder_expunge().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_expunge_finish (CamelFolder *folder,
+                             GAsyncResult *result,
+                             GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->expunge_finish != NULL, FALSE);
+
+	return class->expunge_finish (folder, result, error);
+}
+
+/**
+ * camel_folder_get_message_sync:
+ * @folder: a #CamelFolder
+ * @message_uid: the message UID
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the message corresponding to @message_uid from @folder.
+ *
+ * Returns: a #CamelMimeMessage corresponding to the requested UID
+ *
+ * Since: 2.34
+ **/
+CamelMimeMessage *
+camel_folder_get_message_sync (CamelFolder *folder,
+                               const gchar *message_uid,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+	CamelFolderClass *class;
+	CamelMimeMessage *message;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+	g_return_val_if_fail (message_uid != NULL, NULL);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->get_message_sync != NULL, NULL);
+
+	camel_operation_push_message (
+		cancellable, _("Retrieving message '%s'"), message_uid);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return NULL;
+	}
+
+	message = class->get_message_sync (
+		folder, message_uid, cancellable, error);
+	CAMEL_CHECK_GERROR (folder, get_message_sync, message != NULL, error);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	camel_operation_pop_message (cancellable);
+
+	if (message != NULL && camel_debug_start (":folder")) {
+		printf ("CamelFolder:get_message ('%s', '%s') =\n",
+			camel_folder_get_full_name (folder), message_uid);
+		camel_mime_message_dump (message, FALSE);
+		camel_debug_end ();
+	}
+
+	return message;
+}
+
+/**
+ * camel_folder_get_message:
+ * @folder: a #CamelFolder
+ * @message_uid: the message UID
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously gets the message corresponding to @message_uid from @folder.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_folder_get_message_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_get_message (CamelFolder *folder,
+                          const gchar *message_uid,
+                          gint io_priority,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+	g_return_if_fail (message_uid != NULL);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->get_message != NULL);
+
+	class->get_message (
+		folder, message_uid, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_get_message_finish:
+ * @folder: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError or %NULL
+ *
+ * Finishes the operation started with camel_folder_get_message().
+ *
+ * Returns: a #CamelMimeMessage corresponding to the requested UID
+ *
+ * Since: 2.34
+ **/
+CamelMimeMessage *
+camel_folder_get_message_finish (CamelFolder *folder,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->get_message_finish != NULL, NULL);
+
+	return class->get_message_finish (folder, result, error);
+}
+
+/**
+ * camel_folder_refresh_info_sync:
+ * @folder: a #CamelFolder
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Synchronizes a folder's summary with its backing store.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_refresh_info_sync (CamelFolder *folder,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->refresh_info_sync != NULL, FALSE);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return FALSE;
+	}
+
+	success = class->refresh_info_sync (folder, cancellable, error);
+	CAMEL_CHECK_GERROR (folder, refresh_info_sync, success, error);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_folder_synchronize_sync:
+ * @folder: a #CamelFolder
+ * @expunge: whether to expunge after synchronizing
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Synchronizes any changes that have been made to @folder to its
+ * backing store, optionally expunging deleted messages as well.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_synchronize_sync (CamelFolder *folder,
+                               gboolean expunge,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success = TRUE;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return FALSE;
+	}
+
+	if (!(folder->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED)) {
+		success = class->synchronize_sync (
+			folder, expunge, cancellable, error);
+		CAMEL_CHECK_GERROR (folder, synchronize_sync, success, error);
+	}
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_folder_synchronize:
+ * @folder: a #CamelFolder
+ * @expunge: whether to expunge after synchronizing
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Synchronizes any changes that have been made to @folder to its backing
+ * store asynchronously, optionally expunging deleted messages as well.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_folder_synchronize_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_synchronize (CamelFolder *folder,
+                          gboolean expunge,
+                          gint io_priority,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->synchronize != NULL);
+
+	class->synchronize (
+		folder, expunge, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_synchronize_finish:
+ * @folder: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_folder_synchronize().
+ *
+ * Returns: %TRUE on sucess, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_synchronize_finish (CamelFolder *folder,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->synchronize_finish != NULL, FALSE);
+
+	return class->synchronize_finish (folder, result, error);
+}
+
+/**
+ * camel_folder_synchronize_message_sync:
+ * @folder: a #CamelFolder
+ * @message_uid: a message UID
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Ensure that a message identified by @message_uid has been synchronized in
+ * @folder so that calling camel_folder_get_message() on it later will work
+ * in offline mode.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_synchronize_message_sync (CamelFolder *folder,
+                                       const gchar *message_uid,
+                                       GCancellable *cancellable,
+                                       GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (message_uid != NULL, FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->get_message_sync != NULL, FALSE);
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+		return FALSE;
+	}
+
+	/* Use the sync_message method if the class implements it. */
+	if (class->synchronize_message_sync != NULL) {
+		success = class->synchronize_message_sync (
+			folder, message_uid, cancellable, error);
+		CAMEL_CHECK_GERROR (
+			folder, synchronize_message_sync, success, error);
+	} else {
+		CamelMimeMessage *message;
+
+		message = class->get_message_sync (
+			folder, message_uid, cancellable, error);
+		CAMEL_CHECK_GERROR (
+			folder, get_message_sync, message != NULL, error);
+
+		if (message != NULL) {
+			g_object_unref (message);
+			success = TRUE;
+		}
+	}
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_folder_synchronize_message;
+ * @folder: a #CamelFolder
+ * @message_uid: a message UID
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously ensure that a message identified by @message_uid has been
+ * synchronized in @folder so that calling camel_folder_get_message() on it
+ * later will work in offline mode.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_folder_synchronize_message_finish() to get the result of the
+ * operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_synchronize_message (CamelFolder *folder,
+                                  const gchar *message_uid,
+                                  gint io_priority,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (folder));
+	g_return_if_fail (message_uid != NULL);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->synchronize_message != NULL);
+
+	class->synchronize_message (
+		folder, message_uid, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_synchronize_message_finish:
+ * @folder: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_folder_synchronize_message().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_synchronize_message_finish (CamelFolder *folder,
+                                         GAsyncResult *result,
+                                         GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->synchronize_message_finish != NULL, FALSE);
+
+	return class->synchronize_message_finish (folder, result, error);
+}
+
+/**
+ * camel_folder_transfer_messages_to_sync:
+ * @source: the source #CamelFolder
+ * @message_uids: message UIDs in @source
+ * @destination: the destination #CamelFolder
+ * @delete_originals: whether or not to delete the original messages
+ * @transferred_uids: if non-%NULL, the UIDs of the resulting messages
+ *                    in @destination will be stored here, if known.
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Copies or moves messages from one folder to another.  If the
+ * @source and @destination folders have the same parent_store, this
+ * may be more efficient than using camel_folder_append_message_sync().
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_transfer_messages_to_sync (CamelFolder *source,
+                                        GPtrArray *message_uids,
+                                        CamelFolder *destination,
+                                        gboolean delete_originals,
+                                        GPtrArray **transferred_uids,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+	CamelFolderClass *class;
+	gboolean success;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE);
+	g_return_val_if_fail (CAMEL_IS_FOLDER (destination), FALSE);
+	g_return_val_if_fail (message_uids != NULL, FALSE);
+
+	if (source == destination || message_uids->len == 0)
+		return TRUE;
+
+	if (source->priv->parent_store == destination->priv->parent_store) {
+		/* If either folder is a vtrash, we need to use the
+		 * vtrash transfer method. */
+		if (CAMEL_IS_VTRASH_FOLDER (destination))
+			class = CAMEL_FOLDER_GET_CLASS (destination);
+		else
+			class = CAMEL_FOLDER_GET_CLASS (source);
+		success = class->transfer_messages_to_sync (
+			source, message_uids, destination, delete_originals,
+			transferred_uids, cancellable, error);
+	} else
+		success = folder_transfer_messages_to_sync (
+			source, message_uids, destination, delete_originals,
+			transferred_uids, cancellable, error);
+
+	return success;
+}
+
+/**
+ * camel_folder_transfer_messages_to:
+ * @source: the source #CamelFolder
+ * @message_uids: message UIDs in @source
+ * @destination: the destination #CamelFolder
+ * @delete_originals: whether or not to delete the original messages
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously copies or moves messages from one folder to another.
+ * If the @source or @destination folders have the same parent store,
+ * this may be more efficient than using camel_folder_append_message().
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_folder_transfer_messages_to_finish() to get the result of the
+ * operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_folder_transfer_messages_to (CamelFolder *source,
+                                   GPtrArray *message_uids,
+                                   CamelFolder *destination,
+                                   gboolean delete_originals,
+                                   gint io_priority,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+	CamelFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_FOLDER (source));
+	g_return_if_fail (CAMEL_IS_FOLDER (destination));
+	g_return_if_fail (message_uids != NULL);
+
+	class = CAMEL_FOLDER_GET_CLASS (source);
+	g_return_if_fail (class->transfer_messages_to != NULL);
+
+	class->transfer_messages_to (
+		source, message_uids, destination, delete_originals,
+		io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_folder_transfer_messages_to_finish:
+ * @source: a #CamelFolder
+ * @result: a #GAsyncResult
+ * @transferred_uids: if non-%NULL, the UIDs of the resulting messages
+ *                    in @destination will be stored here, if known.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_folder_transfer_messages_to().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_folder_transfer_messages_to_finish (CamelFolder *source,
+                                          GAsyncResult *result,
+                                          GPtrArray **transferred_uids,
+                                          GError **error)
+{
+	CamelFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (source), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (source);
+	g_return_val_if_fail (class->transfer_messages_to_finish != NULL, FALSE);
+
+	return class->transfer_messages_to_finish (
+		source, result, transferred_uids, error);
+}
+
+/**
  * camel_folder_change_info_new:
  *
  * Create a new folder change info structure.
@@ -2991,59 +4025,3 @@ camel_folder_change_info_free (CamelFolderChangeInfo *info)
 	g_ptr_array_free (info->uid_recent, TRUE);
 	g_slice_free (CamelFolderChangeInfo, info);
 }
-
-/**
- * camel_folder_lock:
- * @folder: a #CamelFolder
- * @lock: lock type to lock
- *
- * Locks #folder's #lock. Unlock it with camel_folder_unlock().
- *
- * Since: 2.32
- **/
-void
-camel_folder_lock (CamelFolder *folder,
-                   CamelFolderLock lock)
-{
-	g_return_if_fail (CAMEL_IS_FOLDER (folder));
-
-	switch (lock) {
-		case CAMEL_FOLDER_CHANGE_LOCK:
-			g_static_mutex_lock (&folder->priv->change_lock);
-			break;
-		case CAMEL_FOLDER_REC_LOCK:
-			if (folder->priv->skip_folder_lock == FALSE)
-				g_static_rec_mutex_lock (&folder->priv->lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
-}
-
-/**
- * camel_folder_unlock:
- * @folder: a #CamelFolder
- * @lock: lock type to unlock
- *
- * Unlocks #folder's #lock, previously locked with camel_folder_lock().
- *
- * Since: 2.32
- **/
-void
-camel_folder_unlock (CamelFolder *folder,
-                     CamelFolderLock lock)
-{
-	g_return_if_fail (CAMEL_IS_FOLDER (folder));
-
-	switch (lock) {
-		case CAMEL_FOLDER_CHANGE_LOCK:
-			g_static_mutex_unlock (&folder->priv->change_lock);
-			break;
-		case CAMEL_FOLDER_REC_LOCK:
-			if (folder->priv->skip_folder_lock == FALSE)
-				g_static_rec_mutex_unlock (&folder->priv->lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
-}
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index 652cba7..0fb551b 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -143,7 +143,7 @@ struct _CamelFolder {
 struct _CamelFolderClass {
 	CamelObjectClass parent_class;
 
-	/* Methods */
+	/* Non-Blocking Methods */
 	gint		(*get_message_count)	(CamelFolder *folder);
 	guint32		(*get_permanent_flags)	(CamelFolder *folder);
 	guint32		(*get_message_flags)	(CamelFolder *folder,
@@ -212,9 +212,10 @@ struct _CamelFolderClass {
 						 const gchar *uid,
 						 GError **error);
 
+	/* Synchronous I/O Methods */
 	gboolean	(*append_message_sync)	(CamelFolder *folder,
 						 CamelMimeMessage *message,
-						 const CamelMessageInfo *info,
+						 CamelMessageInfo *info,
 						 gchar **appended_uid,
 						 GCancellable *cancellable,
 						 GError **error);
@@ -223,7 +224,7 @@ struct _CamelFolderClass {
 						 GError **error);
 	CamelMimeMessage *
 			(*get_message_sync)	(CamelFolder *folder,
-						 const gchar *uid,
+						 const gchar *message_uid,
 						 GCancellable *cancellable,
 						 GError **error);
 	gboolean	(*refresh_info_sync)	(CamelFolder *folder,
@@ -235,16 +236,88 @@ struct _CamelFolderClass {
 						 GError **error);
 	gboolean	(*synchronize_message_sync)
 						(CamelFolder *folder,
-						 const gchar *uid,
+						 const gchar *message_uid,
 						 GCancellable *cancellable,
 						 GError **error);
 	gboolean	(*transfer_messages_to_sync)
 						(CamelFolder *source,
-						 GPtrArray *uids,
+						 GPtrArray *message_uids,
 						 CamelFolder *destination,
+						 gboolean delete_originals,
 						 GPtrArray **transferred_uids,
+						 GCancellable *cancellable,
+						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*append_message)	(CamelFolder *folder,
+						 CamelMimeMessage *message,
+						 CamelMessageInfo *info,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*append_message_finish)
+						(CamelFolder *folder,
+						 GAsyncResult *result,
+						 gchar **appended_uid,
+						 GError **error);
+	void		(*expunge)		(CamelFolder *folder,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*expunge_finish)	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*get_message)		(CamelFolder *folder,
+						 const gchar *message_uid,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelMimeMessage *
+			(*get_message_finish)	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*refresh_info)		(CamelFolder *folder,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*refresh_info_finish)	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*synchronize)		(CamelFolder *folder,
+						 gboolean expunge,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*synchronize_finish)	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*synchronize_message)	(CamelFolder *folder,
+						 const gchar *message_uid,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*synchronize_message_finish)
+						(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*transfer_messages_to)	(CamelFolder *source,
+						 GPtrArray *message_uids,
+						 CamelFolder *destination,
 						 gboolean delete_originals,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*transfer_messages_to_finish)
+						(CamelFolder *source,
+						 GAsyncResult *result,
+						 GPtrArray **transferred_uids,
 						 GError **error);
 
 	/* Signals */
@@ -378,40 +451,118 @@ void		camel_folder_free_deep		(CamelFolder *folder,
 gchar *		camel_folder_get_filename	(CamelFolder *folder,
 						 const gchar *uid,
 						 GError **error);
+void		camel_folder_lock		(CamelFolder *folder,
+						 CamelFolderLock lock);
+void		camel_folder_unlock		(CamelFolder *folder,
+						 CamelFolderLock lock);
+
 gboolean	camel_folder_append_message_sync
 						(CamelFolder *folder,
 						 CamelMimeMessage *message,
-						 const CamelMessageInfo *info,
+						 CamelMessageInfo *info,
 						 gchar **appended_uid,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_folder_append_message	(CamelFolder *folder,
+						 CamelMimeMessage *message,
+						 CamelMessageInfo *info,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_append_message_finish
+						(CamelFolder *folder,
+						 GAsyncResult *result,
+						 gchar **appended_uid,
+						 GError **error);
 gboolean	camel_folder_expunge_sync	(CamelFolder *folder,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_folder_expunge		(CamelFolder *folder,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_expunge_finish	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
 CamelMimeMessage *
 		camel_folder_get_message_sync	(CamelFolder *folder,
-						 const gchar *uid,
+						 const gchar *message_uid,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_folder_get_message	(CamelFolder *folder,
+						 const gchar *message_uid,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelMimeMessage *
+		camel_folder_get_message_finish	(CamelFolder *folder,
+						 GAsyncResult *result,
 						 GError **error);
 gboolean	camel_folder_refresh_info_sync	(CamelFolder *folder,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_folder_refresh_info	(CamelFolder *folder,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_refresh_info_finish
+						(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_folder_synchronize_sync	(CamelFolder *folder,
 						 gboolean expunge,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_folder_synchronize	(CamelFolder *folder,
+						 gboolean expunge,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_synchronize_finish	(CamelFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_folder_synchronize_message_sync
 						(CamelFolder *folder,
-						 const gchar *uid,
+						 const gchar *message_uid,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_folder_synchronize_message
+						(CamelFolder *folder,
+						 const gchar *message_uid,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_synchronize_message_finish
+						(CamelFolder *folder,
+						 GAsyncResult *result,
 						 GError **error);
 gboolean	camel_folder_transfer_messages_to_sync
 						(CamelFolder *source,
-						 GPtrArray *uids,
-						 CamelFolder *dest,
+						 GPtrArray *message_uids,
+						 CamelFolder *destination,
+						 gboolean delete_originals,
 						 GPtrArray **transferred_uids,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_folder_transfer_messages_to
+						(CamelFolder *source,
+						 GPtrArray *message_uids,
+						 CamelFolder *destination,
 						 gboolean delete_originals,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_folder_transfer_messages_to_finish
+						(CamelFolder *source,
+						 GAsyncResult *result,
+						 GPtrArray **transferred_uids,
 						 GError **error);
 
 /* update functions for change info */
@@ -452,11 +603,6 @@ void		camel_folder_change_info_recent_uid
 						(CamelFolderChangeInfo *info,
 						 const gchar *uid);
 
-void		camel_folder_lock		(CamelFolder *folder,
-						 CamelFolderLock lock);
-void		camel_folder_unlock		(CamelFolder *folder,
-						 CamelFolderLock lock);
-
 G_END_DECLS
 
 #endif /* CAMEL_FOLDER_H */
diff --git a/camel/camel-gpg-context.c b/camel/camel-gpg-context.c
index a63257f..f027917 100644
--- a/camel/camel-gpg-context.c
+++ b/camel/camel-gpg-context.c
@@ -1506,7 +1506,7 @@ gpg_id_to_hash (CamelCipherContext *context,
 	return CAMEL_CIPHER_HASH_DEFAULT;
 }
 
-static gint
+static gboolean
 gpg_sign_sync (CamelCipherContext *context,
                const gchar *userid,
                CamelCipherHash hash,
@@ -1520,9 +1520,9 @@ gpg_sign_sync (CamelCipherContext *context,
 	CamelStream *ostream = camel_stream_mem_new (), *istream;
 	CamelDataWrapper *dw;
 	CamelContentType *ct;
-	gint res = -1;
 	CamelMimePart *sigpart;
 	CamelMultipartSigned *mps;
+	gboolean success = FALSE;
 
 	/* Note: see rfc2015 or rfc3156, section 5 */
 
@@ -1588,7 +1588,7 @@ gpg_sign_sync (CamelCipherContext *context,
 		goto fail;
 	}
 
-	res = 0;
+	success = TRUE;
 
 	dw = camel_data_wrapper_new ();
 	camel_stream_reset (ostream, NULL);
@@ -1608,7 +1608,7 @@ gpg_sign_sync (CamelCipherContext *context,
 
 	mps = camel_multipart_signed_new ();
 	ct = camel_content_type_new("multipart", "signed");
-	camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id (context, hash == CAMEL_CIPHER_HASH_DEFAULT ? gpg->hash : hash));
+	camel_content_type_set_param(ct, "micalg", camel_cipher_context_hash_to_id (context, hash == CAMEL_CIPHER_HASH_DEFAULT ? gpg->hash : hash));
 	camel_content_type_set_param(ct, "protocol", class->sign_protocol);
 	camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *)mps, ct);
 	camel_content_type_unref (ct);
@@ -1626,7 +1626,7 @@ fail:
 	if (gpg)
 		gpg_ctx_free (gpg);
 
-	return res;
+	return success;
 }
 
 static CamelCipherValidity *
@@ -1689,8 +1689,9 @@ gpg_verify_sync (CamelCipherContext *context,
 		CamelDataWrapper *content;
 		content = camel_medium_get_content ((CamelMedium *) ipart);
 		istream = camel_stream_mem_new ();
-		camel_data_wrapper_decode_to_stream_sync (
-			content, istream, NULL, NULL);
+		if (!camel_data_wrapper_decode_to_stream_sync (
+			content, istream, cancellable, error))
+			goto exception;
 		camel_stream_reset (istream, NULL);
 		sigpart = NULL;
 	} else {
@@ -1831,7 +1832,7 @@ gpg_verify_sync (CamelCipherContext *context,
 	return NULL;
 }
 
-static gint
+static gboolean
 gpg_encrypt_sync (CamelCipherContext *context,
                   const gchar *userid,
                   GPtrArray *recipients,
@@ -1843,12 +1844,13 @@ gpg_encrypt_sync (CamelCipherContext *context,
 	CamelCipherContextClass *class;
 	CamelGpgContext *ctx = (CamelGpgContext *) context;
 	struct _GpgCtx *gpg;
-	gint i, res = -1;
 	CamelStream *istream, *ostream, *vstream;
 	CamelMimePart *encpart, *verpart;
 	CamelDataWrapper *dw;
 	CamelContentType *ct;
 	CamelMultipartEncrypted *mpe;
+	gboolean success = FALSE;
+	gint i;
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 
@@ -1895,7 +1897,7 @@ gpg_encrypt_sync (CamelCipherContext *context,
 		goto fail;
 	}
 
-	res = 0;
+	success = TRUE;
 
 	dw = camel_data_wrapper_new ();
 	camel_data_wrapper_construct_from_stream_sync (
@@ -1946,7 +1948,7 @@ fail1:
 	g_object_unref (istream);
 	g_object_unref (ostream);
 
-	return res;
+	return success;
 }
 
 static CamelCipherValidity *
@@ -1956,14 +1958,14 @@ gpg_decrypt_sync (CamelCipherContext *context,
                   GCancellable *cancellable,
                   GError **error)
 {
-	struct _GpgCtx *gpg;
+	struct _GpgCtx *gpg = NULL;
 	CamelCipherValidity *valid = NULL;
 	CamelStream *ostream, *istream;
 	CamelDataWrapper *content;
 	CamelMimePart *encrypted;
 	CamelMultipart *mp;
 	CamelContentType *ct;
-	gint rv;
+	gboolean success;
 
 	if (!ipart) {
 		g_set_error (
@@ -2005,8 +2007,9 @@ gpg_decrypt_sync (CamelCipherContext *context,
 	}
 
 	istream = camel_stream_mem_new ();
-	camel_data_wrapper_decode_to_stream_sync (
-		content, istream, NULL, NULL);
+	if (!camel_data_wrapper_decode_to_stream_sync (
+		content, istream, cancellable, error))
+		goto fail;
 	camel_stream_reset (istream, NULL);
 
 	ostream = camel_stream_mem_new ();
@@ -2044,7 +2047,7 @@ gpg_decrypt_sync (CamelCipherContext *context,
 		CamelStream *null = camel_stream_null_new ();
 
 		/* Multipart encrypted - parse a full mime part */
-		rv = camel_data_wrapper_construct_from_stream_sync (
+		success = camel_data_wrapper_construct_from_stream_sync (
 			CAMEL_DATA_WRAPPER (opart),
 			ostream, NULL, error);
 
@@ -2054,8 +2057,8 @@ gpg_decrypt_sync (CamelCipherContext *context,
 			/* nothing had been decoded from the stream, it doesn't
 			   contain any header, like Content-Type or such, thus
 			   write it as a message body */
-			rv = camel_data_wrapper_construct_from_stream_sync (
-				dw, ostream, NULL, error);
+			success = camel_data_wrapper_construct_from_stream_sync (
+				dw, ostream, cancellable, error);
 		}
 
 		g_object_unref (null);
@@ -2063,7 +2066,7 @@ gpg_decrypt_sync (CamelCipherContext *context,
 		/* Inline signed - raw data (may not be a mime part) */
 		CamelDataWrapper *dw;
 		dw = camel_data_wrapper_new ();
-		rv = camel_data_wrapper_construct_from_stream_sync (
+		success = camel_data_wrapper_construct_from_stream_sync (
 			dw, ostream, NULL, error);
 		camel_data_wrapper_set_mime_type(dw, "application/octet-stream");
 		camel_medium_set_content ((CamelMedium *)opart, dw);
@@ -2072,7 +2075,7 @@ gpg_decrypt_sync (CamelCipherContext *context,
 		camel_mime_part_set_content_type(opart, "application/octet-stream");
 	}
 
-	if (rv != -1) {
+	if (success) {
 		valid = camel_cipher_validity_new ();
 		valid->encrypt.description = g_strdup(_("Encrypted content"));
 		valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
@@ -2103,14 +2106,14 @@ gpg_decrypt_sync (CamelCipherContext *context,
 	return valid;
 }
 
-static gint
+static gboolean
 gpg_import_keys_sync (CamelCipherContext *context,
                       CamelStream *istream,
                       GCancellable *cancellable,
                       GError **error)
 {
 	struct _GpgCtx *gpg;
-	gint res = -1;
+	gboolean success = FALSE;
 
 	gpg = gpg_ctx_new (context);
 	gpg_ctx_set_mode (gpg, GPG_CTX_MODE_IMPORT);
@@ -2137,14 +2140,14 @@ gpg_import_keys_sync (CamelCipherContext *context,
 		goto fail;
 	}
 
-	res = 0;
+	success = TRUE;
 fail:
 	gpg_ctx_free (gpg);
 
-	return res;
+	return success;
 }
 
-static gint
+static gboolean
 gpg_export_keys_sync (CamelCipherContext *context,
                       GPtrArray *keys,
                       CamelStream *ostream,
@@ -2152,8 +2155,8 @@ gpg_export_keys_sync (CamelCipherContext *context,
                       GError **error)
 {
 	struct _GpgCtx *gpg;
+	gboolean success = FALSE;
 	gint i;
-	gint res = -1;
 
 	gpg = gpg_ctx_new (context);
 	gpg_ctx_set_mode (gpg, GPG_CTX_MODE_EXPORT);
@@ -2185,11 +2188,11 @@ gpg_export_keys_sync (CamelCipherContext *context,
 		goto fail;
 	}
 
-	res = 0;
+	success = TRUE;
 fail:
 	gpg_ctx_free (gpg);
 
-	return res;
+	return success;
 }
 
 static void
diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c
index ba97e3a..217b85c 100644
--- a/camel/camel-mime-message.c
+++ b/camel/camel-mime-message.c
@@ -288,7 +288,7 @@ mime_message_remove_header (CamelMedium *medium,
 	CAMEL_MEDIUM_CLASS (camel_mime_message_parent_class)->remove_header (medium, name);
 }
 
-static gint
+static gboolean
 mime_message_construct_from_parser_sync (CamelMimePart *dw,
                                          CamelMimeParser *mp,
                                          GCancellable *cancellable,
@@ -298,16 +298,16 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw,
 	gchar *buf;
 	gsize len;
 	gint state;
-	gint ret;
 	gint err;
+	gboolean success;
 
 	/* let the mime-part construct the guts ... */
 	mime_part_class = CAMEL_MIME_PART_CLASS (camel_mime_message_parent_class);
-	ret = mime_part_class->construct_from_parser_sync (
+	success = mime_part_class->construct_from_parser_sync (
 		dw, mp, cancellable, error);
 
-	if (ret == -1)
-		return -1;
+	if (!success)
+		return FALSE;
 
 	/* ... then clean up the follow-on state */
 	state = camel_mime_parser_step (mp, &buf, &len);
@@ -321,7 +321,7 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw,
 	default:
 		g_error ("Bad parser state: Expecing MESSAGE_END or EOF or EOM, got: %u", camel_mime_parser_state (mp));
 		camel_mime_parser_unstep (mp);
-		return -1;
+		return FALSE;
 	}
 
 	err = camel_mime_parser_errno (mp);
@@ -331,10 +331,10 @@ mime_message_construct_from_parser_sync (CamelMimePart *dw,
 			error, G_IO_ERROR,
 			g_io_error_from_errno (errno),
 			"%s", g_strerror (errno));
-		ret = -1;
+		success = FALSE;
 	}
 
-	return ret;
+	return success;
 }
 
 static void
@@ -845,7 +845,10 @@ camel_mime_message_has_8bit_parts (CamelMimeMessage *msg)
 
 /* finds the best charset and transfer encoding for a given part */
 static CamelTransferEncoding
-find_best_encoding (CamelMimePart *part, CamelBestencRequired required, CamelBestencEncoding enctype, gchar **charsetp)
+find_best_encoding (CamelMimePart *part,
+                    CamelBestencRequired required,
+                    CamelBestencEncoding enctype,
+                    gchar **charsetp)
 {
 	CamelMimeFilter *charenc = NULL;
 	CamelTransferEncoding encoding;
@@ -1034,7 +1037,9 @@ best_encoding (CamelMimeMessage *msg, CamelMimePart *part, gpointer datap)
  * parts will be encoded as binary and 8bit textual parts will be encoded as 8bit.
  **/
 void
-camel_mime_message_set_best_encoding (CamelMimeMessage *msg, CamelBestencRequired required, CamelBestencEncoding enctype)
+camel_mime_message_set_best_encoding (CamelMimeMessage *msg,
+                                      CamelBestencRequired required,
+                                      CamelBestencEncoding enctype)
 {
 	struct _enc_data data;
 
diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h
index f4cac90..3f6ae1f 100644
--- a/camel/camel-mime-message.h
+++ b/camel/camel-mime-message.h
@@ -93,55 +93,63 @@ struct _CamelMimeMessageClass {
 	CamelMimePartClass parent_class;
 };
 
-GType                   camel_mime_message_get_type           (void);
-
-/* public methods */
-CamelMimeMessage           *camel_mime_message_new                (void);
-void                        camel_mime_message_set_date           (CamelMimeMessage           *message,
-								   time_t                      date,
-								   gint                         offset);
-time_t                      camel_mime_message_get_date           (CamelMimeMessage           *message,
-								   gint                        *offset);
-time_t                      camel_mime_message_get_date_received  (CamelMimeMessage           *message,
-								   gint                        *offset);
-void                        camel_mime_message_set_message_id     (CamelMimeMessage           *message,
-								   const gchar                 *message_id);
-const gchar                 *camel_mime_message_get_message_id     (CamelMimeMessage           *message);
-void                        camel_mime_message_set_reply_to       (CamelMimeMessage           *message,
-								   CamelInternetAddress *reply_to);
-CamelInternetAddress *      camel_mime_message_get_reply_to       (CamelMimeMessage           *message);
-
-void                        camel_mime_message_set_subject        (CamelMimeMessage           *message,
-								   const gchar                 *subject);
-const gchar                 *camel_mime_message_get_subject        (CamelMimeMessage           *message);
-void                        camel_mime_message_set_from           (CamelMimeMessage           *message,
-								   CamelInternetAddress *from);
-CamelInternetAddress *      camel_mime_message_get_from           (CamelMimeMessage           *message);
-
-CamelInternetAddress *      camel_mime_message_get_recipients     (CamelMimeMessage           *message,
-								   const gchar                 *type);
-void                        camel_mime_message_set_recipients     (CamelMimeMessage           *message,
-								   const gchar                 *type,
-								   CamelInternetAddress *recipients);
-
-void                        camel_mime_message_set_source         (CamelMimeMessage           *message,
-								   const gchar                 *identity);
-const gchar                 *camel_mime_message_get_source         (CamelMimeMessage           *message);
+GType		camel_mime_message_get_type	(void);
+CamelMimeMessage *
+		camel_mime_message_new		(void);
+void		camel_mime_message_set_date	(CamelMimeMessage *message,
+						 time_t date,
+						 gint offset);
+time_t		camel_mime_message_get_date	(CamelMimeMessage *message,
+						 gint *offset);
+time_t		camel_mime_message_get_date_received
+						(CamelMimeMessage *message,
+						 gint *offset);
+void		camel_mime_message_set_message_id
+						(CamelMimeMessage *message,
+						 const gchar *message_id);
+const gchar *	camel_mime_message_get_message_id
+						 (CamelMimeMessage *message);
+void		camel_mime_message_set_reply_to	(CamelMimeMessage *message,
+						 CamelInternetAddress *reply_to);
+CamelInternetAddress *
+		camel_mime_message_get_reply_to	(CamelMimeMessage *message);
+void		camel_mime_message_set_subject	(CamelMimeMessage *message,
+						 const gchar *subject);
+const gchar *	camel_mime_message_get_subject	(CamelMimeMessage *message);
+void		camel_mime_message_set_from	(CamelMimeMessage *message,
+						 CamelInternetAddress *from);
+CamelInternetAddress *
+		camel_mime_message_get_from	(CamelMimeMessage *message);
+CamelInternetAddress *
+		camel_mime_message_get_recipients
+						(CamelMimeMessage *message,
+						 const gchar *type);
+void		camel_mime_message_set_recipients
+						(CamelMimeMessage *message,
+						 const gchar *type,
+						 CamelInternetAddress *recipients);
+void		camel_mime_message_set_source	(CamelMimeMessage *message,
+						 const gchar *identity);
+const gchar *	camel_mime_message_get_source	(CamelMimeMessage *message);
 
 /* utility functions */
-gboolean                    camel_mime_message_has_8bit_parts     (CamelMimeMessage           *message);
-void                        camel_mime_message_set_best_encoding  (CamelMimeMessage           *message,
-								   CamelBestencRequired        required,
-								   CamelBestencEncoding        enctype);
-void                        camel_mime_message_encode_8bit_parts  (CamelMimeMessage           *message);
-
-CamelMimePart              *camel_mime_message_get_part_by_content_id (CamelMimeMessage *message, const gchar *content_id);
-
-gchar                       *camel_mime_message_build_mbox_from    (CamelMimeMessage           *message);
-
-gboolean		    camel_mime_message_has_attachment     (CamelMimeMessage           *message);
-
-void camel_mime_message_dump (CamelMimeMessage *msg, gint body);
+gboolean	camel_mime_message_has_8bit_parts
+						(CamelMimeMessage *message);
+void		camel_mime_message_set_best_encoding
+						(CamelMimeMessage *message,
+						 CamelBestencRequired required,
+						 CamelBestencEncoding enctype);
+void		camel_mime_message_encode_8bit_parts
+						(CamelMimeMessage *message);
+CamelMimePart *	camel_mime_message_get_part_by_content_id
+						(CamelMimeMessage *message,
+						 const gchar *content_id);
+gchar *		camel_mime_message_build_mbox_from
+						(CamelMimeMessage *message);
+gboolean	camel_mime_message_has_attachment
+						(CamelMimeMessage *message);
+void		camel_mime_message_dump		(CamelMimeMessage *message,
+						 gint body);
 
 G_END_DECLS
 
diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c
index e9c7268..b9aad19 100644
--- a/camel/camel-mime-part-utils.c
+++ b/camel/camel-mime-part-utils.c
@@ -64,7 +64,7 @@ simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw,
 	GByteArray *buffer;
 	CamelStream *mem;
 	gsize len;
-	gint retval;
+	gboolean success;
 
 	d(printf ("simple_data_wrapper_construct_from_parser()\n"));
 
@@ -78,11 +78,11 @@ simple_data_wrapper_construct_from_parser (CamelDataWrapper *dw,
 	d(printf("message part kept in memory!\n"));
 
 	mem = camel_stream_mem_new_with_byte_array (buffer);
-	retval = camel_data_wrapper_construct_from_stream_sync (
+	success = camel_data_wrapper_construct_from_stream_sync (
 		dw, mem, cancellable, error);
 	g_object_unref (mem);
 
-	return (retval == 0);
+	return success;
 }
 
 /**
@@ -123,8 +123,8 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
 	case CAMEL_MIME_PARSER_STATE_MESSAGE:
 		d(printf("Creating message part\n"));
 		content = (CamelDataWrapper *) camel_mime_message_new ();
-		success = (camel_mime_part_construct_from_parser_sync (
-			(CamelMimePart *)content, mp, cancellable, error) == 0);
+		success = camel_mime_part_construct_from_parser_sync (
+			(CamelMimePart *)content, mp, cancellable, error);
 		break;
 	case CAMEL_MIME_PARSER_STATE_MULTIPART:
 		d(printf("Creating multi-part\n"));
@@ -160,6 +160,12 @@ camel_mime_part_construct_content_from_parser (CamelMimePart *dw,
 /**
  * camel_mime_message_build_preview:
  *
+ * <note>
+ *   <para>
+ *     This function blocks like crazy.
+ *   </para>
+ * </note>
+ *
  * Since: 2.28
  **/
 gboolean
@@ -186,6 +192,8 @@ camel_mime_message_build_preview (CamelMimePart *msg,
 		/*    !camel_content_type_is (dw->mime_type, "text", "html") && */
 		    !camel_content_type_is (dw->mime_type, "text", "calendar")) {
 		CamelStream *mstream, *bstream;
+
+		/* FIXME Pass a GCancellable and GError here. */
 		mstream = camel_stream_mem_new ();
 		if (camel_data_wrapper_decode_to_stream_sync (dw, mstream, NULL, NULL) > 0) {
 			gchar *line = NULL;
diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c
index e4d7025..8b5bc99 100644
--- a/camel/camel-mime-part.c
+++ b/camel/camel-mime-part.c
@@ -53,9 +53,9 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_MIME_PART, CamelMimePartPrivate))
 
-struct _CamelMimePartPrivate {
+typedef struct _AsyncContext AsyncContext;
 
-	/* TODO: these should be in a camelcontentinfo */
+struct _CamelMimePartPrivate {
 	gchar *description;
 	CamelContentDisposition *disposition;
 	gchar *content_id;
@@ -65,6 +65,11 @@ struct _CamelMimePartPrivate {
 	CamelTransferEncoding encoding;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	CamelMimeParser *parser;
+};
+
 enum {
 	PROP_0,
 	PROP_CONTENT_ID,
@@ -92,6 +97,15 @@ static GHashTable *header_formatted_table;
 
 G_DEFINE_TYPE (CamelMimePart, camel_mime_part, CAMEL_TYPE_MEDIUM)
 
+static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->parser != NULL)
+		g_object_unref (async_context->parser);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
 static gssize
 write_header (CamelStream *stream,
               const gchar *name,
@@ -671,31 +685,32 @@ mime_part_write_to_stream_sync (CamelDataWrapper *dw,
 	return total;
 }
 
-static gint
+static gboolean
 mime_part_construct_from_stream_sync (CamelDataWrapper *dw,
-                                      CamelStream *s,
+                                      CamelStream *stream,
                                       GCancellable *cancellable,
                                       GError **error)
 {
-	CamelMimeParser *mp;
-	gint ret;
+	CamelMimeParser *parser;
+	gboolean success;
 
 	d(printf("mime_part::construct_from_stream()\n"));
 
-	mp = camel_mime_parser_new ();
-	if (camel_mime_parser_init_with_stream (mp, s, error) == -1) {
-		ret = -1;
+	parser = camel_mime_parser_new ();
+	if (camel_mime_parser_init_with_stream (parser, stream, error) == -1) {
+		success = FALSE;
 	} else {
-		ret = camel_mime_part_construct_from_parser_sync (
-			CAMEL_MIME_PART (dw), mp, cancellable, error);
+		success = camel_mime_part_construct_from_parser_sync (
+			CAMEL_MIME_PART (dw), parser, cancellable, error);
 	}
-	g_object_unref (mp);
-	return ret;
+	g_object_unref (parser);
+
+	return success;
 }
 
-static gint
+static gboolean
 mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
-                                      CamelMimeParser *mp,
+                                      CamelMimeParser *parser,
                                       GCancellable *cancellable,
                                       GError **error)
 {
@@ -705,10 +720,9 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
 	gchar *buf;
 	gsize len;
 	gint err;
-	gboolean success;
-	gboolean retval = 0;
+	gboolean success = TRUE;
 
-	switch (camel_mime_parser_step (mp, &buf, &len)) {
+	switch (camel_mime_parser_step (parser, &buf, &len)) {
 	case CAMEL_MIME_PARSER_STATE_MESSAGE:
 		/* set the default type of a message always */
 		if (dw->mime_type)
@@ -717,7 +731,7 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
 	case CAMEL_MIME_PARSER_STATE_HEADER:
 	case CAMEL_MIME_PARSER_STATE_MULTIPART:
 		/* we have the headers, build them into 'us' */
-		headers = camel_mime_parser_headers_raw (mp);
+		headers = camel_mime_parser_headers_raw (parser);
 
 		/* if content-type exists, process it first, set for fallback charset in headers */
 		content = camel_header_raw_find(&headers, "content-type", NULL);
@@ -734,24 +748,89 @@ mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
 		}
 
 		success = camel_mime_part_construct_content_from_parser (
-			mime_part, mp, cancellable, error);
-		retval = success ? 0 : -1;
+			mime_part, parser, cancellable, error);
 		break;
 	default:
-		g_warning("Invalid state encountered???: %u", camel_mime_parser_state(mp));
+		g_warning("Invalid state encountered???: %u", camel_mime_parser_state(parser));
 	}
 
-	err = camel_mime_parser_errno (mp);
+	err = camel_mime_parser_errno (parser);
 	if (err != 0) {
 		errno = err;
 		g_set_error (
 			error, G_IO_ERROR,
 			g_io_error_from_errno (errno),
 			"%s", g_strerror (errno));
-		retval = -1;
+		success = FALSE;
+	}
+
+	return success;
+}
+
+static void
+mime_part_construct_from_parser_thread (GSimpleAsyncResult *simple,
+                                        GObject *object,
+                                        GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_mime_part_construct_from_parser_sync (
+		CAMEL_MIME_PART (object), async_context->parser,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
 	}
+}
+
+static void
+mime_part_construct_from_parser (CamelMimePart *mime_part,
+                                 CamelMimeParser *parser,
+                                 gint io_priority,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->parser = g_object_ref (parser);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (mime_part), callback, user_data,
+		mime_part_construct_from_parser);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, mime_part_construct_from_parser_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+mime_part_construct_from_parser_finish (CamelMimePart *mime_part,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+	GSimpleAsyncResult *simple;
 
-	return retval;
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (mime_part),
+		mime_part_construct_from_parser), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 static void
@@ -782,6 +861,8 @@ camel_mime_part_class_init (CamelMimePartClass *class)
 	data_wrapper_class->construct_from_stream_sync = mime_part_construct_from_stream_sync;
 
 	class->construct_from_parser_sync = mime_part_construct_from_parser_sync;
+	class->construct_from_parser = mime_part_construct_from_parser;
+	class->construct_from_parser_finish = mime_part_construct_from_parser_finish;
 
 	g_object_class_install_property (
 		object_class,
@@ -842,245 +923,264 @@ camel_mime_part_init (CamelMimePart *mime_part)
 	data_wrapper->mime_type = camel_content_type_new ("text", "plain");
 }
 
-/* **** Content-Description */
+/**
+ * camel_mime_part_new:
+ *
+ * Create a new MIME part.
+ *
+ * Returns: a new #CamelMimePart
+ **/
+CamelMimePart *
+camel_mime_part_new (void)
+{
+	return g_object_new (CAMEL_TYPE_MIME_PART, NULL);
+}
 
 /**
- * camel_mime_part_set_description:
- * @mime_part: a #CamelMimePart object
- * @description: description of the MIME part
+ * camel_mime_part_set_content:
+ * @mime_part: a #CamelMimePart
+ * @data: data to put into the part
+ * @length: length of @data
+ * @type: Content-Type of the data
  *
- * Set a description on the MIME part.
+ * Utility function used to set the content of a mime part object to
+ * be the provided data. If @length is 0, this routine can be used as
+ * a way to remove old content (in which case @data and @type are
+ * ignored and may be %NULL).
  **/
 void
-camel_mime_part_set_description (CamelMimePart *mime_part,
-                                 const gchar *description)
+camel_mime_part_set_content (CamelMimePart *mime_part,
+                             const gchar *data,
+                             gint length,
+                             const gchar *type) /* why on earth is the type last? */
 {
-	CamelMedium *medium;
-	gchar *text;
+	CamelMedium *medium = CAMEL_MEDIUM (mime_part);
 
-	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
-	g_return_if_fail (description != NULL);
+	if (length) {
+		CamelDataWrapper *dw;
+		CamelStream *stream;
 
-	medium = CAMEL_MEDIUM (mime_part);
+		dw = camel_data_wrapper_new ();
+		camel_data_wrapper_set_mime_type (dw, type);
+		stream = camel_stream_mem_new_with_buffer (data, length);
+		camel_data_wrapper_construct_from_stream_sync (
+			dw, stream, NULL, NULL);
+		g_object_unref (stream);
+		camel_medium_set_content (medium, dw);
+		g_object_unref (dw);
+	} else
+		camel_medium_set_content (medium, NULL);
+}
 
-	text = camel_header_encode_string ((guchar *) description);
-	camel_medium_set_header (medium, "Content-Description", text);
-	g_free (text);
+/**
+ * camel_mime_part_get_content_disposition:
+ * @mime_part: a #CamelMimePart
+ *
+ * Get the disposition of the MIME part as a structure.
+ * Returned pointer is owned by #mime_part.
+ *
+ * Returns: the disposition structure
+ *
+ * Since: 2.30
+ **/
+const CamelContentDisposition *
+camel_mime_part_get_content_disposition (CamelMimePart *mime_part)
+{
+	g_return_val_if_fail (mime_part != NULL, NULL);
 
-	g_object_notify (G_OBJECT (mime_part), "description");
+	return mime_part->priv->disposition;
 }
 
 /**
- * camel_mime_part_get_description:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_content_id:
+ * @mime_part: a #CamelMimePart
  *
- * Get the description of the MIME part.
+ * Get the content-id field of a MIME part.
  *
- * Returns: the description
+ * Returns: the content-id field of the MIME part
  **/
 const gchar *
-camel_mime_part_get_description (CamelMimePart *mime_part)
+camel_mime_part_get_content_id (CamelMimePart *mime_part)
 {
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return mime_part->priv->description;
+	return mime_part->priv->content_id;
 }
 
-/* **** Content-Disposition */
-
 /**
- * camel_mime_part_set_disposition:
- * @mime_part: a #CamelMimePart object
- * @disposition: disposition of the MIME part
+ * camel_mime_part_set_content_id:
+ * @mime_part: a #CamelMimePart
+ * @contentid: content id
  *
- * Set a disposition on the MIME part.
+ * Set the content-id field on a MIME part.
  **/
 void
-camel_mime_part_set_disposition (CamelMimePart *mime_part,
-                                 const gchar *disposition)
+camel_mime_part_set_content_id (CamelMimePart *mime_part,
+                                const gchar *contentid)
 {
 	CamelMedium *medium;
-	gchar *text;
+	gchar *cid, *id;
 
 	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 
 	medium = CAMEL_MEDIUM (mime_part);
 
-	/* we poke in a new disposition (so we dont lose 'filename', etc) */
-	if (mime_part->priv->disposition == NULL)
-		mime_part_set_disposition (mime_part, disposition);
+	if (contentid)
+		id = g_strstrip (g_strdup (contentid));
+	else
+		id = camel_header_msgid_generate ();
 
-	if (mime_part->priv->disposition != NULL) {
-		g_free (mime_part->priv->disposition->disposition);
-		mime_part->priv->disposition->disposition = g_strdup (disposition);
-	}
+	cid = g_strdup_printf ("<%s>", id);
+	camel_medium_set_header (medium, "Content-ID", cid);
+	g_free (cid);
 
-	text = camel_content_disposition_format (mime_part->priv->disposition);
-	camel_medium_set_header (medium, "Content-Disposition", text);
-	g_free (text);
+	g_free (id);
 
-	g_object_notify (G_OBJECT (mime_part), "disposition");
+	g_object_notify (G_OBJECT (mime_part), "content-id");
 }
 
 /**
- * camel_mime_part_get_disposition:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_content_location:
+ * @mime_part: a #CamelMimePart
  *
- * Get the disposition of the MIME part.
+ * Get the content-location field of a MIME part.
  *
- * Returns: the disposition
+ * Returns: the content-location field of a MIME part
  **/
 const gchar *
-camel_mime_part_get_disposition (CamelMimePart *mime_part)
+camel_mime_part_get_content_location (CamelMimePart *mime_part)
 {
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	if (mime_part->priv->disposition)
-		return mime_part->priv->disposition->disposition;
-	else
-		return NULL;
+	return mime_part->priv->content_location;
 }
 
 /**
- * camel_mime_part_get_content_disposition:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_set_content_location:
+ * @mime_part: a #CamelMimePart
+ * @location: the content-location value of the MIME part
  *
- * Get the disposition of the MIME part as a structure.
- * Returned pointer is owned by #mime_part.
+ * Set the content-location field of the MIME part.
+ **/
+void
+camel_mime_part_set_content_location (CamelMimePart *mime_part,
+                                      const gchar *location)
+{
+	CamelMedium *medium;
+
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+	medium = CAMEL_MEDIUM (mime_part);
+
+	/* FIXME: this should perform content-location folding */
+	camel_medium_set_header (medium, "Content-Location", location);
+
+	g_object_notify (G_OBJECT (mime_part), "content-location");
+}
+
+/**
+ * camel_mime_part_get_content_md5:
+ * @mime_part: a #CamelMimePart
  *
- * Returns: the disposition structure
+ * Get the content-md5 field of the MIME part.
  *
- * Since: 2.30
+ * Returns: the content-md5 field of the MIME part
  **/
-const CamelContentDisposition *
-camel_mime_part_get_content_disposition (CamelMimePart *mime_part)
+const gchar *
+camel_mime_part_get_content_md5 (CamelMimePart *mime_part)
 {
-	g_return_val_if_fail (mime_part != NULL, NULL);
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return mime_part->priv->disposition;
+	return mime_part->priv->content_md5;
 }
 
-/* **** Content-Disposition: filename="xxx" */
-
 /**
- * camel_mime_part_set_filename:
- * @mime_part: a #CamelMimePart object
- * @filename: filename given to the MIME part
+ * camel_mime_part_set_content_md5:
+ * @mime_part: a #CamelMimePart
+ * @md5sum: the md5sum of the MIME part
  *
- * Set the filename on a MIME part.
+ * Set the content-md5 field of the MIME part.
  **/
 void
-camel_mime_part_set_filename (CamelMimePart *mime_part, const gchar *filename)
+camel_mime_part_set_content_md5 (CamelMimePart *mime_part,
+                                 const gchar *content_md5)
 {
-	CamelDataWrapper *dw;
 	CamelMedium *medium;
-	gchar *str;
-
-	medium = CAMEL_MEDIUM (mime_part);
-
-	if (mime_part->priv->disposition == NULL)
-		mime_part->priv->disposition =
-			camel_content_disposition_decode("attachment");
 
-	camel_header_set_param (
-		&mime_part->priv->disposition->params, "filename", filename);
-	str = camel_content_disposition_format (mime_part->priv->disposition);
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 
-	camel_medium_set_header (medium, "Content-Disposition", str);
-	g_free (str);
+	medium = CAMEL_MEDIUM (mime_part);
 
-	dw = (CamelDataWrapper *) mime_part;
-	if (!dw->mime_type)
-		dw->mime_type = camel_content_type_new ("application", "octet-stream");
-	camel_content_type_set_param (dw->mime_type, "name", filename);
-	str = camel_content_type_format (dw->mime_type);
-	camel_medium_set_header (medium, "Content-Type", str);
-	g_free (str);
+	camel_medium_set_header (medium, "Content-MD5", content_md5);
 }
 
 /**
- * camel_mime_part_get_filename:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_content_languages:
+ * @mime_part: a #CamelMimePart
  *
- * Get the filename of a MIME part.
+ * Get the Content-Languages set on the MIME part.
  *
- * Returns: the filename of the MIME part
+ * Returns: a #GList of languages
  **/
-const gchar *
-camel_mime_part_get_filename (CamelMimePart *mime_part)
+const GList *
+camel_mime_part_get_content_languages (CamelMimePart *mime_part)
 {
-	if (mime_part->priv->disposition) {
-		const gchar *name = camel_header_param (
-			mime_part->priv->disposition->params, "filename");
-		if (name)
-			return name;
-	}
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return camel_content_type_param (((CamelDataWrapper *) mime_part)->mime_type, "name");
+	return mime_part->priv->content_languages;
 }
 
-/* **** Content-ID: */
-
 /**
- * camel_mime_part_set_content_id:
- * @mime_part: a #CamelMimePart object
- * @contentid: content id
+ * camel_mime_part_set_content_languages:
+ * @mime_part: a #CamelMimePart
+ * @content_languages: list of languages
  *
- * Set the content-id field on a MIME part.
+ * Set the Content-Languages field of a MIME part.
  **/
 void
-camel_mime_part_set_content_id (CamelMimePart *mime_part,
-                                const gchar *contentid)
+camel_mime_part_set_content_languages (CamelMimePart *mime_part,
+                                       GList *content_languages)
 {
-	CamelMedium *medium;
-	gchar *cid, *id;
-
 	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 
-	medium = CAMEL_MEDIUM (mime_part);
-
-	if (contentid)
-		id = g_strstrip (g_strdup (contentid));
-	else
-		id = camel_header_msgid_generate ();
-
-	cid = g_strdup_printf ("<%s>", id);
-	camel_medium_set_header (medium, "Content-ID", cid);
-	g_free (cid);
+	if (mime_part->priv->content_languages)
+		camel_string_list_free (mime_part->priv->content_languages);
 
-	g_free (id);
+	mime_part->priv->content_languages = content_languages;
 
-	g_object_notify (G_OBJECT (mime_part), "content-id");
+	/* FIXME: translate to a header and set it */
 }
 
 /**
- * camel_mime_part_get_content_id:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_content_type:
+ * @mime_part: a #CamelMimePart
  *
- * Get the content-id field of a MIME part.
+ * Get the Content-Type of a MIME part.
  *
- * Returns: the content-id field of the MIME part
+ * Returns: the parsed #CamelContentType of the MIME part
  **/
-const gchar *
-camel_mime_part_get_content_id (CamelMimePart *mime_part)
+CamelContentType *
+camel_mime_part_get_content_type (CamelMimePart *mime_part)
 {
+	CamelDataWrapper *data_wrapper;
+
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return mime_part->priv->content_id;
-}
+	data_wrapper = CAMEL_DATA_WRAPPER (mime_part);
 
-/* **** Content-MD5: */
+	return camel_data_wrapper_get_mime_type_field (data_wrapper);
+}
 
 /**
- * camel_mime_part_set_content_md5:
- * @mime_part: a #CamelMimePart object
- * @md5sum: the md5sum of the MIME part
+ * camel_mime_part_set_content_type:
+ * @mime_part: a #CamelMimePart
+ * @content_type: content-type string
  *
- * Set the content-md5 field of the MIME part.
+ * Set the content-type on a MIME part.
  **/
 void
-camel_mime_part_set_content_md5 (CamelMimePart *mime_part,
-                                 const gchar *content_md5)
+camel_mime_part_set_content_type (CamelMimePart *mime_part,
+                                  const gchar *content_type)
 {
 	CamelMedium *medium;
 
@@ -1088,93 +1188,107 @@ camel_mime_part_set_content_md5 (CamelMimePart *mime_part,
 
 	medium = CAMEL_MEDIUM (mime_part);
 
-	camel_medium_set_header (medium, "Content-MD5", content_md5);
+	camel_medium_set_header (medium, "Content-Type", content_type);
 }
 
 /**
- * camel_mime_part_get_content_md5:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_description:
+ * @mime_part: a #CamelMimePart
  *
- * Get the content-md5 field of the MIME part.
+ * Get the description of the MIME part.
  *
- * Returns: the content-md5 field of the MIME part
+ * Returns: the description
  **/
 const gchar *
-camel_mime_part_get_content_md5 (CamelMimePart *mime_part)
+camel_mime_part_get_description (CamelMimePart *mime_part)
 {
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return mime_part->priv->content_md5;
+	return mime_part->priv->description;
 }
 
-/* **** Content-Location: */
-
 /**
- * camel_mime_part_set_content_location:
- * @mime_part: a #CamelMimePart object
- * @location: the content-location value of the MIME part
+ * camel_mime_part_set_description:
+ * @mime_part: a #CamelMimePart
+ * @description: description of the MIME part
  *
- * Set the content-location field of the MIME part.
+ * Set a description on the MIME part.
  **/
 void
-camel_mime_part_set_content_location (CamelMimePart *mime_part,
-                                      const gchar *location)
+camel_mime_part_set_description (CamelMimePart *mime_part,
+                                 const gchar *description)
 {
 	CamelMedium *medium;
+	gchar *text;
 
 	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+	g_return_if_fail (description != NULL);
 
 	medium = CAMEL_MEDIUM (mime_part);
 
-	/* FIXME: this should perform content-location folding */
-	camel_medium_set_header (medium, "Content-Location", location);
+	text = camel_header_encode_string ((guchar *) description);
+	camel_medium_set_header (medium, "Content-Description", text);
+	g_free (text);
 
-	g_object_notify (G_OBJECT (mime_part), "content-location");
+	g_object_notify (G_OBJECT (mime_part), "description");
 }
 
 /**
- * camel_mime_part_get_content_location:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_disposition:
+ * @mime_part: a #CamelMimePart
  *
- * Get the content-location field of a MIME part.
+ * Get the disposition of the MIME part.
  *
- * Returns: the content-location field of a MIME part
+ * Returns: the disposition
  **/
 const gchar *
-camel_mime_part_get_content_location (CamelMimePart *mime_part)
+camel_mime_part_get_disposition (CamelMimePart *mime_part)
 {
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
 
-	return mime_part->priv->content_location;
+	if (mime_part->priv->disposition)
+		return mime_part->priv->disposition->disposition;
+	else
+		return NULL;
 }
 
-/* **** Content-Transfer-Encoding: */
-
 /**
- * camel_mime_part_set_encoding:
- * @mime_part: a #CamelMimePart object
- * @encoding: a #CamelTransferEncoding
+ * camel_mime_part_set_disposition:
+ * @mime_part: a #CamelMimePart
+ * @disposition: disposition of the MIME part
  *
- * Set the Content-Transfer-Encoding to use on a MIME part.
+ * Set a disposition on the MIME part.
  **/
 void
-camel_mime_part_set_encoding (CamelMimePart *mime_part,
-                              CamelTransferEncoding encoding)
+camel_mime_part_set_disposition (CamelMimePart *mime_part,
+                                 const gchar *disposition)
 {
 	CamelMedium *medium;
-	const gchar *text;
+	gchar *text;
 
 	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 
 	medium = CAMEL_MEDIUM (mime_part);
 
-	text = camel_transfer_encoding_to_string (encoding);
-	camel_medium_set_header (medium, "Content-Transfer-Encoding", text);
+	/* we poke in a new disposition (so we dont lose 'filename', etc) */
+	if (mime_part->priv->disposition == NULL)
+		mime_part_set_disposition (mime_part, disposition);
+
+	if (mime_part->priv->disposition != NULL) {
+		g_free (mime_part->priv->disposition->disposition);
+		mime_part->priv->disposition->disposition = g_strdup (disposition);
+	}
+
+	text = camel_content_disposition_format (mime_part->priv->disposition);
+	camel_medium_set_header (medium, "Content-Disposition", text);
+	g_free (text);
+
+	g_object_notify (G_OBJECT (mime_part), "disposition");
 }
 
 /**
  * camel_mime_part_get_encoding:
- * @mime_part: a #CamelMimePart object
+ * @mime_part: a #CamelMimePart
  *
  * Get the Content-Transfer-Encoding of a MIME part.
  *
@@ -1190,193 +1304,185 @@ camel_mime_part_get_encoding (CamelMimePart *mime_part)
 	return mime_part->priv->encoding;
 }
 
-/* FIXME: do something with this stuff ... */
-
 /**
- * camel_mime_part_set_content_languages:
- * @mime_part: a #CamelMimePart object
- * @content_languages: list of languages
+ * camel_mime_part_set_encoding:
+ * @mime_part: a #CamelMimePart
+ * @encoding: a #CamelTransferEncoding
  *
- * Set the Content-Languages field of a MIME part.
+ * Set the Content-Transfer-Encoding to use on a MIME part.
  **/
 void
-camel_mime_part_set_content_languages (CamelMimePart *mime_part,
-                                       GList *content_languages)
+camel_mime_part_set_encoding (CamelMimePart *mime_part,
+                              CamelTransferEncoding encoding)
 {
-	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+	CamelMedium *medium;
+	const gchar *text;
 
-	if (mime_part->priv->content_languages)
-		camel_string_list_free (mime_part->priv->content_languages);
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
 
-	mime_part->priv->content_languages = content_languages;
+	medium = CAMEL_MEDIUM (mime_part);
 
-	/* FIXME: translate to a header and set it */
+	text = camel_transfer_encoding_to_string (encoding);
+	camel_medium_set_header (medium, "Content-Transfer-Encoding", text);
 }
 
 /**
- * camel_mime_part_get_content_languages:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_get_filename:
+ * @mime_part: a #CamelMimePart
  *
- * Get the Content-Languages set on the MIME part.
+ * Get the filename of a MIME part.
  *
- * Returns: a #GList of languages
+ * Returns: the filename of the MIME part
  **/
-const GList *
-camel_mime_part_get_content_languages (CamelMimePart *mime_part)
+const gchar *
+camel_mime_part_get_filename (CamelMimePart *mime_part)
 {
-	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
+	if (mime_part->priv->disposition) {
+		const gchar *name = camel_header_param (
+			mime_part->priv->disposition->params, "filename");
+		if (name)
+			return name;
+	}
 
-	return mime_part->priv->content_languages;
+	return camel_content_type_param (
+		((CamelDataWrapper *) mime_part)->mime_type, "name");
 }
 
-/* **** */
-
-/* **** Content-Type: */
-
 /**
- * camel_mime_part_set_content_type:
- * @mime_part: a #CamelMimePart object
- * @content_type: content-type string
+ * camel_mime_part_set_filename:
+ * @mime_part: a #CamelMimePart
+ * @filename: filename given to the MIME part
  *
- * Set the content-type on a MIME part.
+ * Set the filename on a MIME part.
  **/
 void
-camel_mime_part_set_content_type (CamelMimePart *mime_part,
-                                  const gchar *content_type)
+camel_mime_part_set_filename (CamelMimePart *mime_part,
+                              const gchar *filename)
 {
+	CamelDataWrapper *dw;
 	CamelMedium *medium;
-
-	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+	gchar *str;
 
 	medium = CAMEL_MEDIUM (mime_part);
 
-	camel_medium_set_header (medium, "Content-Type", content_type);
-}
+	if (mime_part->priv->disposition == NULL)
+		mime_part->priv->disposition =
+			camel_content_disposition_decode("attachment");
 
-/**
- * camel_mime_part_get_content_type:
- * @mime_part: a #CamelMimePart object
- *
- * Get the Content-Type of a MIME part.
- *
- * Returns: the parsed #CamelContentType of the MIME part
- **/
-CamelContentType *
-camel_mime_part_get_content_type (CamelMimePart *mime_part)
-{
-	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL);
+	camel_header_set_param (
+		&mime_part->priv->disposition->params, "filename", filename);
+	str = camel_content_disposition_format (mime_part->priv->disposition);
+
+	camel_medium_set_header (medium, "Content-Disposition", str);
+	g_free (str);
 
-	return camel_data_wrapper_get_mime_type_field ((CamelDataWrapper *) mime_part);
+	dw = (CamelDataWrapper *) mime_part;
+	if (!dw->mime_type)
+		dw->mime_type = camel_content_type_new ("application", "octet-stream");
+	camel_content_type_set_param (dw->mime_type, "name", filename);
+	str = camel_content_type_format (dw->mime_type);
+	camel_medium_set_header (medium, "Content-Type", str);
+	g_free (str);
 }
 
 /**
  * camel_mime_part_construct_from_parser_sync:
- * @mime_part: a #CamelMimePart object
- * @parser: a #CamelMimeParser object
+ * @mime_part: a #CamelMimePart
+ * @parser: a #CamelMimeParser
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Constructs a MIME part from a parser.
  *
- * Returns: %0 on success or %-1 on fail
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-gint
+gboolean
 camel_mime_part_construct_from_parser_sync (CamelMimePart *mime_part,
-                                            CamelMimeParser *mp,
+                                            CamelMimeParser *parser,
                                             GCancellable *cancellable,
                                             GError **error)
 {
 	CamelMimePartClass *class;
-	gint retval;
+	gboolean success;
 
 	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), -1);
-	g_return_val_if_fail (CAMEL_IS_MIME_PARSER (mp), -1);
+	g_return_val_if_fail (CAMEL_IS_MIME_PARSER (parser), -1);
 
 	class = CAMEL_MIME_PART_GET_CLASS (mime_part);
 	g_return_val_if_fail (class->construct_from_parser_sync != NULL, -1);
 
-	retval = class->construct_from_parser_sync (
-		mime_part, mp, cancellable, error);
+	success = class->construct_from_parser_sync (
+		mime_part, parser, cancellable, error);
 	CAMEL_CHECK_GERROR (
-		mime_part, construct_from_parser_sync, retval == 0, error);
+		mime_part, construct_from_parser_sync, success, error);
 
-	return retval;
+	return success;
 }
 
 /**
- * camel_mime_part_new:
+ * camel_mime_part_construct_from_parser:
+ * @mime_part: a #CamelMimePart
+ * @parser: a #CamelMimeParser
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
  *
- * Create a new MIME part.
+ * Asynchronously constructs a MIME part from a parser.
  *
- * Returns: a new #CamelMimePart object
- **/
-CamelMimePart *
-camel_mime_part_new (void)
-{
-	return g_object_new (CAMEL_TYPE_MIME_PART, NULL);
-}
-
-/**
- * camel_mime_part_set_content:
- * @mime_part: a #CamelMimePart object
- * @data: data to put into the part
- * @length: length of @data
- * @type: Content-Type of the data
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_mime_part_construct_from_parser_finish() to get the result of
+ * the operation.
  *
- * Utility function used to set the content of a mime part object to
- * be the provided data. If @length is 0, this routine can be used as
- * a way to remove old content (in which case @data and @type are
- * ignored and may be %NULL).
+ * Since: 2.34
  **/
 void
-camel_mime_part_set_content (CamelMimePart *mime_part,
-			     const gchar *data, gint length,
-			     const gchar *type) /* why on earth is the type last? */
+camel_mime_part_construct_from_parser (CamelMimePart *mime_part,
+                                       CamelMimeParser *parser,
+                                       gint io_priority,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
 {
-	CamelMedium *medium = CAMEL_MEDIUM (mime_part);
+	CamelMimePartClass *class;
 
-	if (length) {
-		CamelDataWrapper *dw;
-		CamelStream *stream;
+	g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+	g_return_if_fail (CAMEL_IS_MIME_PARSER (parser));
 
-		dw = camel_data_wrapper_new ();
-		camel_data_wrapper_set_mime_type (dw, type);
-		stream = camel_stream_mem_new_with_buffer (data, length);
-		camel_data_wrapper_construct_from_stream_sync (
-			dw, stream, NULL, NULL);
-		g_object_unref (stream);
-		camel_medium_set_content (medium, dw);
-		g_object_unref (dw);
-	} else
-		camel_medium_set_content (medium, NULL);
+	class = CAMEL_MIME_PART_GET_CLASS (mime_part);
+	g_return_if_fail (class->construct_from_parser != NULL);
+
+	class->construct_from_parser (
+		mime_part, parser, io_priority,
+		cancellable, callback, user_data);
 }
 
 /**
- * camel_mime_part_get_content_size:
- * @mime_part: a #CamelMimePart object
+ * camel_mime_part_construct_from_parser_finish:
+ * @mime_part: a #CamelMimePart
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
  *
- * Get the decoded size of the MIME part's content.
+ * Finishes the operation started with camel_mime_part_construct_from_parser().
  *
- * Returns: the size of the MIME part's content in bytes.
+ * Returns: %TRUE on success, %FALSE on error
  *
- * Since: 2.22
+ * Since: 2.34
  **/
-gsize
-camel_mime_part_get_content_size (CamelMimePart *mime_part)
+gboolean
+camel_mime_part_construct_from_parser_finish (CamelMimePart *mime_part,
+                                              GAsyncResult *result,
+                                              GError **error)
 {
-	CamelStream *null;
-	CamelDataWrapper *dw;
-	gsize size;
-
-	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), 0);
-
-	dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+	CamelMimePartClass *class;
 
-	null = camel_stream_null_new ();
-	camel_data_wrapper_decode_to_stream_sync (dw, null, NULL, NULL);
-	size = CAMEL_STREAM_NULL (null)->written;
+	g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
 
-	g_object_unref (null);
+	class = CAMEL_MIME_PART_GET_CLASS (mime_part);
+	g_return_val_if_fail (class->construct_from_parser_finish != NULL, FALSE);
 
-	return size;
+	return class->construct_from_parser_finish (mime_part, result, error);
 }
diff --git a/camel/camel-mime-part.h b/camel/camel-mime-part.h
index 748a31b..89b0dc1 100644
--- a/camel/camel-mime-part.h
+++ b/camel/camel-mime-part.h
@@ -69,10 +69,25 @@ struct _CamelMimePart {
 struct _CamelMimePartClass {
 	CamelMediumClass parent_class;
 
-	gint	(*construct_from_parser_sync)	(CamelMimePart *mime_part,
+	/* Synchronous I/O Methods */
+	gboolean	(*construct_from_parser_sync)
+						(CamelMimePart *mime_part,
 						 CamelMimeParser *parser,
 						 GCancellable *cancellable,
 						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*construct_from_parser)
+						(CamelMimePart *mime_part,
+						 CamelMimeParser *parser,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*construct_from_parser_finish)
+						(CamelMimePart *mime_part,
+						 GAsyncResult *result,
+						 GError **error);
 };
 
 GType		camel_mime_part_get_type	(void);
@@ -119,13 +134,23 @@ void		camel_mime_part_set_content	(CamelMimePart *mime_part,
 						 const gchar *data,
 						 gint length,
 						 const gchar *type);
-gsize		camel_mime_part_get_content_size
-						(CamelMimePart *mime_part);
-gint		camel_mime_part_construct_from_parser_sync
+
+gboolean	camel_mime_part_construct_from_parser_sync
 						(CamelMimePart *mime_part,
 						 CamelMimeParser *parser,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_mime_part_construct_from_parser
+						(CamelMimePart *mime_part,
+						 CamelMimeParser *parser,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_mime_part_construct_from_parser_finish
+						(CamelMimePart *mime_part,
+						 GAsyncResult *result,
+						 GError **error);
 
 G_END_DECLS
 
diff --git a/camel/camel-multipart-signed.c b/camel/camel-multipart-signed.c
index 21968fb..1affe87 100644
--- a/camel/camel-multipart-signed.c
+++ b/camel/camel-multipart-signed.c
@@ -359,7 +359,7 @@ file_error:
 	return -1;
 }
 
-static gint
+static gboolean
 multipart_signed_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
                                              CamelStream *stream,
                                              GCancellable *cancellable,
@@ -370,11 +370,11 @@ multipart_signed_construct_from_stream_sync (CamelDataWrapper *data_wrapper,
 
 	if (camel_stream_write_to_stream (
 		stream, mem, cancellable, error) == -1)
-		return -1;
+		return FALSE;
 
 	multipart_signed_set_stream (mps, mem);
 
-	return 0;
+	return TRUE;
 }
 
 static void
diff --git a/camel/camel-net-utils.c b/camel/camel-net-utils.c
index 6769285..13d3b97 100644
--- a/camel/camel-net-utils.c
+++ b/camel/camel-net-utils.c
@@ -691,7 +691,7 @@ camel_getaddrinfo (const gchar *name,
 	if (g_cancellable_set_error_if_cancelled (cancellable, error))
 		return NULL;
 
-	camel_operation_start_transient (
+	camel_operation_push_message (
 		cancellable, _("Resolving: %s"), name);
 
 	/* force ipv4 addresses only */
@@ -729,7 +729,7 @@ camel_getaddrinfo (const gchar *name,
 
 	cs_freeinfo (msg);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return res;
 }
@@ -841,7 +841,7 @@ camel_getnameinfo (const struct sockaddr *sa,
 	if (g_cancellable_set_error_if_cancelled (cancellable, error))
 		return -1;
 
-	camel_operation_start_transient (
+	camel_operation_push_message (
 		cancellable, _("Resolving address"));
 
 	msg = g_malloc0 (sizeof (*msg));
@@ -879,7 +879,7 @@ camel_getnameinfo (const struct sockaddr *sa,
 
 	cs_freeinfo (msg);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return result;
 }
diff --git a/camel/camel-offline-folder.c b/camel/camel-offline-folder.c
index 73338f6..7e755d2 100644
--- a/camel/camel-offline-folder.c
+++ b/camel/camel-offline-folder.c
@@ -37,10 +37,17 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_OFFLINE_FOLDER, CamelOfflineFolderPrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelOfflineFolderPrivate {
 	gboolean offline_sync;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	gchar *expression;
+};
+
 struct _offline_downsync_msg {
 	CamelSessionThreadMsg msg;
 
@@ -58,12 +65,20 @@ enum {
 G_DEFINE_TYPE (CamelOfflineFolder, camel_offline_folder, CAMEL_TYPE_FOLDER)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	g_free (async_context->expression);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm)
 {
 	struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm;
 	gint i;
 
-	camel_operation_start (
+	camel_operation_push_message (
 		mm->cancellable,
 		_("Downloading new messages for offline mode"));
 
@@ -84,7 +99,7 @@ offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm)
 			"(match-all)", NULL, &mm->error);
 	}
 
-	camel_operation_end (mm->cancellable);
+	camel_operation_pop_message (mm->cancellable);
 }
 
 static void
@@ -174,7 +189,7 @@ offline_folder_downsync_sync (CamelOfflineFolder *offline,
 	GPtrArray *uids, *uncached_uids = NULL;
 	gint i;
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable, _("Syncing messages in folder '%s' to disk"),
 		camel_folder_get_full_name (folder));
 
@@ -207,12 +222,77 @@ done:
 	if (uncached_uids)
 		camel_folder_free_uids (folder, uncached_uids);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return TRUE;
 }
 
 static void
+offline_folder_downsync_thread (GSimpleAsyncResult *simple,
+                                GObject *object,
+                                GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_offline_folder_downsync_sync (
+		CAMEL_OFFLINE_FOLDER (object), async_context->expression,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+offline_folder_downsync (CamelOfflineFolder *folder,
+                         const gchar *expression,
+                         gint io_priority,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->expression = g_strdup (expression);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (folder), callback,
+		user_data, offline_folder_downsync);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, offline_folder_downsync_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+offline_folder_downsync_finish (CamelOfflineFolder *folder,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (folder), offline_folder_downsync), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
 camel_offline_folder_class_init (CamelOfflineFolderClass *class)
 {
 	GObjectClass *object_class;
@@ -224,6 +304,8 @@ camel_offline_folder_class_init (CamelOfflineFolderClass *class)
 	object_class->get_property = offline_folder_get_property;
 
 	class->downsync_sync = offline_folder_downsync_sync;
+	class->downsync = offline_folder_downsync;
+	class->downsync_finish = offline_folder_downsync_finish;
 
 	g_object_class_install_property (
 		object_class,
@@ -249,51 +331,53 @@ camel_offline_folder_init (CamelOfflineFolder *folder)
 
 /**
  * camel_offline_folder_get_offline_sync:
- * @offline_folder: a #CamelOfflineFolder
+ * @folder: a #CamelOfflineFolder
  *
  * Since: 2.32
  **/
 gboolean
-camel_offline_folder_get_offline_sync (CamelOfflineFolder *offline_folder)
+camel_offline_folder_get_offline_sync (CamelOfflineFolder *folder)
 {
-	g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder), FALSE);
+	g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
 
-	return offline_folder->priv->offline_sync;
+	return folder->priv->offline_sync;
 }
 
 /**
  * camel_offline_folder_set_offline_sync:
- * @offline_folder: a #CamelOfflineFolder
+ * @folder: a #CamelOfflineFolder
  * @offline_sync: whether to synchronize for offline use
  *
  * Since: 2.32
  **/
 void
-camel_offline_folder_set_offline_sync (CamelOfflineFolder *offline_folder,
+camel_offline_folder_set_offline_sync (CamelOfflineFolder *folder,
                                        gboolean offline_sync)
 {
-	g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder));
+	g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
 
-	offline_folder->priv->offline_sync = offline_sync;
+	folder->priv->offline_sync = offline_sync;
 
-	g_object_notify (G_OBJECT (offline_folder), "offline-sync");
+	g_object_notify (G_OBJECT (folder), "offline-sync");
 }
 
 /**
  * camel_offline_folder_downsync_sync:
- * @offline: a #CamelOfflineFolder object
+ * @folder: a #CamelOfflineFolder
  * @expression: search expression describing which set of messages
  *              to downsync (%NULL for all)
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Syncs messages in @offline described by the search @expression to
+ * Synchronizes messages in @folder described by the search @expression to
  * the local machine for offline availability.
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
 gboolean
-camel_offline_folder_downsync_sync (CamelOfflineFolder *offline,
+camel_offline_folder_downsync_sync (CamelOfflineFolder *folder,
                                     const gchar *expression,
                                     GCancellable *cancellable,
                                     GError **error)
@@ -301,14 +385,81 @@ camel_offline_folder_downsync_sync (CamelOfflineFolder *offline,
 	CamelOfflineFolderClass *class;
 	gboolean success;
 
-	g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline), FALSE);
+	g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
 
-	class = CAMEL_OFFLINE_FOLDER_GET_CLASS (offline);
+	class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
 	g_return_val_if_fail (class->downsync_sync != NULL, FALSE);
 
 	success = class->downsync_sync (
-		offline, expression, cancellable, error);
-	CAMEL_CHECK_GERROR (offline, downsync_sync, success, error);
+		folder, expression, cancellable, error);
+	CAMEL_CHECK_GERROR (folder, downsync_sync, success, error);
 
 	return success;
 }
+
+/**
+ * camel_offline_folder_downsync:
+ * @folder: a #CamelOfflineFolder
+ * @expression: search expression describing which set of messages
+ *              to downsync (%NULL for all)
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULl
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Synchronizes messages in @folder described by the search @expression to
+ * the local machine asynchronously for offline availability.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_offline_folder_downsync_finish() to get the result of the
+ * operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_offline_folder_downsync (CamelOfflineFolder *folder,
+                               const gchar *expression,
+                               gint io_priority,
+                               GCancellable *cancellable,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
+{
+	CamelOfflineFolderClass *class;
+
+	g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
+
+	class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
+	g_return_if_fail (class->downsync != NULL);
+
+	class->downsync (
+		folder, expression, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_offline_folder_downsync_finish:
+ * @folder: a #CamelOfflineFolder
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_offline_folder_downsync().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_offline_folder_downsync_finish (CamelOfflineFolder *folder,
+                                      GAsyncResult *result,
+                                      GError **error)
+{
+	CamelOfflineFolderClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
+	g_return_val_if_fail (class->downsync_finish != NULL, FALSE);
+
+	return class->downsync_finish (folder, result, error);
+}
diff --git a/camel/camel-offline-folder.h b/camel/camel-offline-folder.h
index d3ca48c..977e769 100644
--- a/camel/camel-offline-folder.h
+++ b/camel/camel-offline-folder.h
@@ -62,22 +62,45 @@ struct _CamelOfflineFolder {
 struct _CamelOfflineFolderClass {
 	CamelFolderClass parent_class;
 
+	/* Synchronous I/O Methods */
 	gboolean	(*downsync_sync)	(CamelOfflineFolder *folder,
 						 const gchar *expression,
 						 GCancellable *cancellable,
 						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*downsync)		(CamelOfflineFolder *folder,
+						 const gchar *expression,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*downsync_finish)	(CamelOfflineFolder *folder,
+						 GAsyncResult *result,
+						 GError **error);
 };
 
 GType		camel_offline_folder_get_type	(void);
 gboolean	camel_offline_folder_get_offline_sync
-						(CamelOfflineFolder *offline);
+						(CamelOfflineFolder *folder);
 void		camel_offline_folder_set_offline_sync
-						(CamelOfflineFolder *offline,
+						(CamelOfflineFolder *folder,
 						 gboolean offline_sync);
+
 gboolean	camel_offline_folder_downsync_sync
-						(CamelOfflineFolder *offline,
+						(CamelOfflineFolder *folder,
+						 const gchar *expression,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_offline_folder_downsync	(CamelOfflineFolder *folder,
 						 const gchar *expression,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_offline_folder_downsync_finish
+						(CamelOfflineFolder *folder,
+						 GAsyncResult *result,
 						 GError **error);
 
 G_END_DECLS
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 82c6989..f00c92b 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -38,20 +38,13 @@
 typedef struct _StatusNode StatusNode;
 
 struct _StatusNode {
-	gboolean transient;
-	gchar *msg;
-	gint pc;		/* last percentage reported */
-	guint stamp;		/* last time stamp reported */
+	CamelOperation *operation;
+	guint source_id;  /* for timeout or idle */
+	gchar *message;
+	gint percent;
 };
 
 struct _CamelOperationPrivate {
-	guint status_idle_id;
-
-	/* For the next 'status' signal. */
-	gchar *status_msg;
-	gint status_pc;
-
-	guint status_update;
 
 	GQueue status_stack;
 
@@ -66,9 +59,6 @@ enum {
 	LAST_SIGNAL
 };
 
-/* Delay before a transient operation has any effect on the status */
-#define CAMEL_OPERATION_TRANSIENT_DELAY (5)
-
 static GStaticRecMutex operation_lock = G_STATIC_REC_MUTEX_INIT;
 #define LOCK() g_static_rec_mutex_lock (&operation_lock)
 #define UNLOCK() g_static_rec_mutex_unlock (&operation_lock)
@@ -79,85 +69,56 @@ static guint signals[LAST_SIGNAL];
 
 G_DEFINE_TYPE (CamelOperation, camel_operation, G_TYPE_CANCELLABLE)
 
-static StatusNode *
-status_node_new (CamelOperation *operation)
-{
-	StatusNode *node;
-
-	node = g_slice_new0 (StatusNode);
-	g_queue_push_head (&operation->priv->status_stack, node);
-
-	return node;
-}
-
 static void
 status_node_free (StatusNode *node)
 {
-	g_free (node->msg);
-	g_slice_free (StatusNode, node);
-}
+	g_free (node->message);
 
-static guint
-stamp (void)
-{
-	GTimeVal tv;
+	if (node->source_id > 0)
+		g_source_remove (node->source_id);
 
-	g_get_current_time (&tv);
-	/* update 4 times/second */
-	return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
+	g_slice_free (StatusNode, node);
 }
 
 static gboolean
-operation_idle_cb (CamelOperation *operation)
+operation_emit_status_cb (StatusNode *node)
 {
-	gchar *msg;
-	gint pc;
+	StatusNode *head_node;
+	gchar *message = NULL;
+	gint percent = 0;
 
 	/* Keep the operation alive until we emit the signal,
 	 * otherwise it might be finalized between unlocking
 	 * the mutex and emitting the signal. */
-	g_object_ref (operation);
+	g_object_ref (node->operation);
 
 	LOCK ();
 
-	msg = operation->priv->status_msg;
-	operation->priv->status_msg = NULL;
+	node->source_id = 0;
 
-	pc = operation->priv->status_pc;
+	head_node = g_queue_peek_head (&node->operation->priv->status_stack);
 
-	operation->priv->status_idle_id = 0;
+	if (node == head_node) {
+		message = g_strdup (node->message);
+		percent = node->percent;
+	}
 
 	UNLOCK ();
 
-	if (msg != NULL) {
-		g_signal_emit (operation, signals[STATUS], 0, msg, pc);
-		g_free (msg);
+	if (message != NULL) {
+		g_signal_emit (
+			node->operation,
+			signals[STATUS], 0,
+			message, percent);
+		g_free (message);
 	}
 
-	g_object_unref (operation);
+	g_object_unref (node->operation);
 
 	return FALSE;
 }
 
 static void
-operation_queue_status_update (CamelOperation *operation,
-                               StatusNode *node)
-{
-	LOCK ();
-
-	if (operation->priv->status_idle_id == 0)
-		operation->priv->status_idle_id = g_idle_add (
-			(GSourceFunc) operation_idle_cb, operation);
-
-	g_free (operation->priv->status_msg);
-	operation->priv->status_msg = g_strdup (node->msg);
-
-	operation->priv->status_pc = node->pc;
-
-	UNLOCK ();
-}
-
-static void
 operation_flush_msgport (CamelOperation *operation)
 {
 	CamelOperationPrivate *priv = operation->priv;
@@ -183,16 +144,13 @@ operation_finalize (GObject *object)
 
 	g_queue_remove (&operation_list, object);
 
-	if (priv->status_idle_id > 0)
-		g_source_remove (priv->status_idle_id);
-
 	operation_flush_msgport (CAMEL_OPERATION (object));
 	camel_msgport_destroy (priv->cancel_port);
 
 	while ((node = g_queue_pop_head (&priv->status_stack)) != NULL) {
 		g_warning (
 			"CamelOperation status stack non-empty: %s",
-			node->msg);
+			node->message);
 		status_node_free (node);
 	}
 
@@ -398,24 +356,24 @@ camel_operation_cancel_prfd (CamelOperation *operation)
 #endif /* CAMEL_HAVE_NSS */
 
 /**
- * camel_operation_start:
+ * camel_operation_push_message:
  * @cancellable: a #GCancellable or %NULL
- * @what: action being performed (printf-style format string)
- * @Varargs: varargs
+ * @format: a standard printf() format string
+ * @Varargs: the parameters to insert into the format string
  *
- * Report the start of an operation.  All start operations should have
- * similar end operations.
+ * Call this function to describe an operation being performed.
+ * Call camel_operation_progress() to report progress on the operation.
+ * Call camel_operation_pop_message() when the operation is complete.
  *
  * This function only works if @cancellable is a #CamelOperation cast as a
  * #GCancellable.  If @cancellable is a plain #GCancellable or %NULL, the
  * function does nothing and returns silently.
  **/
 void
-camel_operation_start (GCancellable *cancellable,
-                       const gchar *what, ...)
+camel_operation_push_message (GCancellable *cancellable,
+                              const gchar *format, ...)
 {
 	CamelOperation *operation;
-	const guint signal_id = signals[STATUS];
 	StatusNode *node;
 	va_list ap;
 
@@ -427,48 +385,45 @@ camel_operation_start (GCancellable *cancellable,
 
 	g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
 
-	if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE))
-		return;
-
 	LOCK ();
 
 	operation = CAMEL_OPERATION (cancellable);
 
-	operation->priv->status_update = 0;
+	va_start (ap, format);
 
-	va_start (ap, what);
+	node = g_slice_new0 (StatusNode);
+	node->message = g_strdup_vprintf (format, ap);
+	node->operation = operation;  /* not referenced */
 
-	node = status_node_new (operation);
-	node->msg = g_strdup_vprintf (what, ap);
+	if (g_queue_is_empty (&operation->priv->status_stack))
+		node->source_id = g_idle_add (
+			(GSourceFunc) operation_emit_status_cb, node);
+	else
+		node->source_id = g_timeout_add_seconds (
+			4, (GSourceFunc) operation_emit_status_cb, node);
 
-	va_end (ap);
+	g_queue_push_head (&operation->priv->status_stack, node);
 
-	operation_queue_status_update (operation, node);
+	va_end (ap);
 
 	UNLOCK ();
 }
 
 /**
- * camel_operation_start_transient:
- * @cancellable: a #GCancellable or %NULL
- * @what: printf-style format string describing the action being performed
- * @Varargs: varargs
+ * camel_operation_pop_message:
+ * @cancellable: a #GCancellable
  *
- * Start a transient event.  We only update this to the display if it
- * takes very long to process, and if we do, we then go back to the
- * previous state when finished.
+ * Pops the most recently pushed message.
  *
  * This function only works if @cancellable is a #CamelOperation cast as a
  * #GCancellable.  If @cancellable is a plain #GCancellable or %NULL, the
  * function does nothing and returns silently.
  **/
 void
-camel_operation_start_transient (GCancellable *cancellable,
-                                 const gchar *what, ...)
+camel_operation_pop_message (GCancellable *cancellable)
 {
 	CamelOperation *operation;
 	StatusNode *node;
-	va_list ap;
 
 	if (cancellable == NULL)
 		return;
@@ -481,17 +436,16 @@ camel_operation_start_transient (GCancellable *cancellable,
 	LOCK ();
 
 	operation = CAMEL_OPERATION (cancellable);
+	node = g_queue_pop_head (&operation->priv->status_stack);
 
-	operation->priv->status_update = 0;
+	if (node != NULL)
+		status_node_free (node);
 
-	va_start (ap, what);
+	node = g_queue_peek_head (&operation->priv->status_stack);
 
-	node = status_node_new (operation);
-	node->msg = g_strdup_vprintf (what, ap);
-	node->stamp = stamp ();
-	node->transient = TRUE;
-
-	va_end (ap);
+	if (node != NULL && node->source_id == 0)
+		node->source_id = g_idle_add (
+			(GSourceFunc) operation_emit_status_cb, node);
 
 	UNLOCK ();
 }
@@ -499,9 +453,9 @@ camel_operation_start_transient (GCancellable *cancellable,
 /**
  * camel_operation_progress:
  * @cancellable: a #GCancellable or %NULL
- * @pc: percent complete, 0 to 100.
+ * @percent: percent complete, 0 to 100.
  *
- * Report progress on the current operation.  @pc reports the current
+ * Report progress on the current operation.  @percent reports the current
  * percentage of completion, which should be in the range of 0 to 100.
  *
  * This function only works if @cancellable is a #CamelOperation cast as a
@@ -510,12 +464,9 @@ camel_operation_start_transient (GCancellable *cancellable,
  **/
 void
 camel_operation_progress (GCancellable *cancellable,
-                          gint pc)
+                          gint percent)
 {
 	CamelOperation *operation;
-	const guint signal_id = signals[STATUS];
-	CamelOperationPrivate *priv;
-	guint now;
 	StatusNode *node;
 
 	if (cancellable == NULL)
@@ -526,83 +477,21 @@ camel_operation_progress (GCancellable *cancellable,
 
 	g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
 
-	if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE))
-		return;
-
 	LOCK ();
 
 	operation = CAMEL_OPERATION (cancellable);
-	priv = operation->priv;
+	node = g_queue_peek_head (&operation->priv->status_stack);
 
-	if (g_queue_is_empty (&priv->status_stack)) {
-		UNLOCK ();
-		return;
-	}
+	if (node != NULL) {
+		node->percent = percent;
 
-	node = g_queue_peek_head (&priv->status_stack);
-	node->pc = pc;
-
-	/* Transient messages dont start updating till 4 seconds after
-	   they started, then they update every second */
-	now = stamp ();
-	if (priv->status_update == now) {
-		operation = NULL;
-	} else if (node->transient) {
-		if (node->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) {
-			operation = NULL;
-		} else {
-			priv->status_update = now;
-		}
-	} else {
-		node->stamp = priv->status_update = now;
+		/* Rate limit progress updates. */
+		if (node->source_id == 0)
+			node->source_id = g_timeout_add (
+				250, (GSourceFunc)
+				operation_emit_status_cb, node);
 	}
 
-	if (operation != NULL)
-		operation_queue_status_update (operation, node);
-
 	UNLOCK ();
 }
 
-/**
- * camel_operation_end:
- * @cancellable: a #GCancellable
- *
- * Report the end of an operation.
- *
- * This function only works if @cancellable is a #CamelOperation cast as a
- * #GCancellable.  If @cancellable is a plain #GCancellable or %NULL, the
- * function does nothing and returns silently.
- **/
-void
-camel_operation_end (GCancellable *cancellable)
-{
-	CamelOperation *operation;
-	const guint signal_id = signals[STATUS];
-	GQueue *status_stack;
-	StatusNode *node;
-
-	if (cancellable == NULL)
-		return;
-
-	if (G_OBJECT_TYPE (cancellable) == G_TYPE_CANCELLABLE)
-		return;
-
-	g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
-
-	if (!g_signal_has_handler_pending (cancellable, signal_id, 0, TRUE))
-		return;
-
-	LOCK ();
-
-	operation = CAMEL_OPERATION (cancellable);
-
-	status_stack = &operation->priv->status_stack;
-
-	if ((node = g_queue_pop_head (status_stack)) != NULL) {
-		node->pc = 100;
-		operation_queue_status_update (operation, node);
-		status_node_free (node);
-	}
-
-	UNLOCK ();
-}
diff --git a/camel/camel-operation.h b/camel/camel-operation.h
index 6b6b549..7cdec8e 100644
--- a/camel/camel-operation.h
+++ b/camel/camel-operation.h
@@ -84,15 +84,12 @@ struct PRFileDesc *
  * a GCancellable pointer and just return silently if the pointer is
  * NULL or the pointed to object actually is a plain GCancellable. */
 
-void		camel_operation_start		(GCancellable *cancellable,
-						 const gchar *what,
-						 ...) G_GNUC_PRINTF (2, 3);
-void		camel_operation_start_transient	(GCancellable *cancellable,
-						 const gchar *what,
+void		camel_operation_push_message	(GCancellable *cancellable,
+						 const gchar *format,
 						 ...) G_GNUC_PRINTF (2, 3);
+void		camel_operation_pop_message	(GCancellable *cancellable);
 void		camel_operation_progress	(GCancellable *cancellable,
-						 gint pc);
-void		camel_operation_end		(GCancellable *cancellable);
+						 gint percent);
 
 G_END_DECLS
 
diff --git a/camel/camel-sasl.c b/camel/camel-sasl.c
index 4966602..de82c55 100644
--- a/camel/camel-sasl.c
+++ b/camel/camel-sasl.c
@@ -44,6 +44,8 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_SASL, CamelSaslPrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelSaslPrivate {
 	CamelService *service;
 	gboolean authenticated;
@@ -51,6 +53,16 @@ struct _CamelSaslPrivate {
 	gchar *mechanism;
 };
 
+struct _AsyncContext {
+	/* arguments */
+	GByteArray *token;
+	gchar *base64_token;
+
+	/* results */
+	GByteArray *response;
+	gchar *base64_response;
+};
+
 enum {
 	PROP_0,
 	PROP_AUTHENTICATED,
@@ -62,6 +74,21 @@ enum {
 G_DEFINE_ABSTRACT_TYPE (CamelSasl, camel_sasl, CAMEL_TYPE_OBJECT)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->token != NULL)
+		g_byte_array_free (async_context->token, TRUE);
+
+	if (async_context->response != NULL)
+		g_byte_array_free (async_context->response, TRUE);
+
+	g_free (async_context->base64_token);
+	g_free (async_context->base64_response);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 sasl_set_mechanism (CamelSasl *sasl,
                     const gchar *mechanism)
 {
@@ -192,6 +219,79 @@ sasl_finalize (GObject *object)
 }
 
 static void
+sasl_challenge_thread (GSimpleAsyncResult *simple,
+                       GObject *object,
+                       GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->response = camel_sasl_challenge_sync (
+		CAMEL_SASL (object), async_context->token,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+sasl_challenge (CamelSasl *sasl,
+                GByteArray *token,
+                gint io_priority,
+                GCancellable *cancellable,
+                GAsyncReadyCallback callback,
+                gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->token = g_byte_array_new ();
+
+	g_byte_array_append (async_context->token, token->data, token->len);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (sasl), callback, user_data, sasl_challenge);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, sasl_challenge_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static GByteArray *
+sasl_challenge_finish (CamelSasl *sasl,
+                       GAsyncResult *result,
+                       GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	GByteArray *response;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (sasl), sasl_challenge), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	response = async_context->response;
+	async_context->response = NULL;
+
+	return response;
+}
+
+static void
 camel_sasl_class_init (CamelSaslClass *class)
 {
 	GObjectClass *object_class;
@@ -204,6 +304,9 @@ camel_sasl_class_init (CamelSaslClass *class)
 	object_class->dispose = sasl_dispose;
 	object_class->finalize = sasl_finalize;
 
+	class->challenge = sasl_challenge;
+	class->challenge_finish = sasl_challenge_finish;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_AUTHENTICATED,
@@ -303,7 +406,7 @@ camel_sasl_new (const gchar *service_name,
 
 /**
  * camel_sasl_get_authenticated:
- * @sasl: a #CamelSasl object
+ * @sasl: a #CamelSasl
  *
  * Returns: whether or not @sasl has successfully authenticated the
  * user. This will be %TRUE after it returns the last needed response.
@@ -380,16 +483,18 @@ camel_sasl_get_service_name (CamelSasl *sasl)
 
 /**
  * camel_sasl_challenge_sync:
- * @sasl: a #CamelSasl object
+ * @sasl: a #CamelSasl
  * @token: a token, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * If @token is %NULL, generate the initial SASL message to send to
- * the server. (This will be %NULL if the client doesn't initiate the
- * exchange.) Otherwise, @token is a challenge from the server, and
+ * the server.  (This will be %NULL if the client doesn't initiate the
+ * exchange.)  Otherwise, @token is a challenge from the server, and
  * the return value is the response.
  *
+ * Free the returned #GByteArray with g_byte_array_free().
+ *
  * Returns: the SASL response or %NULL. If an error occurred, @error will
  * also be set.
  **/
@@ -416,16 +521,86 @@ camel_sasl_challenge_sync (CamelSasl *sasl,
 }
 
 /**
+ * camel_sasl_challenge:
+ * @sasl: a #CamelSasl
+ * @token: a token, or %NULL
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * If @token is %NULL, asynchronously generate the initial SASL message
+ * to send to the server.  (This will be %NULL if the client doesn't
+ * initiate the exchange.)  Otherwise, @token is a challenge from the
+ * server, and the asynchronous result is the response.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_sasl_challenge_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_sasl_challenge (CamelSasl *sasl,
+                      GByteArray *token,
+                      gint io_priority,
+                      GCancellable *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer user_data)
+{
+	CamelSaslClass *class;
+
+	g_return_if_fail (CAMEL_IS_SASL (sasl));
+
+	class = CAMEL_SASL_GET_CLASS (sasl);
+	g_return_if_fail (class->challenge != NULL);
+
+	class->challenge (
+		sasl, token, io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_sasl_challenge_finish:
+ * @sasl: a #CamelSasl
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_sasl_challenge().  Free the
+ * returned #GByteArray with g_byte_array_free().
+ *
+ * Returns: the SASL response or %NULL.  If an error occurred, @error will
+ * also be set.
+ *
+ * Since: 2.34
+ **/
+GByteArray *
+camel_sasl_challenge_finish (CamelSasl *sasl,
+                             GAsyncResult *result,
+                             GError **error)
+{
+	CamelSaslClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_SASL_GET_CLASS (sasl);
+	g_return_val_if_fail (class->challenge_finish != NULL, NULL);
+
+	return class->challenge_finish (sasl, result, error);
+}
+
+/**
  * camel_sasl_challenge_base64_sync:
- * @sasl: a #CamelSasl object
+ * @sasl: a #CamelSasl
  * @token: a base64-encoded token
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * As with #camel_sasl_challenge, but the challenge @token and the
+ * As with camel_sasl_challenge_sync(), but the challenge @token and the
  * response are both base64-encoded.
  *
- * Returns: the base64 encoded challenge string
+ * Returns: the base64-encoded response
+ *
+ * Since: 2.34
  **/
 gchar *
 camel_sasl_challenge_base64_sync (CamelSasl *sasl,
@@ -433,12 +608,13 @@ camel_sasl_challenge_base64_sync (CamelSasl *sasl,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-	GByteArray *token_binary, *ret_binary;
-	gchar *ret;
+	GByteArray *token_binary;
+	GByteArray *response_binary;
+	gchar *response;
 
 	g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL);
 
-	if (token && *token) {
+	if (token != NULL && *token != '\0') {
 		guchar *data;
 		gsize length = 0;
 
@@ -449,20 +625,131 @@ camel_sasl_challenge_base64_sync (CamelSasl *sasl,
 	} else
 		token_binary = NULL;
 
-	ret_binary = camel_sasl_challenge_sync (
+	response_binary = camel_sasl_challenge_sync (
 		sasl, token_binary, cancellable, error);
 	if (token_binary)
 		g_byte_array_free (token_binary, TRUE);
-	if (!ret_binary)
+	if (response_binary == NULL)
 		return NULL;
 
-	if (ret_binary->len > 0)
-		ret = g_base64_encode (ret_binary->data, ret_binary->len);
+	if (response_binary->len > 0)
+		response = g_base64_encode (
+			response_binary->data, response_binary->len);
 	else
-		ret = g_strdup ("");
-	g_byte_array_free (ret_binary, TRUE);
+		response = g_strdup ("");
+
+	g_byte_array_free (response_binary, TRUE);
+
+	return response;
+}
+
+/* Helper for camel_sasl_challenge_base64() */
+static void
+sasl_challenge_base64_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->base64_response = camel_sasl_challenge_base64_sync (
+		CAMEL_SASL (object), async_context->base64_token,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+/**
+ * camel_sasl_challenge_base64:
+ * @sasl: a #CamelSasl
+ * @token: a base64-encoded token
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * As with camel_sasl_challenge(), but the challenge @token and the
+ * response are both base64-encoded.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_challenge_base64_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_sasl_challenge_base64 (CamelSasl *sasl,
+                             const gchar *token,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_if_fail (CAMEL_IS_SASL (sasl));
 
-	return ret;
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->base64_token = g_strdup (token);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (sasl), callback, user_data,
+		camel_sasl_challenge_base64);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, sasl_challenge_base64_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+/**
+ * camel_sasl_challenge_base64_finish:
+ * @sasl: a #CamelSasl
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_sasl_challenge_base64().
+ *
+ * Returns: the base64-encoded response
+ *
+ * Since: 2.34
+ **/
+gchar *
+camel_sasl_challenge_base64_finish (CamelSasl *sasl,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	gchar *response;
+
+	g_return_val_if_fail (CAMEL_IS_SASL (sasl), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (sasl), camel_sasl_challenge_base64), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	response = async_context->base64_response;
+	async_context->base64_response = NULL;
+
+	return response;
 }
 
 /**
diff --git a/camel/camel-sasl.h b/camel/camel-sasl.h
index 57dc1c8..3bb3a84 100644
--- a/camel/camel-sasl.h
+++ b/camel/camel-sasl.h
@@ -63,10 +63,22 @@ struct _CamelSasl {
 struct _CamelSaslClass {
 	CamelObjectClass parent_class;
 
+	/* Synchronous I/O Methods */
 	GByteArray *	(*challenge_sync)	(CamelSasl *sasl,
 						 GByteArray *token,
 						 GCancellable *cancellable,
 						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*challenge)		(CamelSasl *sasl,
+						 GByteArray *token,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	GByteArray *	(*challenge_finish)	(CamelSasl *sasl,
+						 GAsyncResult *result,
+						 GError **error);
 };
 
 GType		camel_sasl_get_type		(void);
@@ -79,15 +91,35 @@ void		camel_sasl_set_authenticated	(CamelSasl *sasl,
 const gchar *	camel_sasl_get_mechanism	(CamelSasl *sasl);
 CamelService *	camel_sasl_get_service		(CamelSasl *sasl);
 const gchar *	camel_sasl_get_service_name	(CamelSasl *sasl);
+
 GByteArray *	camel_sasl_challenge_sync	(CamelSasl *sasl,
 						 GByteArray *token,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_sasl_challenge		(CamelSasl *sasl,
+						 GByteArray *token,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+GByteArray *	camel_sasl_challenge_finish	(CamelSasl *sasl,
+						 GAsyncResult *result,
+						 GError **error);
 gchar *		camel_sasl_challenge_base64_sync
 						(CamelSasl *sasl,
 						 const gchar *token,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_sasl_challenge_base64	(CamelSasl *sasl,
+						 const gchar *token,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gchar *		camel_sasl_challenge_base64_finish
+						(CamelSasl *sasl,
+						 GAsyncResult *result,
+						 GError **error);
 
 GList *		camel_sasl_authtype_list	(gboolean include_plain);
 CamelServiceAuthType *
diff --git a/camel/camel-smime-context.c b/camel/camel-smime-context.c
index 58e81d2..309eef1 100644
--- a/camel/camel-smime-context.c
+++ b/camel/camel-smime-context.c
@@ -759,7 +759,7 @@ get_hash_from_oid (SECOidTag oidTag)
 	return CAMEL_CIPHER_HASH_DEFAULT;
 }
 
-static gint
+static gboolean
 smime_context_sign_sync (CamelCipherContext *context,
                          const gchar *userid,
                          CamelCipherHash hash,
@@ -769,7 +769,6 @@ smime_context_sign_sync (CamelCipherContext *context,
                          GError **error)
 {
 	CamelCipherContextClass *class;
-	gint res = -1;
 	NSSCMSMessage *cmsg;
 	CamelStream *ostream, *istream;
 	GByteArray *buffer;
@@ -777,6 +776,7 @@ smime_context_sign_sync (CamelCipherContext *context,
 	NSSCMSEncoderContext *enc;
 	CamelDataWrapper *dw;
 	CamelContentType *ct;
+	gboolean success = FALSE;
 
 	class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
 
@@ -846,7 +846,7 @@ smime_context_sign_sync (CamelCipherContext *context,
 		goto fail;
 	}
 
-	res = 0;
+	success = TRUE;
 
 	dw = camel_data_wrapper_new ();
 	camel_stream_reset (ostream, NULL);
@@ -872,7 +872,7 @@ smime_context_sign_sync (CamelCipherContext *context,
 
 		mps = camel_multipart_signed_new ();
 		ct = camel_content_type_new ("multipart", "signed");
-		camel_content_type_set_param (ct, "micalg", camel_cipher_hash_to_id (context, get_hash_from_oid (sechash)));
+		camel_content_type_set_param (ct, "micalg", camel_cipher_context_hash_to_id (context, get_hash_from_oid (sechash)));
 		camel_content_type_set_param (ct, "protocol", class->sign_protocol);
 		camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *)mps, ct);
 		camel_content_type_unref (ct);
@@ -904,7 +904,7 @@ fail:
 	g_object_unref (ostream);
 	g_object_unref (istream);
 
-	return res;
+	return success;
 }
 
 static CamelCipherValidity *
@@ -998,7 +998,7 @@ fail:
 	return valid;
 }
 
-static gint
+static gboolean
 smime_context_encrypt_sync (CamelCipherContext *context,
                             const gchar *userid,
                             GPtrArray *recipients,
@@ -1029,7 +1029,7 @@ smime_context_encrypt_sync (CamelCipherContext *context,
 	poolp = PORT_NewArena (1024);
 	if (poolp == NULL) {
 		set_nss_error (error, g_strerror (ENOMEM));
-		return -1;
+		return FALSE;
 	}
 
 	/* Lookup all recipients certs, for later working */
@@ -1164,7 +1164,7 @@ smime_context_encrypt_sync (CamelCipherContext *context,
 	camel_mime_part_set_description (opart, "S/MIME Encrypted Message");
 	camel_mime_part_set_encoding (opart, CAMEL_TRANSFER_ENCODING_BASE64);
 
-	return 0;
+	return TRUE;
 
 fail:
 	if (ostream)
@@ -1181,7 +1181,7 @@ fail:
 
 	PORT_FreeArena (poolp, PR_FALSE);
 
-	return -1;
+	return FALSE;
 }
 
 static CamelCipherValidity *
@@ -1207,9 +1207,12 @@ smime_context_decrypt_sync (CamelCipherContext *context,
 	/* FIXME: stream this to the decoder incrementally */
 	buffer = g_byte_array_new ();
 	istream = camel_stream_mem_new_with_byte_array (buffer);
-	camel_data_wrapper_decode_to_stream_sync (
+	if (!camel_data_wrapper_decode_to_stream_sync (
 		camel_medium_get_content (CAMEL_MEDIUM (ipart)),
-		istream, NULL, NULL);
+		istream, cancellable, error)) {
+		g_object_unref (istream);
+		goto fail;
+	}
 	camel_stream_reset (istream, NULL);
 
 	dec = NSS_CMSDecoder_Start (NULL,
@@ -1352,6 +1355,7 @@ camel_smime_context_describe_part (CamelSMIMEContext *context, CamelMimePart *pa
 		/* FIXME: stream this to the decoder incrementally */
 		buffer = g_byte_array_new ();
 		istream = camel_stream_mem_new_with_byte_array (buffer);
+		/* FIXME Pass a GCancellable and GError here. */
 		camel_data_wrapper_decode_to_stream_sync (
 			camel_medium_get_content ((CamelMedium *)part),
 			istream, NULL, NULL);
diff --git a/camel/camel-store.c b/camel/camel-store.c
index fa4997f..f109e57 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -48,10 +48,24 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_STORE, CamelStorePrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelStorePrivate {
 	GStaticRecMutex folder_lock;	/* for locking folder operations */
 };
 
+struct _AsyncContext {
+	/* arguments */
+	gchar *folder_name_1;
+	gchar *folder_name_2;
+	gboolean expunge;
+	guint32 flags;
+
+	/* results */
+	CamelFolder *folder;
+	CamelFolderInfo *folder_info;
+};
+
 enum {
 	FOLDER_CREATED,
 	FOLDER_DELETED,
@@ -66,6 +80,20 @@ static guint signals[LAST_SIGNAL];
 
 G_DEFINE_ABSTRACT_TYPE (CamelStore, camel_store, CAMEL_TYPE_SERVICE)
 
+static void
+async_context_free (AsyncContext *async_context)
+{
+	g_free (async_context->folder_name_1);
+	g_free (async_context->folder_name_2);
+
+	if (async_context->folder != NULL)
+		g_object_unref (async_context->folder);
+
+	camel_folder_info_free (async_context->folder_info);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
 /**
  * ignore_no_such_table_exception:
  * Clears the exception 'ex' when it's the 'no such table' exception.
@@ -302,6 +330,789 @@ store_noop_sync (CamelStore *store,
 }
 
 static void
+store_get_folder_thread (GSimpleAsyncResult *simple,
+                         GObject *object,
+                         GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder = camel_store_get_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		async_context->flags, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_get_folder (CamelStore *store,
+                  const gchar *folder_name,
+                  guint32 flags,
+                  gint io_priority,
+                  GCancellable *cancellable,
+                  GAsyncReadyCallback callback,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (folder_name);
+	async_context->flags = flags;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_get_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_get_folder_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolder *
+store_get_folder_finish (CamelStore *store,
+                         GAsyncResult *result,
+                         GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_get_folder), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	return g_object_ref (async_context->folder);
+}
+
+static void
+store_get_folder_info_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder_info = camel_store_get_folder_info_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		async_context->flags, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_get_folder_info (CamelStore *store,
+                       const gchar *top,
+                       guint32 flags,
+                       gint io_priority,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (top);
+	async_context->flags = flags;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_get_folder_info);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_get_folder_info_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolderInfo *
+store_get_folder_info_finish (CamelStore *store,
+                              GAsyncResult *result,
+                              GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	CamelFolderInfo *folder_info;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_get_folder_info), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	folder_info = async_context->folder_info;
+	async_context->folder_info = NULL;
+
+	return folder_info;
+}
+
+static void
+store_get_inbox_folder_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder = camel_store_get_inbox_folder_sync (
+		CAMEL_STORE (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_get_inbox_folder (CamelStore *store,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_get_inbox_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_get_inbox_folder_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolder *
+store_get_inbox_folder_finish (CamelStore *store,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_get_inbox_folder), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	return g_object_ref (async_context->folder);
+}
+
+static void
+store_get_junk_folder_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder = camel_store_get_junk_folder_sync (
+		CAMEL_STORE (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_get_junk_folder (CamelStore *store,
+                       gint io_priority,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_get_junk_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_get_junk_folder_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolder *
+store_get_junk_folder_finish (CamelStore *store,
+                              GAsyncResult *result,
+                              GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_get_folder), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	return g_object_ref (async_context->folder);
+}
+
+static void
+store_get_trash_folder_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder = camel_store_get_trash_folder_sync (
+		CAMEL_STORE (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_get_trash_folder (CamelStore *store,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_get_trash_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_get_trash_folder_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolder *
+store_get_trash_folder_finish (CamelStore *store,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_get_trash_folder), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	return g_object_ref (async_context->folder);
+}
+
+static void
+store_create_folder_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->folder_info = camel_store_create_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		async_context->folder_name_2, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_create_folder (CamelStore *store,
+                     const gchar *parent_name,
+                     const gchar *folder_name,
+                     gint io_priority,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (parent_name);
+	async_context->folder_name_2 = g_strdup (folder_name);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_create_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_create_folder_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static CamelFolderInfo *
+store_create_folder_finish (CamelStore *store,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+	CamelFolderInfo *folder_info;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_create_folder_finish), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return NULL;
+
+	folder_info = async_context->folder_info;
+	async_context->folder_info = NULL;
+
+	return folder_info;
+}
+
+static void
+store_delete_folder_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_store_delete_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_delete_folder (CamelStore *store,
+                     const gchar *folder_name,
+                     gint io_priority,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (folder_name);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_delete_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_delete_folder_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_delete_folder_finish (CamelStore *store,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_delete_folder), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+store_rename_folder_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_store_rename_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		async_context->folder_name_2, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_rename_folder (CamelStore *store,
+                     const gchar *old_name,
+                     const gchar *new_name,
+                     gint io_priority,
+                     GCancellable *cancellable,
+                     GAsyncReadyCallback callback,
+                     gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (old_name);
+	async_context->folder_name_2 = g_strdup (new_name);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_rename_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_rename_folder_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_rename_folder_finish (CamelStore *store,
+                            GAsyncResult *result,
+                            GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_rename_folder), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+store_subscribe_folder_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_store_subscribe_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_subscribe_folder (CamelStore *store,
+                        const gchar *folder_name,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (folder_name);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_subscribe_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_subscribe_folder_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_subscribe_folder_finish (CamelStore *store,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_subscribe_folder), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+store_unsubscribe_folder_thread (GSimpleAsyncResult *simple,
+                                 GObject *object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_store_unsubscribe_folder_sync (
+		CAMEL_STORE (object), async_context->folder_name_1,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_unsubscribe_folder (CamelStore *store,
+                          const gchar *folder_name,
+                          gint io_priority,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->folder_name_1 = g_strdup (folder_name);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback,
+		user_data, store_unsubscribe_folder);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_unsubscribe_folder_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_unsubscribe_folder_finish (CamelStore *store,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_unsubscribe_folder), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+store_synchronize_thread (GSimpleAsyncResult *simple,
+                          GObject *object,
+                          GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_store_synchronize_sync (
+		CAMEL_STORE (object), async_context->expunge,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_synchronize (CamelStore *store,
+                   gboolean expunge,
+                   gint io_priority,
+                   GCancellable *cancellable,
+                   GAsyncReadyCallback callback,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->expunge = expunge;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_synchronize);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_synchronize_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_synchronize_finish (CamelStore *store,
+                          GAsyncResult *result,
+                          GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_synchronize), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
+store_noop_thread (GSimpleAsyncResult *simple,
+                   GObject *object,
+                   GCancellable *cancellable)
+{
+	GError *error = NULL;
+
+	camel_store_noop_sync (CAMEL_STORE (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+store_noop (CamelStore *store,
+            gint io_priority,
+            GCancellable *cancellable,
+            GAsyncReadyCallback callback,
+            gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (store), callback, user_data, store_noop);
+
+	g_simple_async_result_run_in_thread (
+		simple, store_noop_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+store_noop_finish (CamelStore *store,
+                   GAsyncResult *result,
+                   GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (store), store_noop), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
 camel_store_class_init (CamelStoreClass *class)
 {
 	GObjectClass *object_class;
@@ -319,12 +1130,38 @@ camel_store_class_init (CamelStoreClass *class)
 	class->hash_folder_name = g_str_hash;
 	class->compare_folder_name = g_str_equal;
 	class->can_refresh_folder = store_can_refresh_folder;
+
 	class->get_inbox_folder_sync = store_get_inbox_folder_sync;
 	class->get_junk_folder_sync = store_get_junk_folder_sync;
 	class->get_trash_folder_sync = store_get_trash_folder_sync;
 	class->synchronize_sync = store_synchronize_sync;
 	class->noop_sync = store_noop_sync;
 
+	class->get_folder = store_get_folder;
+	class->get_folder_finish = store_get_folder_finish;
+	class->get_folder_info = store_get_folder_info;
+	class->get_folder_info_finish = store_get_folder_info_finish;
+	class->get_inbox_folder = store_get_inbox_folder;
+	class->get_inbox_folder_finish = store_get_inbox_folder_finish;
+	class->get_junk_folder = store_get_junk_folder;
+	class->get_junk_folder_finish = store_get_junk_folder_finish;
+	class->get_trash_folder = store_get_trash_folder;
+	class->get_trash_folder_finish = store_get_trash_folder_finish;
+	class->create_folder = store_create_folder;
+	class->create_folder_finish = store_create_folder_finish;
+	class->delete_folder = store_delete_folder;
+	class->delete_folder_finish = store_delete_folder_finish;
+	class->rename_folder = store_rename_folder;
+	class->rename_folder_finish = store_rename_folder_finish;
+	class->subscribe_folder = store_subscribe_folder;
+	class->subscribe_folder_finish = store_subscribe_folder_finish;
+	class->unsubscribe_folder = store_unsubscribe_folder;
+	class->unsubscribe_folder_finish = store_unsubscribe_folder_finish;
+	class->synchronize = store_synchronize;
+	class->synchronize_finish = store_synchronize_finish;
+	class->noop = store_noop;
+	class->noop_finish = store_noop_finish;
+
 	signals[FOLDER_CREATED] = g_signal_new (
 		"folder-created",
 		G_OBJECT_CLASS_TYPE (class),
@@ -412,161 +1249,6 @@ camel_store_error_quark (void)
 	return quark;
 }
 
-/**
- * camel_store_get_folder_sync:
- * @store: a #CamelStore object
- * @folder_name: name of the folder to get
- * @flags: folder flags (create, save body index, etc)
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Get a specific folder object from the store by name.
- *
- * Returns: the folder corresponding to the path @folder_name or %NULL.
- **/
-CamelFolder *
-camel_store_get_folder_sync (CamelStore *store,
-                             const gchar *folder_name,
-                             guint32 flags,
-                             GCancellable *cancellable,
-                             GError **error)
-{
-	CamelStoreClass *class;
-	CamelFolder *folder = NULL;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-	g_return_val_if_fail (folder_name != NULL, NULL);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-
-	/* O_EXCL doesn't make sense if we aren't requesting to also create the folder if it doesn't exist */
-	if (!(flags & CAMEL_STORE_FOLDER_CREATE))
-		flags &= ~CAMEL_STORE_FOLDER_EXCL;
-
-	if (store->folders) {
-		/* Try cache first. */
-		folder = camel_object_bag_reserve (store->folders, folder_name);
-		if (folder && (flags & CAMEL_STORE_FOLDER_EXCL)) {
-			g_set_error (
-				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-				_("Cannot create folder '%s': folder exists"),
-				folder_name);
-                        camel_object_bag_abort (store->folders, folder_name);
-			g_object_unref (folder);
-			return NULL;
-		}
-	}
-
-	if (!folder) {
-
-		if (flags & CAMEL_STORE_IS_MIGRATING) {
-			if ((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) {
-				if (store->folders)
-					camel_object_bag_abort (store->folders, folder_name);
-				return NULL;
-			}
-
-			if ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0) {
-				if (store->folders)
-						camel_object_bag_abort (store->folders, folder_name);
-				return NULL;
-			}
-		}
-
-		if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) {
-			folder = class->get_trash_folder_sync (store, cancellable, error);
-			CAMEL_CHECK_GERROR (store, get_trash_folder_sync, folder != NULL, error);
-		} else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) {
-			folder = class->get_junk_folder_sync (store, cancellable, error);
-			CAMEL_CHECK_GERROR (store, get_junk_folder_sync, folder != NULL, error);
-		} else {
-			folder = class->get_folder_sync (
-				store, folder_name, flags, cancellable, error);
-			CAMEL_CHECK_GERROR (store, get_folder_sync, folder != NULL, error);
-
-			if (folder) {
-				CamelVeeFolder *vfolder;
-
-				if ((store->flags & CAMEL_STORE_VTRASH)
-				    && (vfolder = camel_object_bag_get (store->folders, CAMEL_VTRASH_NAME))) {
-					camel_vee_folder_add_folder (vfolder, folder);
-					g_object_unref (vfolder);
-				}
-
-				if ((store->flags & CAMEL_STORE_VJUNK)
-				    && (vfolder = camel_object_bag_get (store->folders, CAMEL_VJUNK_NAME))) {
-					camel_vee_folder_add_folder (vfolder, folder);
-					g_object_unref (vfolder);
-				}
-			}
-		}
-
-		if (store->folders) {
-			if (folder)
-				camel_object_bag_add (store->folders, folder_name, folder);
-			else
-				camel_object_bag_abort (store->folders, folder_name);
-		}
-
-		if (folder)
-			g_signal_emit (store, signals[FOLDER_OPENED], 0, folder);
-	}
-
-	return folder;
-}
-
-/**
- * camel_store_create_folder_sync:
- * @store: a #CamelStore object
- * @parent_name: name of the new folder's parent, or %NULL
- * @folder_name: name of the folder to create
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Creates a new folder as a child of an existing folder.
- * @parent_name can be %NULL to create a new top-level folder.
- *
- * Returns: info about the created folder, which the caller must
- * free with #camel_store_free_folder_info, or %NULL.
- **/
-CamelFolderInfo *
-camel_store_create_folder_sync (CamelStore *store,
-                                const gchar *parent_name,
-                                const gchar *folder_name,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-	CamelStoreClass *class;
-	CamelFolderInfo *fi;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-	g_return_val_if_fail (folder_name != NULL, NULL);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->create_folder_sync != NULL, NULL);
-
-	if ((parent_name == NULL || parent_name[0] == 0)
-	    && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
-		|| ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) {
-		g_set_error (
-			error, CAMEL_STORE_ERROR,
-			CAMEL_STORE_ERROR_INVALID,
-			_("Cannot create folder: %s: folder exists"),
-			folder_name);
-		return NULL;
-	}
-
-	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	fi = class->create_folder_sync (
-		store, parent_name, folder_name, cancellable, error);
-	CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error);
-
-	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	return fi;
-}
-
 /* deletes folder/removes it from the folder cache, if it's there */
 static void
 cs_delete_cached_folder (CamelStore *store,
@@ -598,199 +1280,6 @@ cs_delete_cached_folder (CamelStore *store,
 }
 
 /**
- * camel_store_delete_folder_sync:
- * @store: a #CamelStore object
- * @folder_name: name of the folder to delete
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Deletes the named folder. The folder must be empty.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_store_delete_folder_sync (CamelStore *store,
-                                const gchar *folder_name,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-	CamelStoreClass *class;
-	gboolean success;
-	GError *local_error = NULL;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
-	g_return_val_if_fail (folder_name != NULL, FALSE);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE);
-
-	/* TODO: should probably be a parameter/bit on the storeinfo */
-	if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
-	    || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) {
-		g_set_error (
-			error, CAMEL_STORE_ERROR,
-			CAMEL_STORE_ERROR_NO_FOLDER,
-			_("Cannot delete folder: %s: Invalid operation"),
-			folder_name);
-		return FALSE;
-	}
-
-	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	success = class->delete_folder_sync (
-		store, folder_name, cancellable, &local_error);
-	CAMEL_CHECK_GERROR (store, delete_folder_sync, success, &local_error);
-
-	/* ignore 'no such table' errors */
-	if (local_error != NULL &&
-	    g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0)
-		g_clear_error (&local_error);
-
-	if (local_error == NULL)
-		cs_delete_cached_folder(store, folder_name);
-	else
-		g_propagate_error (error, local_error);
-
-	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	return success;
-}
-
-/**
- * camel_store_rename_folder_sync:
- * @store: a #CamelStore object
- * @old_namein: the current name of the folder
- * @new_name: the new name of the folder
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Rename a named folder to a new name.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_store_rename_folder_sync (CamelStore *store,
-                                const gchar *old_namein,
-                                const gchar *new_name,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-	CamelStoreClass *class;
-	CamelFolder *folder;
-	gint i, oldlen, namelen;
-	GPtrArray *folders = NULL;
-	gchar *old_name;
-	gboolean success;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
-	g_return_val_if_fail (old_namein != NULL, FALSE);
-	g_return_val_if_fail (new_name != NULL, FALSE);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE);
-
-	if (strcmp (old_namein, new_name) == 0)
-		return TRUE;
-
-	if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0)
-	    || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) {
-		g_set_error (
-			error, CAMEL_STORE_ERROR,
-			CAMEL_STORE_ERROR_NO_FOLDER,
-			_("Cannot rename folder: %s: Invalid operation"),
-			old_namein);
-		return FALSE;
-	}
-
-	/* need to save this, since old_namein might be folder->full_name, which could go away */
-	old_name = g_strdup (old_namein);
-	oldlen = strlen (old_name);
-
-	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	/* If the folder is open (or any subfolders of the open folder)
-	   We need to rename them atomically with renaming the actual folder path */
-	if (store->folders) {
-		folders = camel_object_bag_list (store->folders);
-		for (i=0;i<folders->len;i++) {
-			const gchar *full_name;
-
-			folder = folders->pdata[i];
-			full_name = camel_folder_get_full_name (folder);
-
-			namelen = strlen (full_name);
-			if ((namelen == oldlen &&
-			     strcmp (full_name, old_name) == 0)
-			    || ((namelen > oldlen)
-				&& strncmp (full_name, old_name, oldlen) == 0
-				&& full_name[oldlen] == '/')) {
-				camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
-			} else {
-				g_ptr_array_remove_index_fast (folders, i);
-				i--;
-				g_object_unref (folder);
-			}
-		}
-	}
-
-	/* Now try the real rename (will emit renamed signal) */
-	success = class->rename_folder_sync (
-		store, old_name, new_name, cancellable, error);
-	CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error);
-
-	/* If it worked, update all open folders/unlock them */
-	if (folders) {
-		if (success) {
-			guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
-			CamelFolderInfo *folder_info;
-
-			for (i=0;i<folders->len;i++) {
-				const gchar *full_name;
-				gchar *new;
-
-				folder = folders->pdata[i];
-				full_name = camel_folder_get_full_name (folder);
-
-				new = g_strdup_printf("%s%s", new_name, full_name + strlen(old_name));
-				camel_object_bag_rekey (store->folders, folder, new);
-				camel_folder_rename (folder, new);
-				g_free (new);
-
-				camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-				g_object_unref (folder);
-			}
-
-			/* Emit renamed signal */
-			if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
-				flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
-
-			folder_info = class->get_folder_info_sync (
-				store, new_name, flags, cancellable, error);
-			CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error);
-
-			if (folder_info != NULL) {
-				camel_store_folder_renamed (store, old_name, folder_info);
-				class->free_folder_info (store, folder_info);
-			}
-		} else {
-			/* Failed, just unlock our folders for re-use */
-			for (i=0;i<folders->len;i++) {
-				folder = folders->pdata[i];
-				camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
-				g_object_unref (folder);
-			}
-		}
-	}
-
-	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	g_ptr_array_free (folders, TRUE);
-	g_free (old_name);
-
-	return success;
-}
-
-/**
  * camel_store_folder_created:
  * @store: a #CamelStore
  * @info: information about the created folder
@@ -898,140 +1387,6 @@ camel_store_folder_unsubscribed (CamelStore *store,
 	g_signal_emit (store, signals[FOLDER_UNSUBSCRIBED], 0, info);
 }
 
-/**
- * camel_store_get_inbox_folder_sync:
- * @store: a #CamelStore object
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Returns: the folder in the store into which new mail is delivered,
- * or %NULL if no such folder exists.
- **/
-CamelFolder *
-camel_store_get_inbox_folder_sync (CamelStore *store,
-                                   GCancellable *cancellable,
-                                   GError **error)
-{
-	CamelStoreClass *class;
-	CamelFolder *folder;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL);
-
-	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	folder = class->get_inbox_folder_sync (store, cancellable, error);
-	CAMEL_CHECK_GERROR (
-		store, get_inbox_folder_sync, folder != NULL, error);
-
-	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
-
-	return folder;
-}
-
-/**
- * camel_store_get_junk_folder_sync:
- * @store: a #CamelStore object
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Returns: the folder in the store into which junk is delivered, or
- * %NULL if no such folder exists.
- **/
-CamelFolder *
-camel_store_get_junk_folder_sync (CamelStore *store,
-                                  GCancellable *cancellable,
-                                  GError **error)
-{
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-
-	if ((store->flags & CAMEL_STORE_VJUNK) == 0) {
-		CamelStoreClass *class;
-		CamelFolder *folder;
-
-		class = CAMEL_STORE_GET_CLASS (store);
-		g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL);
-
-		folder = class->get_junk_folder_sync (store, cancellable, error);
-		CAMEL_CHECK_GERROR (
-			store, get_junk_folder_sync, folder != NULL, error);
-
-		return folder;
-	}
-
-	return camel_store_get_folder_sync (
-		store, CAMEL_VJUNK_NAME, 0, cancellable, error);
-}
-
-/**
- * camel_store_get_trash_folder_sync:
- * @store: a #CamelStore object
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Returns: the folder in the store into which trash is delivered, or
- * %NULL if no such folder exists.
- **/
-CamelFolder *
-camel_store_get_trash_folder_sync (CamelStore *store,
-                                   GCancellable *cancellable,
-                                   GError **error)
-{
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-
-	if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
-		CamelStoreClass *class;
-		CamelFolder *folder;
-
-		class = CAMEL_STORE_GET_CLASS (store);
-		g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL);
-
-		folder = class->get_trash_folder_sync (
-			store, cancellable, error);
-		CAMEL_CHECK_GERROR (
-			store, get_trash_folder_sync, folder != NULL, error);
-
-		return folder;
-	}
-
-	return camel_store_get_folder_sync (
-		store, CAMEL_VTRASH_NAME, 0, cancellable, error);
-}
-
-/**
- * camel_store_synchronize_sync:
- * @store: a #CamelStore object
- * @expunge: %TRUE if an expunge should be done after sync or %FALSE otherwise
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Syncs any changes that have been made to the store object and its
- * folders with the real store.
- *
- * Returns: %TRUE on success, %FALSE on failure
- **/
-gboolean
-camel_store_synchronize_sync (CamelStore *store,
-                              gboolean expunge,
-                              GCancellable *cancellable,
-                              GError **error)
-{
-	CamelStoreClass *class;
-	gboolean success;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
-
-	success = class->synchronize_sync (store, expunge, cancellable, error);
-	CAMEL_CHECK_GERROR (store, synchronize_sync, success, error);
-
-	return success;
-}
-
 static void
 add_special_info (CamelStore *store,
                   CamelFolderInfo *info,
@@ -1113,79 +1468,8 @@ dump_fi (CamelFolderInfo *fi, gint depth)
 }
 
 /**
- * camel_store_get_folder_info_sync:
- * @store: a #CamelStore object
- * @top: the name of the folder to start from
- * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * This fetches information about the folder structure of @store,
- * starting with @top, and returns a tree of CamelFolderInfo
- * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
- * only subscribed folders will be listed.   If the store doesn't support
- * subscriptions, then it will list all folders.  If @flags includes
- * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
- * all levels of hierarchy below @top. If not, it will only include
- * the immediate subfolders of @top. If @flags includes
- * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
- * some or all of the structures may be set to %-1, if the store cannot
- * determine that information quickly.  If @flags includes
- * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
- * folders (such as vTrash or vJunk).
- *
- * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered
- * deprecated; most backends will behave the same whether it is
- * supplied or not.  The only guaranteed way to get updated folder
- * counts is to both open the folder and invoke refresh_info() it.
- *
- * Returns: a #CamelFolderInfo tree, which must be freed with
- * #camel_store_free_folder_info, or %NULL.
- **/
-CamelFolderInfo *
-camel_store_get_folder_info_sync (CamelStore *store,
-                                  const gchar *top,
-                                  guint32 flags,
-                                  GCancellable *cancellable,
-                                  GError **error)
-{
-	CamelStoreClass *class;
-	CamelFolderInfo *info;
-
-	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
-
-	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL);
-
-	info = class->get_folder_info_sync (
-		store, top, flags, cancellable, error);
-	if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED))
-		CAMEL_CHECK_GERROR (
-			store, get_folder_info_sync, info != NULL, error);
-
-	if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
-		if (info->uri && (store->flags & CAMEL_STORE_VTRASH))
-			/* the name of the Trash folder, used for deleted messages */
-			add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH);
-		if (info->uri && (store->flags & CAMEL_STORE_VJUNK))
-			/* the name of the Junk folder, used for spam messages */
-			add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK);
-	}
-
-	if (camel_debug_start("store:folder_info")) {
-		gchar *url = camel_url_to_string (((CamelService *)store)->url, CAMEL_URL_HIDE_ALL);
-		printf("Get folder info(%p:%s, '%s') =\n", (gpointer) store, url, top?top:"<null>");
-		g_free (url);
-		dump_fi (info, 2);
-		camel_debug_end ();
-	}
-
-	return info;
-}
-
-/**
  * camel_store_free_folder_info:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info
  *
  * Frees the data returned by #camel_store_get_folder_info. If @fi is %NULL,
@@ -1210,7 +1494,7 @@ camel_store_free_folder_info (CamelStore *store,
 
 /**
  * camel_store_free_folder_info_full:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info
  *
  * An implementation for #CamelStore::free_folder_info. Frees all
@@ -1225,7 +1509,7 @@ camel_store_free_folder_info_full (CamelStore *store,
 
 /**
  * camel_store_free_folder_info_nop:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @fi: a #CamelFolderInfo as gotten via #camel_store_get_folder_info
  *
  * An implementation for #CamelStore::free_folder_info. Does nothing.
@@ -1451,7 +1735,7 @@ camel_folder_info_clone (CamelFolderInfo *fi)
 
 /**
  * camel_store_supports_subscriptions:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  *
  * Get whether or not @store supports subscriptions to folders.
  *
@@ -1467,7 +1751,7 @@ camel_store_supports_subscriptions (CamelStore *store)
 
 /**
  * camel_store_folder_is_subscribed:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @folder_name: full path of the folder
  *
  * Find out if a folder has been subscribed to.
@@ -1498,15 +1782,1259 @@ camel_store_folder_is_subscribed (CamelStore *store,
 }
 
 /**
+ * camel_store_folder_uri_equal:
+ * @store: a #CamelStore
+ * @uri0: a folder uri
+ * @uri1: another folder uri
+ *
+ * Compares two folder uris to check that they are equal.
+ *
+ * Returns: %TRUE if they are equal or %FALSE otherwise
+ **/
+gint
+camel_store_folder_uri_equal (CamelStore *store,
+                              const gchar *uri0,
+                              const gchar *uri1)
+{
+	CamelStoreClass *class;
+	CamelProvider *provider;
+	CamelURL *url0, *url1;
+	gint equal;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (uri0 && uri1, FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->compare_folder_name != NULL, FALSE);
+
+	provider = ((CamelService *) store)->provider;
+
+	if (!(url0 = camel_url_new (uri0, NULL)))
+		return FALSE;
+
+	if (!(url1 = camel_url_new (uri1, NULL))) {
+		camel_url_free (url0);
+		return FALSE;
+	}
+
+	if ((equal = provider->url_equal (url0, url1))) {
+		const gchar *name0, *name1;
+
+		if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) {
+			name0 = url0->fragment;
+			name1 = url1->fragment;
+		} else {
+			name0 = url0->path && url0->path[0] == '/' ? url0->path + 1 : url0->path;
+			name1 = url1->path && url1->path[0] == '/' ? url1->path + 1 : url1->path;
+		}
+
+		if (name0 == NULL)
+			g_warning("URI is badly formed, missing folder name: %s", uri0);
+
+		if (name1 == NULL)
+			g_warning("URI is badly formed, missing folder name: %s", uri1);
+
+		equal = name0 && name1 && class->compare_folder_name (name0, name1);
+	}
+
+	camel_url_free (url0);
+	camel_url_free (url1);
+
+	return equal;
+}
+
+/**
+ * camel_store_can_refresh_folder
+ * @store: a #CamelStore
+ * @info: a #CamelFolderInfo
+ * @error: return location for a #GError, or %NULL
+ *
+ * Returns if this folder (param info) should be checked for new mail or not.
+ * It should not look into sub infos (info->child) or next infos, it should
+ * return value only for the actual folder info.
+ * Default behavior is that all Inbox folders are intended to be refreshed.
+ *
+ * Returns: whether folder should be checked for new mails
+ *
+ * Since: 2.22
+ **/
+gboolean
+camel_store_can_refresh_folder (CamelStore *store,
+                                CamelFolderInfo *info,
+                                GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE);
+
+	return class->can_refresh_folder (store, info, error);
+}
+
+/**
+ * camel_store_lock:
+ * @store: a #CamelStore
+ * @lock: lock type to lock
+ *
+ * Locks #store's #lock. Unlock it with camel_store_unlock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_store_lock (CamelStore *store,
+                  CamelStoreLock lock)
+{
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	switch (lock) {
+		case CAMEL_STORE_FOLDER_LOCK:
+			g_static_rec_mutex_lock (&store->priv->folder_lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_store_unlock:
+ * @store: a #CamelStore
+ * @lock: lock type to unlock
+ *
+ * Unlocks #store's #lock, previously locked with camel_store_lock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_store_unlock (CamelStore *store,
+                    CamelStoreLock lock)
+{
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	switch (lock) {
+		case CAMEL_STORE_FOLDER_LOCK:
+			g_static_rec_mutex_unlock (&store->priv->folder_lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_store_get_folder_sync:
+ * @store: a #CamelStore
+ * @folder_name: name of the folder to get
+ * @flags: folder flags (create, save body index, etc)
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets a specific folder object from @store by name.
+ *
+ * Returns: the requested #CamelFolder object, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_folder_sync (CamelStore *store,
+                             const gchar *folder_name,
+                             guint32 flags,
+                             GCancellable *cancellable,
+                             GError **error)
+{
+	CamelStoreClass *class;
+	CamelFolder *folder = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (folder_name != NULL, NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+
+	/* O_EXCL doesn't make sense if we aren't requesting to also create the folder if it doesn't exist */
+	if (!(flags & CAMEL_STORE_FOLDER_CREATE))
+		flags &= ~CAMEL_STORE_FOLDER_EXCL;
+
+	if (store->folders) {
+		/* Try cache first. */
+		folder = camel_object_bag_reserve (store->folders, folder_name);
+		if (folder && (flags & CAMEL_STORE_FOLDER_EXCL)) {
+			g_set_error (
+				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+				_("Cannot create folder '%s': folder exists"),
+				folder_name);
+                        camel_object_bag_abort (store->folders, folder_name);
+			g_object_unref (folder);
+			return NULL;
+		}
+	}
+
+	if (!folder) {
+
+		if (flags & CAMEL_STORE_IS_MIGRATING) {
+			if ((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0) {
+				if (store->folders)
+					camel_object_bag_abort (store->folders, folder_name);
+				return NULL;
+			}
+
+			if ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0) {
+				if (store->folders)
+						camel_object_bag_abort (store->folders, folder_name);
+				return NULL;
+			}
+		}
+
+		if ((store->flags & CAMEL_STORE_VTRASH) && strcmp(folder_name, CAMEL_VTRASH_NAME) == 0) {
+			folder = class->get_trash_folder_sync (store, cancellable, error);
+			CAMEL_CHECK_GERROR (store, get_trash_folder_sync, folder != NULL, error);
+		} else if ((store->flags & CAMEL_STORE_VJUNK) && strcmp(folder_name, CAMEL_VJUNK_NAME) == 0) {
+			folder = class->get_junk_folder_sync (store, cancellable, error);
+			CAMEL_CHECK_GERROR (store, get_junk_folder_sync, folder != NULL, error);
+		} else {
+			folder = class->get_folder_sync (
+				store, folder_name, flags, cancellable, error);
+			CAMEL_CHECK_GERROR (store, get_folder_sync, folder != NULL, error);
+
+			if (folder) {
+				CamelVeeFolder *vfolder;
+
+				if ((store->flags & CAMEL_STORE_VTRASH)
+				    && (vfolder = camel_object_bag_get (store->folders, CAMEL_VTRASH_NAME))) {
+					camel_vee_folder_add_folder (vfolder, folder);
+					g_object_unref (vfolder);
+				}
+
+				if ((store->flags & CAMEL_STORE_VJUNK)
+				    && (vfolder = camel_object_bag_get (store->folders, CAMEL_VJUNK_NAME))) {
+					camel_vee_folder_add_folder (vfolder, folder);
+					g_object_unref (vfolder);
+				}
+			}
+		}
+
+		if (store->folders) {
+			if (folder)
+				camel_object_bag_add (store->folders, folder_name, folder);
+			else
+				camel_object_bag_abort (store->folders, folder_name);
+		}
+
+		if (folder)
+			g_signal_emit (store, signals[FOLDER_OPENED], 0, folder);
+	}
+
+	return folder;
+}
+
+/**
+ * camel_store_get_folder:
+ * @store: a #CamelStore
+ * @folder_name: name of the folder to get
+ * @flags: folder flags (create, save body index, etc)
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously gets a specific folder object from @store by name.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_get_folder_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_get_folder (CamelStore *store,
+                        const gchar *folder_name,
+                        guint32 flags,
+                        gint io_priority,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (folder_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->get_folder != NULL);
+
+	class->get_folder (
+		store, folder_name, flags, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_get_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_get_folder().
+ *
+ * Returns: the requested #CamelFolder object, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_folder_finish (CamelStore *store,
+                               GAsyncResult *result,
+                               GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_folder_finish != NULL, NULL);
+
+	return class->get_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_get_folder_info_sync:
+ * @store: a #CamelStore
+ * @top: the name of the folder to start from
+ * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * This fetches information about the folder structure of @store,
+ * starting with @top, and returns a tree of #CamelFolderInfo
+ * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
+ * only subscribed folders will be listed.   If the store doesn't support
+ * subscriptions, then it will list all folders.  If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
+ * all levels of hierarchy below @top. If not, it will only include
+ * the immediate subfolders of @top. If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
+ * some or all of the structures may be set to %-1, if the store cannot
+ * determine that information quickly.  If @flags includes
+ * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
+ * folders (such as vTrash or vJunk).
+ *
+ * The returned #CamelFolderInfo tree should be freed with
+ * camel_store_free_folder_info().
+ *
+ * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered
+ * deprecated; most backends will behave the same whether it is
+ * supplied or not.  The only guaranteed way to get updated folder
+ * counts is to both open the folder and invoke refresh_info() it.
+ *
+ * Returns: a #CamelFolderInfo tree, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolderInfo *
+camel_store_get_folder_info_sync (CamelStore *store,
+                                  const gchar *top,
+                                  guint32 flags,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+	CamelStoreClass *class;
+	CamelFolderInfo *info;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL);
+
+	info = class->get_folder_info_sync (
+		store, top, flags, cancellable, error);
+	if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED))
+		CAMEL_CHECK_GERROR (
+			store, get_folder_info_sync, info != NULL, error);
+
+	if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
+		if (info->uri && (store->flags & CAMEL_STORE_VTRASH))
+			/* the name of the Trash folder, used for deleted messages */
+			add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH);
+		if (info->uri && (store->flags & CAMEL_STORE_VJUNK))
+			/* the name of the Junk folder, used for spam messages */
+			add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK);
+	}
+
+	if (camel_debug_start("store:folder_info")) {
+		gchar *url = camel_url_to_string (((CamelService *)store)->url, CAMEL_URL_HIDE_ALL);
+		printf("Get folder info(%p:%s, '%s') =\n", (gpointer) store, url, top?top:"<null>");
+		g_free (url);
+		dump_fi (info, 2);
+		camel_debug_end ();
+	}
+
+	return info;
+}
+
+/**
+ * camel_store_get_folder_info:
+ * @store: a #CamelStore
+ * @top: the name of the folder to start from
+ * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously fetches information about the folder structure of @store,
+ * starting with @top.  For details of the behavior, see
+ * camel_store_get_folder_info_sync().
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_get_folder_info_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_get_folder_info (CamelStore *store,
+                             const gchar *top,
+                             guint32 flags,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->get_folder_info != NULL);
+
+	class->get_folder_info (
+		store, top, flags, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_get_folder_info_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_get_folder_info().
+ * The returned #CamelFolderInfo tree should be freed with
+ * camel_store_free_folder_info().
+ *
+ * Returns: a #CamelFolderInfo tree, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolderInfo *
+camel_store_get_folder_info_finish (CamelStore *store,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_folder_info_finish != NULL, NULL);
+
+	return class->get_folder_info_finish (store, result, error);
+}
+
+/**
+ * camel_store_get_inbox_folder_sync:
+ * @store: a #CamelStore
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the folder in @store into which new mail is delivered.
+ *
+ * Returns: the inbox folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_inbox_folder_sync (CamelStore *store,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+	CamelStoreClass *class;
+	CamelFolder *folder;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL);
+
+	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return NULL;
+	}
+
+	folder = class->get_inbox_folder_sync (store, cancellable, error);
+	CAMEL_CHECK_GERROR (
+		store, get_inbox_folder_sync, folder != NULL, error);
+
+	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	return folder;
+}
+
+/**
+ * camel_store_get_inbox_folder:
+ * @store: a #CamelStore
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously gets the folder in @store into which new mail is delivered.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_get_inbox_folder_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_get_inbox_folder (CamelStore *store,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->get_inbox_folder != NULL);
+
+	class->get_inbox_folder (
+		store, io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_get_inbox_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_get_inbox_folder().
+ *
+ * Returns: the inbox folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_inbox_folder_finish (CamelStore *store,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_inbox_folder_finish != NULL, NULL);
+
+	return class->get_inbox_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_get_junk_folder_sync:
+ * @store: a #CamelStore
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the folder in @store into which junk is delivered.
+ *
+ * Returns: the junk folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_junk_folder_sync (CamelStore *store,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+	if ((store->flags & CAMEL_STORE_VJUNK) == 0) {
+		CamelStoreClass *class;
+		CamelFolder *folder;
+
+		class = CAMEL_STORE_GET_CLASS (store);
+		g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL);
+
+		folder = class->get_junk_folder_sync (store, cancellable, error);
+		CAMEL_CHECK_GERROR (
+			store, get_junk_folder_sync, folder != NULL, error);
+
+		return folder;
+	}
+
+	return camel_store_get_folder_sync (
+		store, CAMEL_VJUNK_NAME, 0, cancellable, error);
+}
+
+/**
+ * camel_store_get_junk_folder:
+ * @store: a #CamelStore
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously gets the folder in @store into which junk is delivered.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_get_junk_folder_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_get_junk_folder (CamelStore *store,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->get_junk_folder != NULL);
+
+	class->get_junk_folder (
+		store, io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_get_junk_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_get_junk_folder().
+ *
+ * Returns: the junk folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_junk_folder_finish (CamelStore *store,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_junk_folder_finish != NULL, NULL);
+
+	return class->get_junk_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_get_trash_folder_sync:
+ * @store: a #CamelStore
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the folder in @store into which trash is delivered.
+ *
+ * Returns: the trash folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_trash_folder_sync (CamelStore *store,
+                                   GCancellable *cancellable,
+                                   GError **error)
+{
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+	if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
+		CamelStoreClass *class;
+		CamelFolder *folder;
+
+		class = CAMEL_STORE_GET_CLASS (store);
+		g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL);
+
+		folder = class->get_trash_folder_sync (
+			store, cancellable, error);
+		CAMEL_CHECK_GERROR (
+			store, get_trash_folder_sync, folder != NULL, error);
+
+		return folder;
+	}
+
+	return camel_store_get_folder_sync (
+		store, CAMEL_VTRASH_NAME, 0, cancellable, error);
+}
+
+/**
+ * camel_store_get_trash_folder:
+ * @store: a #CamelStore
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously gets the folder in @store into which trash is delivered.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_get_trash_folder_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_get_trash_folder (CamelStore *store,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->get_trash_folder != NULL);
+
+	class->get_trash_folder (
+		store, io_priority, cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_get_trash_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_get_trash_folder().
+ *
+ * Returns: the trash folder for @store, or %NULL on error or if no such
+ * folder exists
+ *
+ * Since: 2.34
+ **/
+CamelFolder *
+camel_store_get_trash_folder_finish (CamelStore *store,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->get_trash_folder_finish != NULL, NULL);
+
+	return class->get_trash_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_create_folder_sync:
+ * @store: a #CamelStore
+ * @parent_name: name of the new folder's parent, or %NULL
+ * @folder_name: name of the folder to create
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates a new folder as a child of an existing folder.
+ * @parent_name can be %NULL to create a new top-level folder.
+ * The returned #CamelFolderInfo struct should be freed with
+ * camel_store_free_folder_info().
+ *
+ * Returns: info about the created folder, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolderInfo *
+camel_store_create_folder_sync (CamelStore *store,
+                                const gchar *parent_name,
+                                const gchar *folder_name,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+	CamelStoreClass *class;
+	CamelFolderInfo *fi;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (folder_name != NULL, NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->create_folder_sync != NULL, NULL);
+
+	if ((parent_name == NULL || parent_name[0] == 0)
+	    && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
+		|| ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) {
+		g_set_error (
+			error, CAMEL_STORE_ERROR,
+			CAMEL_STORE_ERROR_INVALID,
+			_("Cannot create folder: %s: folder exists"),
+			folder_name);
+		return NULL;
+	}
+
+	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return NULL;
+	}
+
+	fi = class->create_folder_sync (
+		store, parent_name, folder_name, cancellable, error);
+	CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error);
+
+	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	return fi;
+}
+
+/**
+ * camel_store_create_folder:
+ * @store: a #CamelStore
+ * @parent_name: name of the new folder's parent, or %NULL
+ * @folder_name: name of the folder to create
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously creates a new folder as a child of an existing folder.
+ * @parent_name can be %NULL to create a new top-level folder.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_create_folder_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_create_folder (CamelStore *store,
+                           const gchar *parent_name,
+                           const gchar *folder_name,
+                           gint io_priority,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (folder_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->create_folder != NULL);
+
+	class->create_folder (
+		store, parent_name, folder_name, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_create_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_create_folder().
+ * The returned #CamelFolderInfo struct should be freed with
+ * camel_store_free_folder_info().
+ *
+ * Returns: info about the created folder, or %NULL on error
+ *
+ * Since: 2.34
+ **/
+CamelFolderInfo *
+camel_store_create_folder_finish (CamelStore *store,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->create_folder_finish != NULL, NULL);
+
+	return class->create_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_delete_folder_sync:
+ * @store: a #CamelStore
+ * @folder_name: name of the folder to delete
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes the folder described by @folder_name.  The folder must be empty.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_delete_folder_sync (CamelStore *store,
+                                const gchar *folder_name,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+	CamelStoreClass *class;
+	gboolean success;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (folder_name != NULL, FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE);
+
+	/* TODO: should probably be a parameter/bit on the storeinfo */
+	if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
+	    || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) {
+		g_set_error (
+			error, CAMEL_STORE_ERROR,
+			CAMEL_STORE_ERROR_NO_FOLDER,
+			_("Cannot delete folder: %s: Invalid operation"),
+			folder_name);
+		return FALSE;
+	}
+
+	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return FALSE;
+	}
+
+	success = class->delete_folder_sync (
+		store, folder_name, cancellable, &local_error);
+	CAMEL_CHECK_GERROR (store, delete_folder_sync, success, &local_error);
+
+	/* ignore 'no such table' errors */
+	if (local_error != NULL &&
+	    g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0)
+		g_clear_error (&local_error);
+
+	if (local_error == NULL)
+		cs_delete_cached_folder(store, folder_name);
+	else
+		g_propagate_error (error, local_error);
+
+	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	return success;
+}
+
+/**
+ * camel_store_delete_folder:
+ * @store: a #CamelStore
+ * @folder_name: name of the folder to delete
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes the folder described by @folder_name.  The
+ * folder must be empty.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_delete_folder_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_delete_folder (CamelStore *store,
+                           const gchar *folder_name,
+                           gint io_priority,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (folder_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->delete_folder != NULL);
+
+	class->delete_folder (
+		store, folder_name, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_delete_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_delete_folder().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_delete_folder_finish (CamelStore *store,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->delete_folder_finish != NULL, FALSE);
+
+	return class->delete_folder_finish (store, result, error);
+}
+
+/**
+ * camel_store_rename_folder_sync:
+ * @store: a #CamelStore
+ * @old_name: the current name of the folder
+ * @new_name: the new name of the folder
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Renames the folder described by @old_name to @new_name.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_rename_folder_sync (CamelStore *store,
+                                const gchar *old_namein,
+                                const gchar *new_name,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+	CamelStoreClass *class;
+	CamelFolder *folder;
+	gint i, oldlen, namelen;
+	GPtrArray *folders = NULL;
+	gchar *old_name;
+	gboolean success;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (old_namein != NULL, FALSE);
+	g_return_val_if_fail (new_name != NULL, FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE);
+
+	if (strcmp (old_namein, new_name) == 0)
+		return TRUE;
+
+	if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0)
+	    || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) {
+		g_set_error (
+			error, CAMEL_STORE_ERROR,
+			CAMEL_STORE_ERROR_NO_FOLDER,
+			_("Cannot rename folder: %s: Invalid operation"),
+			old_namein);
+		return FALSE;
+	}
+
+	/* need to save this, since old_namein might be folder->full_name, which could go away */
+	old_name = g_strdup (old_namein);
+	oldlen = strlen (old_name);
+
+	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return FALSE;
+	}
+
+	/* If the folder is open (or any subfolders of the open folder)
+	   We need to rename them atomically with renaming the actual folder path */
+	if (store->folders) {
+		folders = camel_object_bag_list (store->folders);
+		for (i=0;i<folders->len;i++) {
+			const gchar *full_name;
+
+			folder = folders->pdata[i];
+			full_name = camel_folder_get_full_name (folder);
+
+			namelen = strlen (full_name);
+			if ((namelen == oldlen &&
+			     strcmp (full_name, old_name) == 0)
+			    || ((namelen > oldlen)
+				&& strncmp (full_name, old_name, oldlen) == 0
+				&& full_name[oldlen] == '/')) {
+				camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+			} else {
+				g_ptr_array_remove_index_fast (folders, i);
+				i--;
+				g_object_unref (folder);
+			}
+		}
+	}
+
+	/* Now try the real rename (will emit renamed signal) */
+	success = class->rename_folder_sync (
+		store, old_name, new_name, cancellable, error);
+	CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error);
+
+	/* If it worked, update all open folders/unlock them */
+	if (folders) {
+		if (success) {
+			guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+			CamelFolderInfo *folder_info;
+
+			for (i=0;i<folders->len;i++) {
+				const gchar *full_name;
+				gchar *new;
+
+				folder = folders->pdata[i];
+				full_name = camel_folder_get_full_name (folder);
+
+				new = g_strdup_printf("%s%s", new_name, full_name + strlen(old_name));
+				camel_object_bag_rekey (store->folders, folder, new);
+				camel_folder_rename (folder, new);
+				g_free (new);
+
+				camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+				g_object_unref (folder);
+			}
+
+			/* Emit renamed signal */
+			if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+				flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+			folder_info = class->get_folder_info_sync (
+				store, new_name, flags, cancellable, error);
+			CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error);
+
+			if (folder_info != NULL) {
+				camel_store_folder_renamed (store, old_name, folder_info);
+				class->free_folder_info (store, folder_info);
+			}
+		} else {
+			/* Failed, just unlock our folders for re-use */
+			for (i=0;i<folders->len;i++) {
+				folder = folders->pdata[i];
+				camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+				g_object_unref (folder);
+			}
+		}
+	}
+
+	camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+
+	g_ptr_array_free (folders, TRUE);
+	g_free (old_name);
+
+	return success;
+}
+
+/**
+ * camel_store_rename_folder:
+ * @store: a #CamelStore
+ * @old_name: the current name of the folder
+ * @new_name: the new name of the folder
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously renames the folder described by @old_name to @new_name.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_rename_folder_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_rename_folder (CamelStore *store,
+                           const gchar *old_name,
+                           const gchar *new_name,
+                           gint io_priority,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (old_name != NULL);
+	g_return_if_fail (new_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->rename_folder != NULL);
+
+	class->rename_folder (
+		store, old_name, new_name, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_rename_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_rename_folder().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_rename_folder_finish (CamelStore *store,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->rename_folder_finish != NULL, FALSE);
+
+	return class->rename_folder_finish (store, result, error);
+}
+
+/**
  * camel_store_subscribe_folder_sync:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @folder_name: full path of the folder
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Subscribe to the folder described by @folder_name.
+ * Subscribes to the folder described by @folder_name.
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
 gboolean
 camel_store_subscribe_folder_sync (CamelStore *store,
@@ -1526,6 +3054,12 @@ camel_store_subscribe_folder_sync (CamelStore *store,
 
 	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
 
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return FALSE;
+	}
+
 	success = class->subscribe_folder_sync (
 		store, folder_name, cancellable, error);
 	CAMEL_CHECK_GERROR (store, subscribe_folder_sync, success, error);
@@ -1536,15 +3070,83 @@ camel_store_subscribe_folder_sync (CamelStore *store,
 }
 
 /**
+ * camel_store_subscribe_folder:
+ * @store: a #CamelStore
+ * @folder_name: full path of the folder
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously subscribes to the folder described by @folder_name.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call camel_store_subscribe_folder_finish() to get the result of
+ * the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_subscribe_folder (CamelStore *store,
+                              const gchar *folder_name,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (folder_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->subscribe_folder != NULL);
+
+	class->subscribe_folder (
+		store, folder_name, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_subscribe_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_subscribe_folder().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_subscribe_folder_finish (CamelStore *store,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	CamelStoreClass *class;
+
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->subscribe_folder_finish != NULL, FALSE);
+
+	return class->subscribe_folder_finish (store, result, error);
+}
+
+/**
  * camel_store_unsubscribe_folder_sync:
- * @store: a #CamelStore object
+ * @store: a #CamelStore
  * @folder_name: full path of the folder
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Unsubscribe from the folder described by @folder_name.
+ * Unsubscribes from the folder described by @folder_name.
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
 gboolean
 camel_store_unsubscribe_folder_sync (CamelStore *store,
@@ -1564,6 +3166,12 @@ camel_store_unsubscribe_folder_sync (CamelStore *store,
 
 	camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
 
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
+		return FALSE;
+	}
+
 	success = class->unsubscribe_folder_sync (
 		store, folder_name, cancellable, error);
 	CAMEL_CHECK_GERROR (store, unsubscribe_folder_sync, success, error);
@@ -1577,171 +3185,257 @@ camel_store_unsubscribe_folder_sync (CamelStore *store,
 }
 
 /**
- * camel_store_noop_sync:
- * @store: a #CamelStore object
+ * camel_store_unsubscribe_folder:
+ * @store: a #CamelStore
+ * @folder_name: full path of the folder
+ * @io_priority: the I/O priority of the request
  * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously unsubscribes from the folder described by @folder_name.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_unsubscribe_folder_finish() to get the result of the
+ * operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_unsubscribe_folder (CamelStore *store,
+                                const gchar *folder_name,
+                                gint io_priority,
+                                GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data)
+{
+	CamelStoreClass *class;
+
+	g_return_if_fail (CAMEL_IS_STORE (store));
+	g_return_if_fail (folder_name != NULL);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->unsubscribe_folder != NULL);
+
+	class->unsubscribe_folder (
+		store, folder_name, io_priority,
+		cancellable, callback, user_data);
+}
+
+/**
+ * camel_store_unsubscribe_folder_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
  * @error: return location for a #GError, or %NULL
  *
- * Pings @store so that its connection doesn't timeout.
+ * Finishes the operation started with camel_store_unsubscribe_folder().
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
 gboolean
-camel_store_noop_sync (CamelStore *store,
-                       GCancellable *cancellable,
-                       GError **error)
+camel_store_unsubscribe_folder_finish (CamelStore *store,
+                                       GAsyncResult *result,
+                                       GError **error)
 {
 	CamelStoreClass *class;
-	gboolean success;
 
 	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
 
 	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->noop_sync != NULL, FALSE);
-
-	success = class->noop_sync (store, cancellable, error);
-	CAMEL_CHECK_GERROR (store, noop_sync, success, error);
+	g_return_val_if_fail (class->unsubscribe_folder_finish != NULL, FALSE);
 
-	return success;
+	return class->unsubscribe_folder_finish (store, result, error);
 }
 
 /**
- * camel_store_folder_uri_equal:
- * @store: a #CamelStore object
- * @uri0: a folder uri
- * @uri1: another folder uri
+ * camel_store_synchronize_sync:
+ * @store: a #CamelStore
+ * @expunge: whether to expunge after synchronizing
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
  *
- * Compares two folder uris to check that they are equal.
+ * Synchronizes any changes that have been made to @store and its folders
+ * with the real store.
  *
- * Returns: %TRUE if they are equal or %FALSE otherwise
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-gint
-camel_store_folder_uri_equal (CamelStore *store,
-                              const gchar *uri0,
-                              const gchar *uri1)
+gboolean
+camel_store_synchronize_sync (CamelStore *store,
+                              gboolean expunge,
+                              GCancellable *cancellable,
+                              GError **error)
 {
 	CamelStoreClass *class;
-	CamelProvider *provider;
-	CamelURL *url0, *url1;
-	gint equal;
+	gboolean success;
 
 	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
-	g_return_val_if_fail (uri0 && uri1, FALSE);
 
 	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->compare_folder_name != NULL, FALSE);
+	g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
 
-	provider = ((CamelService *) store)->provider;
+	success = class->synchronize_sync (store, expunge, cancellable, error);
+	CAMEL_CHECK_GERROR (store, synchronize_sync, success, error);
 
-	if (!(url0 = camel_url_new (uri0, NULL)))
-		return FALSE;
+	return success;
+}
 
-	if (!(url1 = camel_url_new (uri1, NULL))) {
-		camel_url_free (url0);
-		return FALSE;
-	}
+/**
+ * camel_store_synchronize:
+ * @store: a #CamelStore
+ * @expunge: whether to expunge after synchronizing
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Synchronizes any changes that have been made to @store and its folders
+ * with the real store asynchronously.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_synchronize_finish() to get the result of the operation.
+ *
+ * Since: 2.34
+ **/
+void
+camel_store_synchronize (CamelStore *store,
+                         gboolean expunge,
+                         gint io_priority,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	CamelStoreClass *class;
 
-	if ((equal = provider->url_equal (url0, url1))) {
-		const gchar *name0, *name1;
+	g_return_if_fail (CAMEL_IS_STORE (store));
 
-		if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) {
-			name0 = url0->fragment;
-			name1 = url1->fragment;
-		} else {
-			name0 = url0->path && url0->path[0] == '/' ? url0->path + 1 : url0->path;
-			name1 = url1->path && url1->path[0] == '/' ? url1->path + 1 : url1->path;
-		}
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->synchronize != NULL);
 
-		if (name0 == NULL)
-			g_warning("URI is badly formed, missing folder name: %s", uri0);
+	class->synchronize (
+		store, expunge, io_priority,
+		cancellable, callback, user_data);
+}
 
-		if (name1 == NULL)
-			g_warning("URI is badly formed, missing folder name: %s", uri1);
+/**
+ * camel_store_synchronize_finish:
+ * @store: a #CamelStore
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with camel_store_synchronize().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
+ **/
+gboolean
+camel_store_synchronize_finish (CamelStore *store,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	CamelStoreClass *class;
 
-		equal = name0 && name1 && class->compare_folder_name (name0, name1);
-	}
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
 
-	camel_url_free (url0);
-	camel_url_free (url1);
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->synchronize_finish != NULL, FALSE);
 
-	return equal;
+	return class->synchronize_finish (store, result, error);
 }
 
 /**
- * camel_store_can_refresh_folder
+ * camel_store_noop_sync:
  * @store: a #CamelStore
- * @info: a #CamelFolderInfo
+ * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Returns if this folder (param info) should be checked for new mail or not.
- * It should not look into sub infos (info->child) or next infos, it should
- * return value only for the actual folder info.
- * Default behavior is that all Inbox folders are intended to be refreshed.
+ * Pings @store so its connection doesn't time out.
  *
- * Returns: whether folder should be checked for new mails
+ * Returns: %TRUE on success, %FALSE on error
  *
- * Since: 2.22
+ * Since: 2.34
  **/
 gboolean
-camel_store_can_refresh_folder (CamelStore *store,
-                                CamelFolderInfo *info,
-                                GError **error)
+camel_store_noop_sync (CamelStore *store,
+                       GCancellable *cancellable,
+                       GError **error)
 {
 	CamelStoreClass *class;
+	gboolean success;
 
 	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
-	g_return_val_if_fail (info != NULL, FALSE);
 
 	class = CAMEL_STORE_GET_CLASS (store);
-	g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE);
+	g_return_val_if_fail (class->noop_sync != NULL, FALSE);
 
-	return class->can_refresh_folder (store, info, error);
+	success = class->noop_sync (store, cancellable, error);
+	CAMEL_CHECK_GERROR (store, noop_sync, success, error);
+
+	return success;
 }
 
 /**
- * camel_store_lock:
+ * camel_store_noop:
  * @store: a #CamelStore
- * @lock: lock type to lock
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
  *
- * Locks #store's #lock. Unlock it with camel_store_unlock().
+ * Pings @store asynchronously so its connection doesn't time out.
  *
- * Since: 2.32
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_store_noop_finish() to get the result of the operation.
+ *
+ * Since: 2.34
  **/
 void
-camel_store_lock (CamelStore *store,
-                  CamelStoreLock lock)
+camel_store_noop (CamelStore *store,
+                  gint io_priority,
+                  GCancellable *cancellable,
+                  GAsyncReadyCallback callback,
+                  gpointer user_data)
 {
+	CamelStoreClass *class;
+
 	g_return_if_fail (CAMEL_IS_STORE (store));
 
-	switch (lock) {
-		case CAMEL_STORE_FOLDER_LOCK:
-			g_static_rec_mutex_lock (&store->priv->folder_lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_if_fail (class->noop != NULL);
+
+	class->noop (store, io_priority, cancellable, callback, user_data);
 }
 
 /**
- * camel_store_unlock:
+ * camel_store_noop_finish:
  * @store: a #CamelStore
- * @lock: lock type to unlock
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
  *
- * Unlocks #store's #lock, previously locked with camel_store_lock().
+ * Finishes the operation started with camel_store_noop().
  *
- * Since: 2.32
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-void
-camel_store_unlock (CamelStore *store,
-                    CamelStoreLock lock)
+gboolean
+camel_store_noop_finish (CamelStore *store,
+                         GAsyncResult *result,
+                         GError **error)
 {
-	g_return_if_fail (CAMEL_IS_STORE (store));
+	CamelStoreClass *class;
 
-	switch (lock) {
-		case CAMEL_STORE_FOLDER_LOCK:
-			g_static_rec_mutex_unlock (&store->priv->folder_lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
+	g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_STORE_GET_CLASS (store);
+	g_return_val_if_fail (class->noop_finish != NULL, FALSE);
+
+	return class->noop_finish (store, result, error);
 }
diff --git a/camel/camel-store.h b/camel/camel-store.h
index 641c6e1..ce53de6 100644
--- a/camel/camel-store.h
+++ b/camel/camel-store.h
@@ -220,7 +220,7 @@ struct _CamelStoreClass {
 	GHashFunc hash_folder_name;
 	GCompareFunc compare_folder_name;
 
-	/* Methods */
+	/* Non-Blocking Methods */
 	gboolean	(*can_refresh_folder)	(CamelStore *store,
 						 CamelFolderInfo *info,
 						 GError **error);
@@ -229,6 +229,7 @@ struct _CamelStoreClass {
 	void		(*free_folder_info)	(CamelStore *store,
 						 CamelFolderInfo *fi);
 
+	/* Synchronous I/O Methods */
 	CamelFolder *	(*get_folder_sync)	(CamelStore *store,
 						 const gchar *folder_name,
 						 guint32 flags,
@@ -284,6 +285,124 @@ struct _CamelStoreClass {
 						 GCancellable *cancellable,
 						 GError **error);
 
+	/* Asyncrhonous I/O Methods (all have defaults) */
+	void		(*get_folder)		(CamelStore *store,
+						 const gchar *folder_name,
+						 guint32 flags,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolder *	(*get_folder_finish)	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*get_folder_info)	(CamelStore *store,
+						 const gchar *top,
+						 guint32 flags,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolderInfo *
+			(*get_folder_info_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*get_inbox_folder)	(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolder *	(*get_inbox_folder_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*get_junk_folder)	(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolder *	(*get_junk_folder_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*get_trash_folder)	(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolder *	(*get_trash_folder_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*create_folder)	(CamelStore *store,
+						 const gchar *parent_name,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	CamelFolderInfo *
+			(*create_folder_finish)	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*delete_folder)	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*delete_folder_finish)	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*rename_folder)	(CamelStore *store,
+						 const gchar *old_name,
+						 const gchar *new_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*rename_folder_finish)	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*subscribe_folder)	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*subscribe_folder_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*unsubscribe_folder)	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*unsubscribe_folder_finish)
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*synchronize)		(CamelStore *store,
+						 gboolean expunge,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*synchronize_finish)	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+	void		(*noop)			(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*noop_finish)		(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+
 	/* Signals */
 	void		(*folder_created)	(CamelStore *store,
 						 CamelFolderInfo *info);
@@ -352,6 +471,16 @@ CamelFolder *	camel_store_get_folder_sync	(CamelStore *store,
 						 guint32 flags,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_get_folder		(CamelStore *store,
+						 const gchar *folder_name,
+						 guint32 flags,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolder *	camel_store_get_folder_finish	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 CamelFolderInfo *
 		camel_store_get_folder_info_sync
 						(CamelStore *store,
@@ -359,50 +488,159 @@ CamelFolderInfo *
 						 guint32 flags,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_get_folder_info	(CamelStore *store,
+						 const gchar *top,
+						 guint32 flags,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolderInfo *
+		camel_store_get_folder_info_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 CamelFolder *	camel_store_get_inbox_folder_sync
 						(CamelStore *store,
 						 GCancellable *cancellable,
 						 GError **error);
-CamelFolder *	camel_store_get_trash_folder_sync
-						(CamelStore *store,
+void		camel_store_get_inbox_folder	(CamelStore *store,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolder *	camel_store_get_inbox_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
 						 GError **error);
 CamelFolder *	camel_store_get_junk_folder_sync
 						(CamelStore *store,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_get_junk_folder	(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolder *	camel_store_get_junk_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
+CamelFolder *	camel_store_get_trash_folder_sync
+						(CamelStore *store,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_store_get_trash_folder	(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolder *	camel_store_get_trash_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 CamelFolderInfo *
 		camel_store_create_folder_sync	(CamelStore *store,
 						 const gchar *parent_name,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_create_folder	(CamelStore *store,
+						 const gchar *parent_name,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+CamelFolderInfo *
+		camel_store_create_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_delete_folder_sync	(CamelStore *store,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_delete_folder	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_delete_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_rename_folder_sync	(CamelStore *store,
-						 const gchar *old_namein,
+						 const gchar *old_name,
 						 const gchar *new_name,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_rename_folder	(CamelStore *store,
+						 const gchar *old_name,
+						 const gchar *new_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_rename_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_subscribe_folder_sync
 						(CamelStore *store,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_subscribe_folder	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_subscribe_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_unsubscribe_folder_sync
 						(CamelStore *store,
 						 const gchar *folder_name,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_unsubscribe_folder	(CamelStore *store,
+						 const gchar *folder_name,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_unsubscribe_folder_finish
+						(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_synchronize_sync	(CamelStore *store,
 						 gboolean expunge,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_synchronize		(CamelStore *store,
+						 gboolean expunge,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_synchronize_finish	(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 gboolean	camel_store_noop_sync		(CamelStore *store,
 						 GCancellable *cancellable,
 						 GError **error);
+void		camel_store_noop		(CamelStore *store,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_store_noop_finish		(CamelStore *store,
+						 GAsyncResult *result,
+						 GError **error);
 
 G_END_DECLS
 
diff --git a/camel/camel-transport.c b/camel/camel-transport.c
index 24bdc7b..068c2ef 100644
--- a/camel/camel-transport.c
+++ b/camel/camel-transport.c
@@ -36,13 +36,37 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_TRANSPORT, CamelTransportPrivate))
 
+typedef struct _AsyncContext AsyncContext;
+
 struct _CamelTransportPrivate {
 	GMutex *send_lock;   /* for locking send operations */
 };
 
+struct _AsyncContext {
+	/* arguments */
+	CamelAddress *from;
+	CamelAddress *recipients;
+	CamelMimeMessage *message;
+};
+
 G_DEFINE_ABSTRACT_TYPE (CamelTransport, camel_transport, CAMEL_TYPE_SERVICE)
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->from != NULL)
+		g_object_unref (async_context->from);
+
+	if (async_context->recipients != NULL)
+		g_object_unref (async_context->recipients);
+
+	if (async_context->message != NULL)
+		g_object_unref (async_context->message);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
 transport_finalize (GObject *object)
 {
 	CamelTransportPrivate *priv;
@@ -56,6 +80,74 @@ transport_finalize (GObject *object)
 }
 
 static void
+transport_send_to_thread (GSimpleAsyncResult *simple,
+                          GObject *object,
+                          GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	camel_transport_send_to_sync (
+		CAMEL_TRANSPORT (object), async_context->message,
+		async_context->from, async_context->recipients,
+		cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static void
+transport_send_to (CamelTransport *transport,
+                   CamelMimeMessage *message,
+                   CamelAddress *from,
+                   CamelAddress *recipients,
+                   gint io_priority,
+                   GCancellable *cancellable,
+                   GAsyncReadyCallback callback,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->from = g_object_ref (from);
+	async_context->recipients = g_object_ref (recipients);
+	async_context->message = g_object_ref (message);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (transport), callback, user_data, transport_send_to);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, transport_send_to_thread, io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+transport_send_to_finish (CamelTransport *transport,
+                          GAsyncResult *result,
+                          GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (transport), transport_send_to), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+static void
 camel_transport_class_init (CamelTransportClass *class)
 {
 	GObjectClass *object_class;
@@ -64,6 +156,9 @@ camel_transport_class_init (CamelTransportClass *class)
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->finalize = transport_finalize;
+
+	class->send_to = transport_send_to;
+	class->send_to_finish = transport_send_to_finish;
 }
 
 static void
@@ -75,8 +170,56 @@ camel_transport_init (CamelTransport *transport)
 }
 
 /**
+ * camel_transport_lock:
+ * @transport: a #CamelTransport
+ * @lock: lock type to lock
+ *
+ * Locks #transport's #lock. Unlock it with camel_transport_unlock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_transport_lock (CamelTransport *transport,
+                      CamelTransportLock lock)
+{
+	g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
+
+	switch (lock) {
+		case CAMEL_TRANSPORT_SEND_LOCK:
+			g_mutex_lock (transport->priv->send_lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
+ * camel_transport_unlock:
+ * @transport: a #CamelTransport
+ * @lock: lock type to unlock
+ *
+ * Unlocks #transport's #lock, previously locked with camel_transport_lock().
+ *
+ * Since: 2.32
+ **/
+void
+camel_transport_unlock (CamelTransport *transport,
+                        CamelTransportLock lock)
+{
+	g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
+
+	switch (lock) {
+		case CAMEL_TRANSPORT_SEND_LOCK:
+			g_mutex_unlock (transport->priv->send_lock);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+}
+
+/**
  * camel_transport_send_to_sync:
- * @transport: a #CamelTransport object
+ * @transport: a #CamelTransport
  * @message: a #CamelMimeMessage to send
  * @from: a #CamelAddress to send from
  * @recipients: a #CamelAddress containing all recipients
@@ -84,10 +227,12 @@ camel_transport_init (CamelTransport *transport)
  * @error: return location for a #GError, or %NULL
  *
  * Sends the message to the given recipients, regardless of the contents
- * of @message. If the message contains a "Bcc" header, the transport
+ * of @message.  If the message contains a "Bcc" header, the transport
  * is responsible for stripping it.
  *
- * Return %TRUE on success or %FALSE on fail
+ * Returns: %TRUE on success or %FALSE on error
+ *
+ * Since: 2.34
  **/
 gboolean
 camel_transport_send_to_sync (CamelTransport *transport,
@@ -110,6 +255,12 @@ camel_transport_send_to_sync (CamelTransport *transport,
 
 	camel_transport_lock (transport, CAMEL_TRANSPORT_SEND_LOCK);
 
+	/* Check for cancellation after locking. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		camel_transport_unlock (transport, CAMEL_TRANSPORT_SEND_LOCK);
+		return FALSE;
+	}
+
 	success = class->send_to_sync (
 		transport, message, from, recipients, cancellable, error);
 	CAMEL_CHECK_GERROR (transport, send_to_sync, success, error);
@@ -120,49 +271,74 @@ camel_transport_send_to_sync (CamelTransport *transport,
 }
 
 /**
- * camel_transport_lock:
+ * camel_transport_send_to:
  * @transport: a #CamelTransport
- * @lock: lock type to lock
+ * @message: a #CamelMimeMessage to send
+ * @from: a #CamelAddress to send from
+ * @recipients: a #CamelAddress containing all recipients
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
  *
- * Locks #transport's #lock. Unlock it with camel_transport_unlock().
+ * Sends the message asynchronously to the given recipients, regardless of
+ * the contents of @message.  If the message contains a "Bcc" header, the
+ * transport is responsible for stripping it.
  *
- * Since: 2.32
+ * When the operation is finished, @callback will be called.  You can then
+ * call camel_transport_send_to_finish() to get the result of the operation.
+ *
+ * Since: 2.34
  **/
 void
-camel_transport_lock (CamelTransport *transport,
-                      CamelTransportLock lock)
+camel_transport_send_to (CamelTransport *transport,
+                         CamelMimeMessage *message,
+                         CamelAddress *from,
+                         CamelAddress *recipients,
+                         gint io_priority,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
 {
+	CamelTransportClass *class;
+
 	g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
+	g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+	g_return_if_fail (CAMEL_IS_ADDRESS (from));
+	g_return_if_fail (CAMEL_IS_ADDRESS (recipients));
 
-	switch (lock) {
-		case CAMEL_TRANSPORT_SEND_LOCK:
-			g_mutex_lock (transport->priv->send_lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
+	class = CAMEL_TRANSPORT_GET_CLASS (transport);
+	g_return_if_fail (class->send_to != NULL);
+
+	class->send_to (
+		transport, message, from, recipients, io_priority,
+		cancellable, callback, user_data);
 }
 
 /**
- * camel_transport_unlock:
+ * camel_transport_send_to_finish:
  * @transport: a #CamelTransport
- * @lock: lock type to unlock
+ * @result: a #GAsyncResult
+ * @error: return locaton for a #GError, or %NULL
  *
- * Unlocks #transport's #lock, previously locked with camel_transport_lock().
+ * Finishes the operation started with camel_transport_send_to().
  *
- * Since: 2.32
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 2.34
  **/
-void
-camel_transport_unlock (CamelTransport *transport,
-                        CamelTransportLock lock)
+gboolean
+camel_transport_send_to_finish (CamelTransport *transport,
+                                GAsyncResult *result,
+                                GError **error)
 {
-	g_return_if_fail (CAMEL_IS_TRANSPORT (transport));
+	CamelTransportClass *class;
 
-	switch (lock) {
-		case CAMEL_TRANSPORT_SEND_LOCK:
-			g_mutex_unlock (transport->priv->send_lock);
-			break;
-		default:
-			g_return_if_reached ();
-	}
+	g_return_val_if_fail (CAMEL_IS_TRANSPORT (transport), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	class = CAMEL_TRANSPORT_GET_CLASS (transport);
+	g_return_val_if_fail (class->send_to_finish != NULL, FALSE);
+
+	return class->send_to_finish (transport, result, error);
 }
diff --git a/camel/camel-transport.h b/camel/camel-transport.h
index 7a53961..ce01ef2 100644
--- a/camel/camel-transport.h
+++ b/camel/camel-transport.h
@@ -76,26 +76,52 @@ struct _CamelTransport {
 struct _CamelTransportClass {
 	CamelServiceClass parent_class;
 
+	/* Synchronous I/O Methods */
 	gboolean	(*send_to_sync)		(CamelTransport *transport,
 						 CamelMimeMessage *message,
 						 CamelAddress *from,
 						 CamelAddress *recipients,
 						 GCancellable *cancellable,
 						 GError **error);
-};
 
-GType		camel_transport_get_type	(void);
-gboolean	camel_transport_send_to_sync	(CamelTransport *transport,
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*send_to)		(CamelTransport *transport,
 						 CamelMimeMessage *message,
 						 CamelAddress *from,
 						 CamelAddress *recipients,
+						 gint io_priority,
 						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	gboolean	(*send_to_finish)	(CamelTransport *transport,
+						 GAsyncResult *result,
 						 GError **error);
+};
+
+GType		camel_transport_get_type	(void);
 void		camel_transport_lock		(CamelTransport *transport,
 						 CamelTransportLock lock);
 void		camel_transport_unlock		(CamelTransport *transport,
 						 CamelTransportLock lock);
 
+gboolean	camel_transport_send_to_sync	(CamelTransport *transport,
+						 CamelMimeMessage *message,
+						 CamelAddress *from,
+						 CamelAddress *recipients,
+						 GCancellable *cancellable,
+						 GError **error);
+void		camel_transport_send_to		(CamelTransport *transport,
+						 CamelMimeMessage *message,
+						 CamelAddress *from,
+						 CamelAddress *recipients,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	camel_transport_send_to_finish	(CamelTransport *transport,
+						 GAsyncResult *result,
+						 GError **error);
+
 G_END_DECLS
 
 #endif /* CAMEL_TRANSPORT_H */
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index 8585108..17c985c 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -1210,7 +1210,7 @@ vee_folder_thaw (CamelFolder *folder)
 static gboolean
 vee_folder_append_message_sync (CamelFolder *folder,
                                 CamelMimeMessage *message,
-                                const CamelMessageInfo *info,
+                                CamelMessageInfo *info,
                                 gchar **appended_uid,
                                 GCancellable *cancellable,
                                 GError **error)
@@ -1372,8 +1372,8 @@ static gboolean
 vee_folder_transfer_messages_to_sync (CamelFolder *folder,
                                       GPtrArray *uids,
                                       CamelFolder *dest,
-                                      GPtrArray **transferred_uids,
                                       gboolean delete_originals,
+                                      GPtrArray **transferred_uids,
                                       GCancellable *cancellable,
                                       GError **error)
 {
diff --git a/camel/camel-vtrash-folder.c b/camel/camel-vtrash-folder.c
index 63fd5db..31fd387 100644
--- a/camel/camel-vtrash-folder.c
+++ b/camel/camel-vtrash-folder.c
@@ -70,7 +70,7 @@ transfer_messages (CamelFolder *folder,
 
 	camel_folder_transfer_messages_to_sync (
 		md->folder, md->uids, md->dest,
-		NULL, md->delete, md->cancellable, error);
+		md->delete, NULL, md->cancellable, error);
 
 	if (md->cancellable != NULL)
 		g_object_unref (md->cancellable);
@@ -86,7 +86,7 @@ transfer_messages (CamelFolder *folder,
 static gboolean
 vtrash_folder_append_message_sync (CamelFolder *folder,
                                    CamelMimeMessage *message,
-                                   const CamelMessageInfo *info,
+                                   CamelMessageInfo *info,
                                    gchar **appended_uid,
                                    GCancellable *cancellable,
                                    GError **error)
@@ -102,8 +102,8 @@ static gboolean
 vtrash_folder_transfer_messages_to_sync (CamelFolder *source,
                                          GPtrArray *uids,
                                          CamelFolder *dest,
-                                         GPtrArray **transferred_uids,
                                          gboolean delete_originals,
+                                         GPtrArray **transferred_uids,
                                          GCancellable *cancellable,
                                          GError **error)
 {
diff --git a/camel/providers/groupwise/camel-groupwise-folder.c b/camel/providers/groupwise/camel-groupwise-folder.c
index 53da6ce..622c57b 100644
--- a/camel/providers/groupwise/camel-groupwise-folder.c
+++ b/camel/providers/groupwise/camel-groupwise-folder.c
@@ -77,7 +77,7 @@ struct _CamelGroupwiseFolderPrivate {
 extern gint camel_application_is_exiting;
 
 /*prototypes*/
-static gboolean groupwise_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, GPtrArray **transferred_uids, gboolean delete_originals, GCancellable *cancellable, GError **error);
+static gboolean groupwise_transfer_messages_to_sync (CamelFolder *source, GPtrArray *uids, CamelFolder *destination, gboolean delete_originals, GPtrArray **transferred_uids, GCancellable *cancellable, GError **error);
 void convert_to_calendar (EGwItem *item, gchar **str, gint *len);
 static void convert_to_task (EGwItem *item, gchar **str, gint *len);
 static void convert_to_note (EGwItem *item, gchar **str, gint *len);
@@ -548,7 +548,7 @@ move_to_mailbox (CamelFolder *folder,
 		CAMEL_GW_MESSAGE_JUNK, 0);
 	if (dest)
 		groupwise_transfer_messages_to_sync (
-			folder, uids, dest, NULL, TRUE, cancellable, error);
+			folder, uids, dest, TRUE, NULL, cancellable, error);
 	else
 		g_warning ("No Mailbox folder found");
 
@@ -577,7 +577,7 @@ move_to_junk (CamelFolder *folder,
 
 	if (dest)
 		groupwise_transfer_messages_to_sync (
-			folder, uids, dest, NULL, TRUE, cancellable, error);
+			folder, uids, dest, TRUE, NULL, cancellable, error);
 	else {
 		fi = create_junk_folder (parent_store);
 		dest = camel_store_get_folder_sync (
@@ -586,7 +586,7 @@ move_to_junk (CamelFolder *folder,
 			g_warning ("Could not get JunkFolder:Message not moved");
 		else
 			groupwise_transfer_messages_to_sync (
-				folder, uids, dest, NULL, TRUE, cancellable, error);
+				folder, uids, dest, TRUE, NULL, cancellable, error);
 	}
 	update_junk_list (parent_store, info, ADD_JUNK_ENTRY);
 }
@@ -1030,7 +1030,7 @@ update_update (CamelSession *session,
 		goto end1;
 	}
 
-	camel_operation_start (
+	camel_operation_push_message (
 		msg->cancellable,
 		_("Checking for deleted messages %s"),
 		camel_folder_get_name (m->folder));
@@ -1103,12 +1103,12 @@ update_update (CamelSession *session,
 
 	g_print ("\nNumber of items in the folder: %d \n", g_list_length(items_full_list));
 	gw_update_all_items (m->folder, items_full_list, NULL, NULL);
-	camel_operation_end (msg->cancellable);
+	camel_operation_pop_message (msg->cancellable);
 
 	return;
  end1:
 	camel_service_unlock (CAMEL_SERVICE (gw_store), CAMEL_SERVICE_REC_CONNECT_LOCK);
-	camel_operation_end (msg->cancellable);
+	camel_operation_pop_message (msg->cancellable);
 	if (items_full_list) {
 		g_list_foreach (items_full_list, (GFunc)g_free, NULL);
 		g_list_free (items_full_list);
@@ -1515,7 +1515,7 @@ gw_update_cache (CamelFolder *folder,
 		is_junk = TRUE;
 	}
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable,
 		_("Fetching summary information for new messages in %s"),
 		camel_folder_get_name (folder));
@@ -1714,7 +1714,7 @@ gw_update_cache (CamelFolder *folder,
 		g_object_unref (item);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	g_free (container_id);
 	g_string_free (str_to, TRUE);
@@ -2060,7 +2060,7 @@ groupwise_folder_item_to_msg ( CamelFolder *folder,
 	msg = camel_mime_message_new ();
 	if (has_mime_822 && body) {
 		temp_stream = camel_stream_mem_new_with_buffer (body, body_len);
-		if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, temp_stream, NULL, error) == -1) {
+		if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, temp_stream, NULL, error)) {
 			g_object_unref (msg);
 			g_object_unref (temp_stream);
 			msg = NULL;
@@ -2398,7 +2398,7 @@ groupwise_folder_constructed (GObject *object)
 static gboolean
 groupwise_append_message_sync (CamelFolder *folder,
                                CamelMimeMessage *message,
-                               const CamelMessageInfo *info,
+                               CamelMessageInfo *info,
                                gchar **appended_uid,
                                GCancellable *cancellable,
                                GError **error)
@@ -2653,7 +2653,7 @@ groupwise_folder_get_message_sync (CamelFolder *folder,
 		camel_stream_reset (stream, NULL);
 		camel_stream_write_to_stream (cache_stream, stream, cancellable, NULL);
 		camel_stream_reset (stream, NULL);
-		if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, stream, cancellable, error) == -1) {
+		if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, stream, cancellable, error)) {
 			if (errno == EINTR) {
 				g_object_unref (msg);
 				g_object_unref (cache_stream);
@@ -2810,8 +2810,8 @@ static gboolean
 groupwise_transfer_messages_to_sync (CamelFolder *source,
                                      GPtrArray *uids,
                                      CamelFolder *destination,
-                                     GPtrArray **transferred_uids,
                                      gboolean delete_originals,
+                                     GPtrArray **transferred_uids,
                                      GCancellable *cancellable,
                                      GError **error)
 {
diff --git a/camel/providers/groupwise/camel-groupwise-journal.c b/camel/providers/groupwise/camel-groupwise-journal.c
index 0927106..81fa47c 100644
--- a/camel/providers/groupwise/camel-groupwise-journal.c
+++ b/camel/providers/groupwise/camel-groupwise-journal.c
@@ -175,7 +175,7 @@ groupwise_entry_play_append (CamelOfflineJournal *journal,
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error) == -1) {
+	if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error)) {
 		g_object_unref (message);
 		g_object_unref (stream);
 		goto done;
@@ -229,7 +229,7 @@ groupwise_entry_play_transfer (CamelOfflineJournal *journal,
 		g_ptr_array_add (uids, entry->original_uid);
 
 		if (camel_folder_transfer_messages_to_sync (
-			src, uids, folder, &xuids, FALSE, cancellable, error)) {
+			src, uids, folder, FALSE, &xuids, cancellable, error)) {
 			real = (CamelGroupwiseMessageInfo *) camel_folder_summary_uid (folder->summary, xuids->pdata[0]);
 
 			/* transfer all the system flags, user flags/tags, etc */
diff --git a/camel/providers/groupwise/camel-groupwise-store.c b/camel/providers/groupwise/camel-groupwise-store.c
index cdc8cd9..0a8d5ff 100644
--- a/camel/providers/groupwise/camel-groupwise-store.c
+++ b/camel/providers/groupwise/camel-groupwise-store.c
@@ -667,7 +667,7 @@ groupwise_store_get_folder_sync (CamelStore *store,
 			return NULL;
 		}
 
-		camel_operation_start (
+		camel_operation_push_message (
 			cancellable,
 			_("Fetching summary information for new messages in %s"),
 			camel_folder_get_name (folder));
@@ -712,7 +712,7 @@ groupwise_store_get_folder_sync (CamelStore *store,
 
 		e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
 
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 	}
 	if (done && all_ok) {
 		if (summary->time_string)
@@ -798,7 +798,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store,
 					return FALSE;
 			}
 
-			camel_operation_start (
+			camel_operation_push_message (
 				cancellable,
 				_("Fetching summary information for new messages in %s"),
 				camel_folder_get_name (folder));
@@ -815,7 +815,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store,
 								error, CAMEL_SERVICE_ERROR,
 								CAMEL_SERVICE_ERROR_INVALID,
 								_("Authentication failed"));
-							camel_operation_end (cancellable);
+							camel_operation_pop_message (cancellable);
 							g_free (container_id);
 							return FALSE;
 					}
@@ -849,7 +849,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store,
 
 			e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
 
-			camel_operation_end (cancellable);
+			camel_operation_pop_message (cancellable);
 	}
 
 	if (done) {
diff --git a/camel/providers/groupwise/camel-groupwise-transport.c b/camel/providers/groupwise/camel-groupwise-transport.c
index 12caf78..3b5336b 100644
--- a/camel/providers/groupwise/camel-groupwise-transport.c
+++ b/camel/providers/groupwise/camel-groupwise-transport.c
@@ -94,7 +94,7 @@ groupwise_send_to_sync (CamelTransport *transport,
 				    CAMEL_URL_HIDE_PARAMS   |
 				    CAMEL_URL_HIDE_AUTH) );
 
-	camel_operation_start (cancellable, _("Sending Message") );
+	camel_operation_push_message (cancellable, _("Sending Message") );
 
 	/*camel groupwise store and cnc*/
 	store = camel_session_get_store (service->session, url, NULL);
@@ -113,7 +113,7 @@ groupwise_send_to_sync (CamelTransport *transport,
 	cnc = cnc_lookup (priv);
 	if (!cnc) {
 		g_warning ("||| Eh!!! Failure |||\n");
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		g_set_error (
 			error, CAMEL_SERVICE_ERROR,
 			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
@@ -140,7 +140,7 @@ groupwise_send_to_sync (CamelTransport *transport,
 	status = e_gw_connection_send_item (cnc, item, &sent_item_list);
 	if (status != E_GW_CONNECTION_STATUS_OK) {
 		g_warning (" Error Sending mail");
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		e_gw_item_set_link_info (item, NULL);
 		g_object_unref (item);
 		if (temp_item)
@@ -169,7 +169,7 @@ groupwise_send_to_sync (CamelTransport *transport,
 		g_object_unref (temp_item);
 	g_object_unref (item);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return TRUE;
 }
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 0f073a3..6517e80 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -89,23 +89,27 @@ static CamelMimeMessage *imap_get_message_sync (CamelFolder *folder, const gchar
 static gboolean imap_synchronize_message_sync (CamelFolder *folder, const gchar *uid, GCancellable *cancellable,
 			       GError **error);
 static gboolean imap_append_online (CamelFolder *folder, CamelMimeMessage *message,
-				const CamelMessageInfo *info, gchar **appended_uid,
+				CamelMessageInfo *info, gchar **appended_uid,
 				GCancellable *cancellable,
 				GError **error);
 static gboolean imap_append_offline (CamelFolder *folder, CamelMimeMessage *message,
-				 const CamelMessageInfo *info, gchar **appended_uid,
+				 CamelMessageInfo *info, gchar **appended_uid,
 				 GError **error);
 
-static gboolean imap_transfer_online (CamelFolder *source, GPtrArray *uids,
-				  CamelFolder *dest, GPtrArray **transferred_uids,
-				  gboolean delete_originals,
-				  GCancellable *cancellable,
-				  GError **error);
-static gboolean imap_transfer_offline (CamelFolder *source, GPtrArray *uids,
-				   CamelFolder *dest, GPtrArray **transferred_uids,
-				   gboolean delete_originals,
-				   GCancellable *cancellable,
-				   GError **error);
+static gboolean	imap_transfer_online		(CamelFolder *source,
+						 GPtrArray *uids,
+						 CamelFolder *dest,
+						 gboolean delete_originals,
+						 GPtrArray **transferred_uids,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imap_transfer_offline		(CamelFolder *source,
+						 GPtrArray *uids,
+						 CamelFolder *dest,
+						 gboolean delete_originals,
+						 GPtrArray **transferred_uids,
+						 GCancellable *cancellable,
+						 GError **error);
 
 /* searching */
 static GPtrArray *imap_search_by_expression (CamelFolder *folder, const gchar *expression, GError **error);
@@ -124,11 +128,14 @@ static CamelImapMessageInfo * imap_folder_summary_uid_or_error (
 	const gchar * uid,
 	GError **error);
 
-static gboolean
-imap_transfer_messages (CamelFolder *source, GPtrArray *uids,
-			CamelFolder *dest, GPtrArray **transferred_uids,
-			gboolean delete_originals, gboolean can_call_sync,
-			GCancellable *cancellable, GError **error);
+static gboolean	imap_transfer_messages		(CamelFolder *source,
+						 GPtrArray *uids,
+						 CamelFolder *dest,
+						 gboolean delete_originals,
+						 GPtrArray **transferred_uids,
+						 gboolean can_call_sync,
+						 GCancellable *cancellable,
+						 GError **error);
 
 #ifdef G_OS_WIN32
 /* The strtok() in Microsoft's C library is MT-safe (but still uses
@@ -979,13 +986,13 @@ imap_rescan (CamelFolder *folder,
 	}
 
 	/* Check UIDs and flags of all messages we already know of. */
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable, _("Scanning for changed messages in %s"),
 		camel_folder_get_name (folder));
 	uid = camel_folder_summary_uid_from_index (folder->summary, summary_len - 1);
 
 	if (!uid) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return TRUE;
 	}
 
@@ -994,7 +1001,7 @@ imap_rescan (CamelFolder *folder,
 		"UID FETCH 1:%s (FLAGS)", uid);
 	g_free (uid);
 	if (!ok) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return FALSE;
 	}
 
@@ -1029,13 +1036,13 @@ imap_rescan (CamelFolder *folder,
 	}
 
 	if (summary_got == 0 && summary_len == 0) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 		g_free (new);
 		return TRUE;
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) {
 		for (i = 0; i < summary_len && new[i].uid; i++) {
@@ -1486,8 +1493,8 @@ move_messages (CamelFolder *src_folder,
 	if (src_folder != des_folder) {
 		/* do 'copy' to not be bothered with CAMEL_MESSAGE_DELETED again */
 		if (!imap_transfer_messages (
-			src_folder, uids, des_folder, NULL,
-			FALSE, FALSE, cancellable, error))
+			src_folder, uids, des_folder, FALSE,
+			NULL, FALSE, cancellable, error))
 			return;
 	}
 
@@ -2175,7 +2182,7 @@ get_temp_uid (void)
 static gboolean
 imap_append_offline (CamelFolder *folder,
                      CamelMimeMessage *message,
-                     const CamelMessageInfo *info,
+                     CamelMessageInfo *info,
                      gchar **appended_uid,
                      GError **error)
 {
@@ -2231,7 +2238,7 @@ imap_folder_uid_in_ignore_recent (CamelImapFolder *imap_folder, const gchar *uid
 static CamelImapResponse *
 do_append (CamelFolder *folder,
            CamelMimeMessage *message,
-           const CamelMessageInfo *info,
+           CamelMessageInfo *info,
            gchar **uid,
            GCancellable *cancellable,
            GError **error)
@@ -2341,7 +2348,7 @@ retry:
 static gboolean
 imap_append_online (CamelFolder *folder,
                     CamelMimeMessage *message,
-                    const CamelMessageInfo *info,
+                    CamelMessageInfo *info,
                     gchar **appended_uid,
                     GCancellable *cancellable,
                     GError **error)
@@ -2397,7 +2404,7 @@ imap_append_online (CamelFolder *folder,
 gboolean
 camel_imap_append_resyncing (CamelFolder *folder,
                              CamelMimeMessage *message,
-                             const CamelMessageInfo *info,
+                             CamelMessageInfo *info,
                              gchar **appended_uid,
                              GCancellable *cancellable,
                              GError **error)
@@ -2439,8 +2446,8 @@ static gboolean
 imap_transfer_offline (CamelFolder *source,
                        GPtrArray *uids,
                        CamelFolder *dest,
-                       GPtrArray **transferred_uids,
                        gboolean delete_originals,
+                       GPtrArray **transferred_uids,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -2758,8 +2765,8 @@ static gboolean
 imap_transfer_messages (CamelFolder *source,
                         GPtrArray *uids,
                         CamelFolder *dest,
-                        GPtrArray **transferred_uids,
                         gboolean delete_originals,
+                        GPtrArray **transferred_uids,
                         gboolean can_call_sync,
                         GCancellable *cancellable,
                         GError **error)
@@ -2774,8 +2781,8 @@ imap_transfer_messages (CamelFolder *source,
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
 		return imap_transfer_offline (
-			source, uids, dest, transferred_uids,
-			delete_originals, cancellable, error);
+			source, uids, dest, delete_originals,
+			transferred_uids, cancellable, error);
 
 	/* Sync message flags if needed. */
 	if (can_call_sync && !imap_synchronize_sync (
@@ -2806,22 +2813,22 @@ static gboolean
 imap_transfer_online (CamelFolder *source,
                       GPtrArray *uids,
                       CamelFolder *dest,
-                      GPtrArray **transferred_uids,
                       gboolean delete_originals,
+                      GPtrArray **transferred_uids,
                       GCancellable *cancellable,
                       GError **error)
 {
 	return imap_transfer_messages (
-		source, uids, dest, transferred_uids,
-		delete_originals, TRUE, cancellable, error);
+		source, uids, dest, delete_originals,
+		transferred_uids, TRUE, cancellable, error);
 }
 
 gboolean
 camel_imap_transfer_resyncing (CamelFolder *source,
                                GPtrArray *uids,
                                CamelFolder *dest,
-                               GPtrArray **transferred_uids,
                                gboolean delete_originals,
+                               GPtrArray **transferred_uids,
                                GCancellable *cancellable,
                                GError **error)
 {
@@ -3097,7 +3104,7 @@ get_content (CamelImapFolder *imap_folder,
 	if (camel_content_type_is (ci->type, "multipart", "signed")) {
 		CamelMultipartSigned *body_mp;
 		gchar *spec;
-		gint ret;
+		gboolean success;
 
 		/* Note: because we get the content parts uninterpreted anyway, we could potentially
 		   just use the normalmultipart code, except that multipart/signed wont let you yet! */
@@ -3116,10 +3123,10 @@ get_content (CamelImapFolder *imap_folder,
 
 		stream = camel_imap_folder_fetch_data (imap_folder, uid, spec, FALSE, cancellable, error);
 		if (stream) {
-			ret = camel_data_wrapper_construct_from_stream_sync (
+			success = camel_data_wrapper_construct_from_stream_sync (
 				CAMEL_DATA_WRAPPER (body_mp), stream, cancellable, error);
 			g_object_unref (CAMEL_OBJECT (stream));
-			if (ret == -1) {
+			if (!success) {
 				g_object_unref ( body_mp);
 				return NULL;
 			}
@@ -3154,13 +3161,13 @@ get_content (CamelImapFolder *imap_folder,
 			sprintf (child_spec + speclen, "%d.MIME", num++);
 			stream = camel_imap_folder_fetch_data (imap_folder, uid, child_spec, FALSE, cancellable, error);
 			if (stream) {
-				gint ret;
+				gboolean success;
 
 				part = camel_mime_part_new ();
-				ret = camel_data_wrapper_construct_from_stream_sync (
+				success = camel_data_wrapper_construct_from_stream_sync (
 					CAMEL_DATA_WRAPPER (part), stream, cancellable, error);
 				g_object_unref (CAMEL_OBJECT (stream));
-				if (ret == -1) {
+				if (!success) {
 					g_object_unref (CAMEL_OBJECT (part));
 					g_object_unref (CAMEL_OBJECT (body_mp));
 					g_free (child_spec);
@@ -3244,7 +3251,7 @@ get_message (CamelImapFolder *imap_folder,
 	CamelMimeMessage *msg;
 	CamelStream *stream;
 	gchar *section_text, *part_spec;
-	gint ret;
+	gboolean success;
 
 	folder = CAMEL_FOLDER (imap_folder);
 	parent_store = camel_folder_get_parent_store (folder);
@@ -3262,10 +3269,10 @@ get_message (CamelImapFolder *imap_folder,
 		return NULL;
 
 	msg = camel_mime_message_new ();
-	ret = camel_data_wrapper_construct_from_stream_sync (
+	success = camel_data_wrapper_construct_from_stream_sync (
 		CAMEL_DATA_WRAPPER (msg), stream, cancellable, error);
 	g_object_unref (CAMEL_OBJECT (stream));
-	if (ret == -1) {
+	if (!success) {
 		g_object_unref (CAMEL_OBJECT (msg));
 		return NULL;
 	}
@@ -3302,7 +3309,7 @@ get_message_simple (CamelImapFolder *imap_folder,
                     GError **error)
 {
 	CamelMimeMessage *msg;
-	gint ret;
+	gboolean success;
 
 	if (!stream) {
 		stream = camel_imap_folder_fetch_data (imap_folder, uid, "",
@@ -3312,10 +3319,10 @@ get_message_simple (CamelImapFolder *imap_folder,
 	}
 
 	msg = camel_mime_message_new ();
-	ret = camel_data_wrapper_construct_from_stream_sync (
+	success = camel_data_wrapper_construct_from_stream_sync (
 		CAMEL_DATA_WRAPPER (msg), stream, cancellable, error);
 	g_object_unref (CAMEL_OBJECT (stream));
-	if (ret == -1) {
+	if (!success) {
 		g_prefix_error (error, _("Unable to retrieve message: "));
 		g_object_unref (CAMEL_OBJECT (msg));
 		return NULL;
@@ -3730,8 +3737,8 @@ add_message_from_data (CamelFolder *folder,
 		g_ptr_array_set_size (messages, seq - first + 1);
 
 	msg = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync (
-		CAMEL_DATA_WRAPPER (msg), stream, cancellable, NULL) == -1) {
+	if (!camel_data_wrapper_construct_from_stream_sync (
+		CAMEL_DATA_WRAPPER (msg), stream, cancellable, NULL)) {
 		g_object_unref (CAMEL_OBJECT (msg));
 		return;
 	}
@@ -3907,7 +3914,7 @@ imap_update_summary (CamelFolder *folder,
 		return FALSE;
 	}
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable,
 		_("Fetching summary information for new messages in %s"),
 		camel_folder_get_name (folder));
@@ -3954,7 +3961,7 @@ imap_update_summary (CamelFolder *folder,
 		g_ptr_array_add (fetch_data, data);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) {
 		if (type != CAMEL_IMAP_RESPONSE_ERROR && type != CAMEL_IMAP_RESPONSE_TAGGED)
@@ -3989,7 +3996,7 @@ imap_update_summary (CamelFolder *folder,
 		qsort (needheaders->pdata, needheaders->len,
 		       sizeof (gpointer), uid_compar);
 
-		camel_operation_start (
+		camel_operation_push_message (
 			cancellable,
 			_("Fetching summary information for new messages in %s"),
 			camel_folder_get_name (folder));
@@ -4000,7 +4007,7 @@ imap_update_summary (CamelFolder *folder,
 						       "UID FETCH %s BODYSTRUCTURE BODY.PEEK[%s]",
 						       uidset, header_spec->str)) {
 				g_ptr_array_free (needheaders, TRUE);
-				camel_operation_end (cancellable);
+				camel_operation_pop_message (cancellable);
 				g_free (uidset);
 				g_string_free (header_spec, TRUE);
 				goto lose;
@@ -4028,7 +4035,7 @@ imap_update_summary (CamelFolder *folder,
 
 			if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) {
 				g_ptr_array_free (needheaders, TRUE);
-				camel_operation_end (cancellable);
+				camel_operation_pop_message (cancellable);
 
 				if (type != CAMEL_IMAP_RESPONSE_ERROR && type != CAMEL_IMAP_RESPONSE_TAGGED)
 					camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
@@ -4038,7 +4045,7 @@ imap_update_summary (CamelFolder *folder,
 		}
 		g_string_free (header_spec, TRUE);
 		g_ptr_array_free (needheaders, TRUE);
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 	}
 
 	/* Now finish up summary entries (fix UIDs, set flags and size) */
diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h
index e24bd96..7ea9711 100644
--- a/camel/providers/imap/camel-imap-folder.h
+++ b/camel/providers/imap/camel-imap-folder.h
@@ -102,15 +102,15 @@ CamelStream *	camel_imap_folder_fetch_data	(CamelImapFolder *imap_folder,
 						 GError **error);
 gboolean	camel_imap_append_resyncing	(CamelFolder *folder,
 						 CamelMimeMessage *message,
-						 const CamelMessageInfo *info,
+						 CamelMessageInfo *info,
 						 gchar **appended_uid,
 						 GCancellable *cancellable,
 						 GError **error);
 gboolean	camel_imap_transfer_resyncing	(CamelFolder *source,
 						 GPtrArray *uids,
 						 CamelFolder *dest,
-						 GPtrArray **transferred_uids,
 						 gboolean delete_originals,
+						 GPtrArray **transferred_uids,
 						 GCancellable *cancellable,
 						 GError **error);
 gboolean	camel_imap_expunge_uids_resyncing
diff --git a/camel/providers/imap/camel-imap-journal.c b/camel/providers/imap/camel-imap-journal.c
index cd6f74f..d94b522 100644
--- a/camel/providers/imap/camel-imap-journal.c
+++ b/camel/providers/imap/camel-imap-journal.c
@@ -370,7 +370,7 @@ imap_entry_play (CamelOfflineJournal *journal,
 
 		if (!camel_imap_transfer_resyncing (
 			journal->folder, imap_entry->uids, destination,
-			&ret_uids, imap_entry->move, cancellable, error))
+			imap_entry->move, &ret_uids, cancellable, error))
 			return -1;
 
 		if (ret_uids) {
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index bf5595a..02457cb 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -278,7 +278,7 @@ imapx_search_by_expression (CamelFolder *folder, const gchar *expression, GError
 static gboolean
 imapx_append_message_sync (CamelFolder *folder,
                            CamelMimeMessage *message,
-                           const CamelMessageInfo *info,
+                           CamelMessageInfo *info,
                            gchar **appended_uid,
                            GCancellable *cancellable,
                            GError **error)
@@ -399,8 +399,8 @@ imapx_get_message_sync (CamelFolder *folder,
 		msg = camel_mime_message_new ();
 
 		g_mutex_lock (ifolder->stream_lock);
-		if (camel_data_wrapper_construct_from_stream_sync (
-			(CamelDataWrapper *)msg, stream, cancellable, error) == -1) {
+		if (!camel_data_wrapper_construct_from_stream_sync (
+			(CamelDataWrapper *)msg, stream, cancellable, error)) {
 			g_object_unref (msg);
 			msg = NULL;
 		}
@@ -521,8 +521,8 @@ static gboolean
 imapx_transfer_messages_to_sync (CamelFolder *source,
                                  GPtrArray *uids,
                                  CamelFolder *dest,
-                                 GPtrArray **transferred_uids,
                                  gboolean delete_originals,
+                                 GPtrArray **transferred_uids,
                                  GCancellable *cancellable,
                                  GError **error)
 {
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index f2bf917..2776d02 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -3847,7 +3847,7 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
 
 		/* If we have any new messages, download their headers, but only a few (100?) at a time */
 		if (fetch_new) {
-			camel_operation_start (
+			camel_operation_push_message (
 				job->cancellable,
 				_("Fetching summary information for new messages in %s"),
 				camel_folder_get_name (job->folder));
@@ -3889,7 +3889,7 @@ imapx_job_scan_changes_start (CamelIMAPXServer *is,
 {
 	CamelIMAPXCommand *ic;
 
-	camel_operation_start (
+	camel_operation_push_message (
 		job->cancellable,
 		_("Scanning for changed messages in %s"),
 		camel_folder_get_name (job->folder));
@@ -3974,7 +3974,7 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is,
 	} else
 		uid = g_strdup ("1");
 
-	camel_operation_start (
+	camel_operation_push_message (
 		job->cancellable,
 		_("Fetching summary information for new messages in %s"),
 		camel_folder_get_name (folder));
diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c
index 57f322f..764b1ee 100644
--- a/camel/providers/local/camel-maildir-folder.c
+++ b/camel/providers/local/camel-maildir-folder.c
@@ -114,7 +114,7 @@ maildir_folder_get_filename (CamelFolder *folder,
 static gboolean
 maildir_folder_append_message_sync (CamelFolder *folder,
                                     CamelMimeMessage *message,
-                                    const CamelMessageInfo *info,
+                                    CamelMessageInfo *info,
                                     gchar **appended_uid,
                                     GCancellable *cancellable,
                                     GError **error)
@@ -253,9 +253,9 @@ maildir_folder_get_message_sync (CamelFolder *folder,
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync (
+	if (!camel_data_wrapper_construct_from_stream_sync (
 		(CamelDataWrapper *)message,
-		message_stream, cancellable, error) == -1) {
+		message_stream, cancellable, error)) {
 		g_prefix_error (
 			error, _("Cannot get message %s from folder %s: "),
 			uid, lf->folder_path);
@@ -281,8 +281,8 @@ static gboolean
 maildir_folder_transfer_messages_to_sync (CamelFolder *source,
                                           GPtrArray *uids,
                                           CamelFolder *dest,
-                                          GPtrArray **transferred_uids,
                                           gboolean delete_originals,
+                                          GPtrArray **transferred_uids,
                                           GCancellable *cancellable,
                                           GError **error)
 {
@@ -293,7 +293,8 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
 		CamelLocalFolder *lf = (CamelLocalFolder *) source;
 		CamelLocalFolder *df = (CamelLocalFolder *) dest;
 
-		camel_operation_start (cancellable, _("Moving messages"));
+		camel_operation_push_message (
+			cancellable, _("Moving messages"));
 
 		camel_folder_freeze (dest);
 		camel_folder_freeze (source);
@@ -346,7 +347,7 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
 		camel_folder_thaw (source);
 		camel_folder_thaw (dest);
 
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 	} else
 		fallback = TRUE;
 
@@ -356,8 +357,8 @@ maildir_folder_transfer_messages_to_sync (CamelFolder *source,
 		/* Chain up to parent's transfer_messages_to() method. */
 		folder_class = CAMEL_FOLDER_CLASS (camel_maildir_folder_parent_class);
 		return folder_class->transfer_messages_to_sync (
-			source, uids, dest, transferred_uids,
-			delete_originals, cancellable, error);
+			source, uids, dest, delete_originals,
+			transferred_uids, cancellable, error);
 	}
 
 	return TRUE;
diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c
index dca9bb8..7ad3e24 100644
--- a/camel/providers/local/camel-maildir-summary.c
+++ b/camel/providers/local/camel-maildir-summary.c
@@ -552,7 +552,8 @@ maildir_summary_check (CamelLocalSummary *cls,
 
 	d(printf("checking summary ...\n"));
 
-	camel_operation_start (cancellable, _("Checking folder consistency"));
+	camel_operation_push_message (
+		cancellable, _("Checking folder consistency"));
 
 	/* scan the directory, check for mail files not in the index, or index entries that
 	   no longer exist */
@@ -565,7 +566,7 @@ maildir_summary_check (CamelLocalSummary *cls,
 			cls->folder_path, g_strerror (errno));
 		g_free (cur);
 		g_free (new);
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		g_mutex_unlock (((CamelMaildirSummary *) cls)->priv->summary_lock);
 		return -1;
 	}
@@ -642,9 +643,10 @@ maildir_summary_check (CamelLocalSummary *cls,
 	g_hash_table_foreach (left, (GHFunc)remove_summary, &rd);
 	g_hash_table_destroy (left);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
-	camel_operation_start (cancellable, _("Checking for new messages"));
+	camel_operation_push_message (
+		cancellable, _("Checking for new messages"));
 
 	/* now, scan new for new messages, and copy them to cur, and so forth */
 	dir = opendir (new);
@@ -704,7 +706,8 @@ maildir_summary_check (CamelLocalSummary *cls,
 			g_free (src);
 			g_free (dest);
 		}
-		camel_operation_end (cancellable);
+
+		camel_operation_pop_message (cancellable);
 		closedir (dir);
 	}
 
@@ -736,7 +739,7 @@ maildir_summary_sync (CamelLocalSummary *cls,
 	if (camel_local_summary_check (cls, changes, cancellable, error) == -1)
 		return -1;
 
-	camel_operation_start (cancellable, _("Storing folder"));
+	camel_operation_push_message (cancellable, _("Storing folder"));
 
 	camel_folder_summary_prepare_fetch_all ((CamelFolderSummary *)cls, error);
 	count = camel_folder_summary_count ((CamelFolderSummary *)cls);
@@ -792,7 +795,7 @@ maildir_summary_sync (CamelLocalSummary *cls,
 		camel_message_info_free (info);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	/* Chain up to parent's sync() method. */
 	local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (camel_maildir_summary_parent_class);
diff --git a/camel/providers/local/camel-mbox-folder.c b/camel/providers/local/camel-mbox-folder.c
index 32abf33..8174904 100644
--- a/camel/providers/local/camel-mbox-folder.c
+++ b/camel/providers/local/camel-mbox-folder.c
@@ -138,7 +138,7 @@ fail:
 static gboolean
 mbox_folder_append_message_sync (CamelFolder *folder,
                                  CamelMimeMessage *message,
-                                 const CamelMessageInfo *info,
+                                 CamelMessageInfo *info,
                                  gchar **appended_uid,
                                  GCancellable *cancellable,
                                  GError **error)
@@ -380,8 +380,8 @@ retry:
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_mime_part_construct_from_parser_sync (
-		(CamelMimePart *)message, parser, cancellable, error) == -1) {
+	if (!camel_mime_part_construct_from_parser_sync (
+		(CamelMimePart *)message, parser, cancellable, error)) {
 		g_prefix_error (
 			error, _("Cannot get message %s from folder %s: "),
 			uid, lf->folder_path);
diff --git a/camel/providers/local/camel-mbox-summary.c b/camel/providers/local/camel-mbox-summary.c
index 86d0562..5ce1476 100644
--- a/camel/providers/local/camel-mbox-summary.c
+++ b/camel/providers/local/camel-mbox-summary.c
@@ -469,7 +469,7 @@ summary_update (CamelLocalSummary *cls,
 
 	cls->index_force = FALSE;
 
-	camel_operation_start (cancellable, _("Storing folder"));
+	camel_operation_push_message (cancellable, _("Storing folder"));
 
 	fd = g_open (cls->folder_path, O_LARGEFILE | O_RDONLY | O_BINARY, 0);
 	if (fd == -1) {
@@ -479,7 +479,7 @@ summary_update (CamelLocalSummary *cls,
 			g_io_error_from_errno (errno),
 			_("Could not open folder: %s: %s"),
 			cls->folder_path, g_strerror (errno));
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return -1;
 	}
 
@@ -598,7 +598,7 @@ summary_update (CamelLocalSummary *cls,
 		}
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return ok;
 }
@@ -691,7 +691,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs,
 
 	d(printf("performing full summary/sync\n"));
 
-	camel_operation_start (cancellable, _("Storing folder"));
+	camel_operation_push_message (cancellable, _("Storing folder"));
 
 	fd = g_open (cls->folder_path, O_LARGEFILE | O_RDONLY | O_BINARY, 0);
 	if (fd == -1) {
@@ -700,7 +700,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs,
 			g_io_error_from_errno (errno),
 			_("Could not open file: %s: %s"),
 			cls->folder_path, g_strerror (errno));
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return -1;
 	}
 
@@ -763,7 +763,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs,
 	}
 	tmpname = NULL;
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return 0;
  error:
@@ -776,7 +776,7 @@ mbox_summary_sync_full (CamelMboxSummary *mbs,
 	if (tmpname)
 		g_unlink (tmpname);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return -1;
 }
@@ -827,7 +827,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
 
 	d(printf("Performing quick summary sync\n"));
 
-	camel_operation_start (cancellable, _("Storing folder"));
+	camel_operation_push_message (cancellable, _("Storing folder"));
 
 	fd = g_open (cls->folder_path, O_LARGEFILE|O_RDWR|O_BINARY, 0);
 	if (fd == -1) {
@@ -837,7 +837,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
 			_("Could not open file: %s: %s"),
 			cls->folder_path, g_strerror (errno));
 
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return -1;
 	}
 
@@ -960,7 +960,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
 	g_ptr_array_free (summary, TRUE);
 	g_object_unref (mp);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 	camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
 	return 0;
@@ -974,7 +974,7 @@ mbox_summary_sync_quick (CamelMboxSummary *mbs,
 	if (info)
 		camel_message_info_free ((CamelMessageInfo *)info);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 	camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
 	return -1;
diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c
index a005a13..59147ef 100644
--- a/camel/providers/local/camel-mh-folder.c
+++ b/camel/providers/local/camel-mh-folder.c
@@ -55,7 +55,7 @@ mh_folder_get_filename (CamelFolder *folder,
 static gboolean
 mh_folder_append_message_sync (CamelFolder *folder,
                                CamelMimeMessage *message,
-                               const CamelMessageInfo *info,
+                               CamelMessageInfo *info,
                                gchar **appended_uid,
                                GCancellable *cancellable,
                                GError **error)
@@ -171,9 +171,9 @@ mh_folder_get_message_sync (CamelFolder *folder,
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync (
+	if (!camel_data_wrapper_construct_from_stream_sync (
 		(CamelDataWrapper *)message,
-		message_stream, cancellable, error) == -1) {
+		message_stream, cancellable, error)) {
 		g_prefix_error (
 			error, _("Cannot get message %s from folder %s: "),
 			name, lf->folder_path);
diff --git a/camel/providers/local/camel-spool-summary.c b/camel/providers/local/camel-spool-summary.c
index 30fc168..3dbf398 100644
--- a/camel/providers/local/camel-spool-summary.c
+++ b/camel/providers/local/camel-spool-summary.c
@@ -128,7 +128,7 @@ spool_summary_sync_full (CamelMboxSummary *cls,
 
 	d(printf("performing full summary/sync\n"));
 
-	camel_operation_start (cancellable, _("Storing folder"));
+	camel_operation_push_message (cancellable, _("Storing folder"));
 
 	fd = open (((CamelLocalSummary *)cls)->folder_path, O_RDWR|O_LARGEFILE);
 	if (fd == -1) {
@@ -138,7 +138,7 @@ spool_summary_sync_full (CamelMboxSummary *cls,
 			_("Could not open file: %s: %s"),
 			((CamelLocalSummary *)cls)->folder_path,
 			g_strerror (errno));
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return -1;
 	}
 
@@ -286,7 +286,7 @@ spool_summary_sync_full (CamelMboxSummary *cls,
 	if (tmpname[0] != '\0')
 		unlink (tmpname);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return 0;
  error:
@@ -299,7 +299,7 @@ spool_summary_sync_full (CamelMboxSummary *cls,
 	if (tmpname[0] != '\0')
 		unlink (tmpname);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return -1;
 }
diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c
index 450b903..5c0e1b3 100644
--- a/camel/providers/nntp/camel-nntp-folder.c
+++ b/camel/providers/nntp/camel-nntp-folder.c
@@ -414,7 +414,7 @@ nntp_folder_get_message_sync (CamelFolder *folder,
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error) == -1) {
+	if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) message, stream, cancellable, error)) {
 		g_prefix_error (error, _("Cannot get message %s: "), uid);
 		g_object_unref (message);
 		message = NULL;
diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c
index 1076171..68129a7 100644
--- a/camel/providers/nntp/camel-nntp-summary.c
+++ b/camel/providers/nntp/camel-nntp-summary.c
@@ -241,7 +241,7 @@ add_range_xover (CamelNNTPSummary *cns,
 	s = (CamelFolderSummary *)cns;
 	summary_table = camel_folder_summary_get_hashtable (s);
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable, _("%s: Scanning new messages"),
 		((CamelService *)store)->url->host);
 
@@ -250,7 +250,7 @@ add_range_xover (CamelNNTPSummary *cns,
 		ret = camel_nntp_raw_command_auth (store, cancellable, error, &line, "xover %r", low, high);
 
 	if (ret != 224) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		if (ret != -1)
 			g_set_error (
 				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
@@ -321,7 +321,7 @@ add_range_xover (CamelNNTPSummary *cns,
 		camel_header_raw_clear (&headers);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	camel_folder_summary_free_hashtable (summary_table);
 
@@ -352,7 +352,7 @@ add_range_head (CamelNNTPSummary *cns,
 
 	mp = camel_mime_parser_new ();
 
-	camel_operation_start (
+	camel_operation_push_message (
 		cancellable, _("%s: Scanning new messages"),
 		((CamelService *)store)->url->host);
 
@@ -426,7 +426,7 @@ ioerror:
 	}
 	g_object_unref (mp);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	camel_folder_summary_free_hashtable (summary_table);
 
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index 390fd77..fce90e9 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -338,7 +338,7 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 	/* Sigh, most of the crap in this function is so that the cancel button
 	   returns the proper exception code.  Sigh. */
 
-	camel_operation_start_transient (
+	camel_operation_push_message (
 		cancellable, _("Retrieving POP message %d"), fi->id);
 
 	/* If we have an oustanding retrieve message running, wait for that to complete
@@ -450,8 +450,8 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 	}
 
 	message = camel_mime_message_new ();
-	if (camel_data_wrapper_construct_from_stream_sync (
-		CAMEL_DATA_WRAPPER (message), stream, cancellable, error) == -1) {
+	if (!camel_data_wrapper_construct_from_stream_sync (
+		CAMEL_DATA_WRAPPER (message), stream, cancellable, error)) {
 		g_prefix_error (error, _("Cannot get message %s: "), uid);
 		g_object_unref (message);
 		message = NULL;
@@ -459,7 +459,7 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 done:
 	g_object_unref (stream);
 fail:
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return message;
 }
@@ -479,7 +479,8 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
 	parent_store = camel_folder_get_parent_store (folder);
 	pop3_store = CAMEL_POP3_STORE (parent_store);
 
-	camel_operation_start (cancellable, _("Retrieving POP summary"));
+	camel_operation_push_message (
+		cancellable, _("Retrieving POP summary"));
 
 	pop3_folder->uids = g_ptr_array_new ();
 	pop3_folder->uids_uid = g_hash_table_new (g_str_hash, g_str_equal);
@@ -528,7 +529,7 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
 	/* dont need this anymore */
 	g_hash_table_destroy (pop3_folder->uids_id);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return success;
 }
@@ -553,17 +554,22 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
 	if (pop3_store->delete_after && !expunge) {
 		d(printf("%s(%d): pop3_store->delete_after = [%d], expunge=[%d]\n",
 			 __FILE__, __LINE__, pop3_store->delete_after, expunge));
-		camel_operation_start (cancellable, _("Expunging old messages"));
+		camel_operation_push_message (
+			cancellable, _("Expunging old messages"));
+
 		camel_pop3_delete_old (
 			folder, pop3_store->delete_after,
 			cancellable, error);
+
+		camel_operation_pop_message (cancellable);
 	}
 
 	if (!expunge) {
 		return TRUE;
 	}
 
-	camel_operation_start (cancellable, _("Expunging deleted messages"));
+	camel_operation_push_message (
+		cancellable, _("Expunging deleted messages"));
 
 	for (i = 0; i < pop3_folder->uids->len; i++) {
 		fi = pop3_folder->uids->pdata[i];
@@ -602,7 +608,7 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
 			cancellable, (i+1) * 100 / pop3_folder->uids->len);
 	}
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	camel_pop3_store_expunge (pop3_store, error);
 
@@ -681,8 +687,8 @@ pop3_get_message_time_from_cache (CamelFolder *folder, const gchar *uid, time_t
 		CamelMimeMessage *message;
 
 		message = camel_mime_message_new ();
-		if (camel_data_wrapper_construct_from_stream_sync (
-			(CamelDataWrapper *)message, stream, NULL, NULL) == -1) {
+		if (!camel_data_wrapper_construct_from_stream_sync (
+			(CamelDataWrapper *)message, stream, NULL, NULL)) {
 			g_warning (_("Cannot get message %s: %s"), uid, g_strerror (errno));
 			g_object_unref (message);
 			message = NULL;
@@ -782,8 +788,6 @@ camel_pop3_delete_old (CamelFolder *folder,
 			cancellable, (i+1) * 100 / pop3_folder->uids->len);
 	}
 
-	camel_operation_end (cancellable);
-
 	camel_pop3_store_expunge (pop3_store, error);
 
 	return 0;
diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c
index 9f17160..2b17ec0 100644
--- a/camel/providers/smtp/camel-smtp-transport.c
+++ b/camel/providers/smtp/camel-smtp-transport.c
@@ -614,7 +614,7 @@ smtp_send_to_sync (CamelTransport *transport,
 		return FALSE;
 	}
 
-	camel_operation_start (cancellable, _("Sending message"));
+	camel_operation_push_message (cancellable, _("Sending message"));
 
 	/* find out if the message has 8bit mime parts */
 	has_8bit_parts = camel_mime_message_has_8bit_parts (message);
@@ -623,7 +623,7 @@ smtp_send_to_sync (CamelTransport *transport,
 	   you'll be sending an 8bit mime message at "MAIL FROM:" time. */
 	if (!smtp_mail (
 		smtp_transport, addr, has_8bit_parts, cancellable, error)) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return FALSE;
 	}
 
@@ -632,7 +632,7 @@ smtp_send_to_sync (CamelTransport *transport,
 		g_set_error (
 			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 			_("Cannot send message: no recipients defined."));
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return FALSE;
 	}
 
@@ -645,28 +645,28 @@ smtp_send_to_sync (CamelTransport *transport,
 				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 				_("Cannot send message: "
 				  "one or more invalid recipients"));
-			camel_operation_end (cancellable);
+			camel_operation_pop_message (cancellable);
 			return FALSE;
 		}
 
 		enc = camel_internet_address_encode_address (NULL, NULL, addr);
 		if (!smtp_rcpt (smtp_transport, enc, cancellable, error)) {
 			g_free (enc);
-			camel_operation_end (cancellable);
+			camel_operation_pop_message (cancellable);
 			return FALSE;
 		}
 		g_free (enc);
 	}
 
 	if (!smtp_data (smtp_transport, message, cancellable, error)) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		return FALSE;
 	}
 
 	/* reset the service for our next transfer session */
 	smtp_rset (smtp_transport, cancellable, NULL);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return TRUE;
 }
@@ -1011,7 +1011,7 @@ smtp_helo (CamelSmtpTransport *transport,
 		transport->authtypes = NULL;
 	}
 
-	camel_operation_start_transient (cancellable, _("SMTP Greeting"));
+	camel_operation_push_message (cancellable, _("SMTP Greeting"));
 
 	addr = transport->localaddr;
 	addrlen = transport->localaddrlen;
@@ -1039,7 +1039,7 @@ smtp_helo (CamelSmtpTransport *transport,
 		transport->ostream, cmdbuf, cancellable, error) == -1) {
 		g_free (cmdbuf);
 		g_prefix_error (error, _("HELO command failed: "));
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 
 		camel_service_disconnect_sync (
 			(CamelService *) transport, FALSE, NULL);
@@ -1057,14 +1057,14 @@ smtp_helo (CamelSmtpTransport *transport,
 		if (respbuf == NULL) {
 			g_prefix_error (error, _("HELO command failed: "));
 			transport->connected = FALSE;
-			camel_operation_end (cancellable);
+			camel_operation_pop_message (cancellable);
 			return FALSE;
 		}
 		if (strncmp (respbuf, "250", 3)) {
 			smtp_set_error (
 				transport, respbuf, cancellable, error);
 			g_prefix_error (error, _("HELO command failed: "));
-			camel_operation_end (cancellable);
+			camel_operation_pop_message (cancellable);
 			g_free (respbuf);
 			return FALSE;
 		}
@@ -1113,7 +1113,7 @@ smtp_helo (CamelSmtpTransport *transport,
 	} while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
 	g_free (respbuf);
 
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	return TRUE;
 }
@@ -1131,11 +1131,11 @@ smtp_auth (CamelSmtpTransport *transport,
 
 	service = CAMEL_SERVICE (transport);
 
-	camel_operation_start_transient (cancellable, _("SMTP Authentication"));
+	camel_operation_push_message (cancellable, _("SMTP Authentication"));
 
 	sasl = camel_sasl_new ("smtp", mech, service);
 	if (!sasl) {
-		camel_operation_end (cancellable);
+		camel_operation_pop_message (cancellable);
 		g_set_error (
 			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 			_("Error creating SASL authentication object."));
@@ -1242,7 +1242,7 @@ smtp_auth (CamelSmtpTransport *transport,
 	}
 
 	g_object_unref (sasl);
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	g_free (respbuf);
 
@@ -1258,7 +1258,7 @@ smtp_auth (CamelSmtpTransport *transport,
 
  lose:
 	g_object_unref (sasl);
-	camel_operation_end (cancellable);
+	camel_operation_pop_message (cancellable);
 
 	g_free (respbuf);
 
diff --git a/docs/reference/camel/camel-docs.sgml b/docs/reference/camel/camel-docs.sgml
index eb472fe..d20d7a0 100644
--- a/docs/reference/camel/camel-docs.sgml
+++ b/docs/reference/camel/camel-docs.sgml
@@ -207,6 +207,10 @@
       <title>Index of deprecated symbols</title>
       <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
     </index>
+    <index id="api-index-2.34" role="2.34">
+      <title>Index of new symbols in 2.34</title>
+      <xi:include href="xml/api-index-2.34.xml"><xi:fallback /></xi:include>
+    </index>
     <index id="api-index-2.32" role="2.32">
       <title>Index of new symbols in 2.32</title>
       <xi:include href="xml/api-index-2.32.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 0d18659..c80d562 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -139,14 +139,26 @@ camel_cipher_validity_encrypt_t
 camel_cipher_validity_mode_t
 camel_cipher_context_new
 camel_cipher_context_get_session
-camel_cipher_id_to_hash
-camel_cipher_hash_to_id
-camel_cipher_sign_sync
-camel_cipher_verify_sync
-camel_cipher_encrypt_sync
-camel_cipher_decrypt_sync
-camel_cipher_import_keys_sync
-camel_cipher_export_keys_sync
+camel_cipher_context_id_to_hash
+camel_cipher_context_hash_to_id
+camel_cipher_context_sign_sync
+camel_cipher_context_sign
+camel_cipher_context_sign_finish
+camel_cipher_context_verify_sync
+camel_cipher_context_verify
+camel_cipher_context_verify_finish
+camel_cipher_context_encrypt_sync
+camel_cipher_context_encrypt
+camel_cipher_context_encrypt_finish
+camel_cipher_context_decrypt_sync
+camel_cipher_context_decrypt
+camel_cipher_context_decrypt_finish
+camel_cipher_context_import_keys_sync
+camel_cipher_context_import_keys
+camel_cipher_context_import_keys_finish
+camel_cipher_context_export_keys_sync
+camel_cipher_context_export_keys
+camel_cipher_context_export_keys_finish
 camel_cipher_validity_new
 camel_cipher_validity_init
 camel_cipher_validity_get_valid
@@ -210,8 +222,14 @@ camel_data_wrapper_get_mime_type_field
 camel_data_wrapper_set_mime_type_field
 camel_data_wrapper_is_offline
 camel_data_wrapper_write_to_stream_sync
+camel_data_wrapper_write_to_stream
+camel_data_wrapper_write_to_stream_finish
 camel_data_wrapper_decode_to_stream_sync
+camel_data_wrapper_decode_to_stream
+camel_data_wrapper_decode_to_stream_finish
 camel_data_wrapper_construct_from_stream_sync
+camel_data_wrapper_construct_from_stream
+camel_data_wrapper_construct_from_stream_finish
 CamelDataWrapperLock
 camel_data_wrapper_lock
 camel_data_wrapper_unlock
@@ -467,12 +485,26 @@ camel_folder_free_shallow
 camel_folder_free_deep
 camel_folder_get_filename
 camel_folder_append_message_sync
+camel_folder_append_message
+camel_folder_append_message_finish
 camel_folder_expunge_sync
+camel_folder_expunge
+camel_folder_expunge_finish
 camel_folder_get_message_sync
+camel_folder_get_message
+camel_folder_get_message_finish
 camel_folder_refresh_info_sync
+camel_folder_refresh_info
+camel_folder_refresh_info_finish
 camel_folder_synchronize_sync
+camel_folder_synchronize
+camel_folder_synchronize_finish
 camel_folder_synchronize_message_sync
+camel_folder_synchronize_message
+camel_folder_synchronize_message_finish
 camel_folder_transfer_messages_to_sync
+camel_folder_transfer_messages_to
+camel_folder_transfer_messages_to_finish
 camel_folder_change_info_new
 camel_folder_change_info_clear
 camel_folder_change_info_free
@@ -1244,6 +1276,7 @@ camel_mime_message_get_part_by_content_id
 camel_mime_message_build_mbox_from
 camel_mime_message_has_attachment
 camel_mime_message_dump
+camel_mime_message_build_preview
 <SUBSECTION Standard>
 CAMEL_MIME_MESSAGE
 CAMEL_IS_MIME_MESSAGE
@@ -1327,10 +1360,10 @@ camel_mime_part_get_content_languages
 camel_mime_part_set_content_type
 camel_mime_part_get_content_type
 camel_mime_part_construct_from_parser_sync
+camel_mime_part_construct_from_parser
+camel_mime_part_construct_from_parser_finish
 camel_mime_part_set_content
-camel_mime_part_get_content_size
 camel_mime_part_construct_content_from_parser
-camel_mime_message_build_preview
 <SUBSECTION Standard>
 CAMEL_MIME_PART
 CAMEL_IS_MIME_PART
@@ -1487,6 +1520,8 @@ CamelOfflineFolder
 camel_offline_folder_get_offline_sync
 camel_offline_folder_set_offline_sync
 camel_offline_folder_downsync_sync
+camel_offline_folder_downsync
+camel_offline_folder_downsync_finish
 <SUBSECTION Standard>
 CAMEL_OFFLINE_FOLDER
 CAMEL_IS_OFFLINE_FOLDER
@@ -1599,10 +1634,9 @@ camel_operation_uncancel
 camel_operation_cancel_check
 camel_operation_cancel_fd
 camel_operation_cancel_prfd
-camel_operation_start
-camel_operation_start_transient
+camel_operation_push_message
+camel_operation_pop_message
 camel_operation_progress
-camel_operation_end
 <SUBSECTION Standard>
 CAMEL_OPERATION
 CAMEL_IS_OPERATION
@@ -1839,7 +1873,11 @@ camel_sasl_get_mechanism
 camel_sasl_get_service
 camel_sasl_get_service_name
 camel_sasl_challenge_sync
+camel_sasl_challenge
+camel_sasl_challenge_finish
 camel_sasl_challenge_base64_sync
+camel_sasl_challenge_base64
+camel_sasl_challenge_base64_finish
 camel_sasl_authtype_list
 camel_sasl_authtype
 <SUBSECTION Standard>
@@ -2128,17 +2166,41 @@ CamelStoreLock
 camel_store_lock
 camel_store_unlock
 camel_store_get_folder_sync
+camel_store_get_folder
+camel_store_get_folder_finish
 camel_store_get_folder_info_sync
+camel_store_get_folder_info
+camel_store_get_folder_info_finish
 camel_store_get_inbox_folder_sync
+camel_store_get_inbox_folder
+camel_store_get_inbox_folder_finish
 camel_store_get_junk_folder_sync
+camel_store_get_junk_folder
+camel_store_get_junk_folder_finish
 camel_store_get_trash_folder_sync
+camel_store_get_trash_folder
+camel_store_get_trash_folder_finish
 camel_store_create_folder_sync
+camel_store_create_folder
+camel_store_create_folder_finish
 camel_store_delete_folder_sync
+camel_store_delete_folder
+camel_store_delete_folder_finish
 camel_store_rename_folder_sync
+camel_store_rename_folder
+camel_store_rename_folder_finish
 camel_store_subscribe_folder_sync
+camel_store_subscribe_folder
+camel_store_subscribe_folder_finish
 camel_store_unsubscribe_folder_sync
+camel_store_unsubscribe_folder
+camel_store_unsubscribe_folder_finish
 camel_store_synchronize_sync
+camel_store_synchronize
+camel_store_synchronize_finish
 camel_store_noop_sync
+camel_store_noop
+camel_store_noop_finish
 <SUBSECTION Standard>
 CAMEL_STORE
 CAMEL_IS_STORE
@@ -2459,10 +2521,12 @@ camel_text_index_name_get_type
 <FILE>camel-transport</FILE>
 <TITLE>CamelTransport</TITLE>
 CamelTransport
-camel_transport_send_to_sync
 CamelTransportLock
 camel_transport_lock
 camel_transport_unlock
+camel_transport_send_to_sync
+camel_transport_send_to
+camel_transport_send_to_finish
 <SUBSECTION Standard>
 CAMEL_TRANSPORT
 CAMEL_IS_TRANSPORT
diff --git a/docs/reference/camel/tmpl/camel-cipher-context.sgml b/docs/reference/camel/tmpl/camel-cipher-context.sgml
index 1068c8f..aa30635 100644
--- a/docs/reference/camel/tmpl/camel-cipher-context.sgml
+++ b/docs/reference/camel/tmpl/camel-cipher-context.sgml
@@ -116,7 +116,7 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_id_to_hash ##### -->
+<!-- ##### FUNCTION camel_cipher_context_id_to_hash ##### -->
 <para>
 
 </para>
@@ -126,7 +126,7 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_hash_to_id ##### -->
+<!-- ##### FUNCTION camel_cipher_context_hash_to_id ##### -->
 <para>
 
 </para>
@@ -136,7 +136,7 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_sign_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_sign_sync ##### -->
 <para>
 
 </para>
@@ -151,19 +151,70 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_verify_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_sign ##### -->
 <para>
 
 </para>
 
 @context: 
+ userid: 
+ hash: 
 @ipart: 
+ opart: 
+ io_priority: 
 @cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_sign_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_verify_sync ##### -->
+<para>
+
+</para>
+
+ context: 
+ ipart: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_verify ##### -->
+<para>
+
+</para>
+
+ context: 
+ ipart: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_verify_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
 @error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_encrypt_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_encrypt_sync ##### -->
 <para>
 
 </para>
@@ -178,7 +229,34 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_decrypt_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_encrypt ##### -->
+<para>
+
+</para>
+
+ context: 
+ userid: 
+ recipients: 
+ ipart: 
+ opart: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_encrypt_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_decrypt_sync ##### -->
 <para>
 
 </para>
@@ -191,19 +269,68 @@ CamelCipherContext
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_import_keys_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_decrypt ##### -->
+<para>
+
+</para>
+
+ context: 
+ ipart: 
+ opart: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_decrypt_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_import_keys_sync ##### -->
+<para>
+
+</para>
+
+ context: 
+ istream: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_import_keys ##### -->
 <para>
 
 </para>
 
 @context: 
 @istream: 
+ io_priority: 
 @cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_import_keys_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
 @error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_cipher_export_keys_sync ##### -->
+<!-- ##### FUNCTION camel_cipher_context_export_keys_sync ##### -->
 <para>
 
 </para>
@@ -216,6 +343,31 @@ CamelCipherContext
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_cipher_context_export_keys ##### -->
+<para>
+
+</para>
+
+ context: 
+ keys: 
+ ostream: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_cipher_context_export_keys_finish ##### -->
+<para>
+
+</para>
+
+ context: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_cipher_validity_new ##### -->
 <para>
 
@@ -528,6 +680,44 @@ CamelCipherContext
 @gpointer cert_data: 
 @gpointer cert_data:
 @gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
+ gpointer cert_data:
+ gpointer cert_data: 
 @gpointer cert_data: 
 
 
diff --git a/docs/reference/camel/tmpl/camel-data-wrapper.sgml b/docs/reference/camel/tmpl/camel-data-wrapper.sgml
index a27a941..cb746fa 100644
--- a/docs/reference/camel/tmpl/camel-data-wrapper.sgml
+++ b/docs/reference/camel/tmpl/camel-data-wrapper.sgml
@@ -92,6 +92,30 @@ CamelDataWrapper
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_data_wrapper_write_to_stream ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ stream: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_data_wrapper_write_to_stream_finish ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_data_wrapper_decode_to_stream_sync ##### -->
 <para>
 
@@ -104,6 +128,30 @@ CamelDataWrapper
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_data_wrapper_decode_to_stream ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ stream: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_data_wrapper_decode_to_stream_finish ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_data_wrapper_construct_from_stream_sync ##### -->
 <para>
 
@@ -116,6 +164,30 @@ CamelDataWrapper
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_data_wrapper_construct_from_stream ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ stream: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_data_wrapper_construct_from_stream_finish ##### -->
+<para>
+
+</para>
+
+ data_wrapper: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### ENUM CamelDataWrapperLock ##### -->
 <para>
 
diff --git a/docs/reference/camel/tmpl/camel-db.sgml b/docs/reference/camel/tmpl/camel-db.sgml
index 08e58fa..be18b4d 100644
--- a/docs/reference/camel/tmpl/camel-db.sgml
+++ b/docs/reference/camel/tmpl/camel-db.sgml
@@ -82,9 +82,9 @@ CamelDB
 </para>
 
 @Param1: 
- Varargs: 
+ Param2: 
 @Param3: 
- Varargs: 
+ Param4: 
 @Param5: 
 @Returns: 
 
diff --git a/docs/reference/camel/tmpl/camel-folder-summary.sgml b/docs/reference/camel/tmpl/camel-folder-summary.sgml
index 5cdadca..9769acc 100644
--- a/docs/reference/camel/tmpl/camel-folder-summary.sgml
+++ b/docs/reference/camel/tmpl/camel-folder-summary.sgml
@@ -718,6 +718,7 @@ CamelFolderSummary
 </para>
 
 @info: 
+ Returns: 
 
 
 <!-- ##### FUNCTION camel_message_info_new_from_header ##### -->
diff --git a/docs/reference/camel/tmpl/camel-folder.sgml b/docs/reference/camel/tmpl/camel-folder.sgml
index 99b6483..4e52502 100644
--- a/docs/reference/camel/tmpl/camel-folder.sgml
+++ b/docs/reference/camel/tmpl/camel-folder.sgml
@@ -648,6 +648,32 @@ CamelFolder
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_append_message ##### -->
+<para>
+
+</para>
+
+ folder: 
+ message: 
+ info: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_append_message_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ appended_uid: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_expunge_sync ##### -->
 <para>
 
@@ -659,18 +685,65 @@ CamelFolder
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_expunge ##### -->
+<para>
+
+</para>
+
+ folder: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_expunge_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_get_message_sync ##### -->
 <para>
 
 </para>
 
 @folder: 
- uid: 
+ message_uid: 
 @cancellable: 
 @error: 
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_get_message ##### -->
+<para>
+
+</para>
+
+ folder: 
+ message_uid: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_get_message_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_refresh_info_sync ##### -->
 <para>
 
@@ -682,6 +755,29 @@ CamelFolder
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_refresh_info ##### -->
+<para>
+
+</para>
+
+ folder: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_refresh_info_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_synchronize_sync ##### -->
 <para>
 
@@ -694,29 +790,104 @@ CamelFolder
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_synchronize ##### -->
+<para>
+
+</para>
+
+ folder: 
+ expunge: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_synchronize_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_synchronize_message_sync ##### -->
 <para>
 
 </para>
 
 @folder: 
- uid: 
+ message_uid: 
 @cancellable: 
 @error: 
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_folder_synchronize_message ##### -->
+<para>
+
+</para>
+
+ folder: 
+ message_uid: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_synchronize_message_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_folder_transfer_messages_to_sync ##### -->
 <para>
 
 </para>
 
 @source: 
- uids: 
- dest: 
+ message_uids: 
+ destination: 
+ delete_originals: 
 @transferred_uids: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_folder_transfer_messages_to ##### -->
+<para>
+
+</para>
+
+ source: 
+ message_uids: 
+ destination: 
 @delete_originals: 
+ io_priority: 
 @cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_folder_transfer_messages_to_finish ##### -->
+<para>
+
+</para>
+
+ source: 
+ result: 
+ transferred_uids: 
 @error: 
 @Returns: 
 
diff --git a/docs/reference/camel/tmpl/camel-mime-message.sgml b/docs/reference/camel/tmpl/camel-mime-message.sgml
index 8b91f07..dd7e37b 100644
--- a/docs/reference/camel/tmpl/camel-mime-message.sgml
+++ b/docs/reference/camel/tmpl/camel-mime-message.sgml
@@ -284,7 +284,17 @@ CamelMimeMessage
 
 </para>
 
- msg: 
+ message: 
 @body: 
 
 
+<!-- ##### FUNCTION camel_mime_message_build_preview ##### -->
+<para>
+
+</para>
+
+ mime_part: 
+ info: 
+ Returns: 
+
+
diff --git a/docs/reference/camel/tmpl/camel-mime-part.sgml b/docs/reference/camel/tmpl/camel-mime-part.sgml
index 55cad4b..28c7905 100644
--- a/docs/reference/camel/tmpl/camel-mime-part.sgml
+++ b/docs/reference/camel/tmpl/camel-mime-part.sgml
@@ -238,45 +238,50 @@ CamelMimePart
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_mime_part_set_content ##### -->
+<!-- ##### FUNCTION camel_mime_part_construct_from_parser ##### -->
 <para>
 
 </para>
 
 @mime_part: 
- data: 
- length: 
- type: 
+ parser: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
 
 
-<!-- ##### FUNCTION camel_mime_part_get_content_size ##### -->
+<!-- ##### FUNCTION camel_mime_part_construct_from_parser_finish ##### -->
 <para>
 
 </para>
 
 @mime_part: 
+ result: 
+ error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_mime_part_construct_content_from_parser ##### -->
+<!-- ##### FUNCTION camel_mime_part_set_content ##### -->
 <para>
 
 </para>
 
 @mime_part: 
- mp: 
- cancellable: 
- error: 
- Returns: 
+ data: 
+ length: 
+ type: 
 
 
-<!-- ##### FUNCTION camel_mime_message_build_preview ##### -->
+<!-- ##### FUNCTION camel_mime_part_construct_content_from_parser ##### -->
 <para>
 
 </para>
 
 @mime_part: 
- info: 
+ mp: 
+ cancellable: 
+ error: 
 @Returns: 
 
 
diff --git a/docs/reference/camel/tmpl/camel-offline-folder.sgml b/docs/reference/camel/tmpl/camel-offline-folder.sgml
index e84bfae..6c51d3a 100644
--- a/docs/reference/camel/tmpl/camel-offline-folder.sgml
+++ b/docs/reference/camel/tmpl/camel-offline-folder.sgml
@@ -36,7 +36,7 @@ CamelOfflineFolder
 
 </para>
 
- offline: 
+ folder: 
 @Returns: 
 
 
@@ -45,7 +45,7 @@ CamelOfflineFolder
 
 </para>
 
- offline: 
+ folder: 
 @offline_sync: 
 
 
@@ -54,10 +54,34 @@ CamelOfflineFolder
 
 </para>
 
- offline: 
+ folder: 
 @expression: 
 @cancellable: 
 @error: 
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_offline_folder_downsync ##### -->
+<para>
+
+</para>
+
+ folder: 
+ expression: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_offline_folder_downsync_finish ##### -->
+<para>
+
+</para>
+
+ folder: 
+ result: 
+ error: 
+ Returns: 
+
+
diff --git a/docs/reference/camel/tmpl/camel-operation.sgml b/docs/reference/camel/tmpl/camel-operation.sgml
index 3660bc7..1555b1b 100644
--- a/docs/reference/camel/tmpl/camel-operation.sgml
+++ b/docs/reference/camel/tmpl/camel-operation.sgml
@@ -80,24 +80,22 @@ camel-operation
 @Returns: 
 
 
-<!-- ##### FUNCTION camel_operation_start ##### -->
+<!-- ##### FUNCTION camel_operation_push_message ##### -->
 <para>
 
 </para>
 
 @cancellable: 
- what: 
+ format: 
 @Varargs: 
 
 
-<!-- ##### FUNCTION camel_operation_start_transient ##### -->
+<!-- ##### FUNCTION camel_operation_pop_message ##### -->
 <para>
 
 </para>
 
 @cancellable: 
- what: 
- Varargs: 
 
 
 <!-- ##### FUNCTION camel_operation_progress ##### -->
@@ -106,14 +104,6 @@ camel-operation
 </para>
 
 @cancellable: 
- pc: 
-
-
-<!-- ##### FUNCTION camel_operation_end ##### -->
-<para>
-
-</para>
-
- cancellable: 
+ percent: 
 
 
diff --git a/docs/reference/camel/tmpl/camel-sasl.sgml b/docs/reference/camel/tmpl/camel-sasl.sgml
index 9d4c81f..ab15851 100644
--- a/docs/reference/camel/tmpl/camel-sasl.sgml
+++ b/docs/reference/camel/tmpl/camel-sasl.sgml
@@ -114,6 +114,30 @@ CamelSasl
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_sasl_challenge ##### -->
+<para>
+
+</para>
+
+ sasl: 
+ token: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_sasl_challenge_finish ##### -->
+<para>
+
+</para>
+
+ sasl: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_sasl_challenge_base64_sync ##### -->
 <para>
 
@@ -126,6 +150,30 @@ CamelSasl
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_sasl_challenge_base64 ##### -->
+<para>
+
+</para>
+
+ sasl: 
+ token: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_sasl_challenge_base64_finish ##### -->
+<para>
+
+</para>
+
+ sasl: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_sasl_authtype_list ##### -->
 <para>
 
diff --git a/docs/reference/camel/tmpl/camel-store.sgml b/docs/reference/camel/tmpl/camel-store.sgml
index 7976bfc..aa399d9 100644
--- a/docs/reference/camel/tmpl/camel-store.sgml
+++ b/docs/reference/camel/tmpl/camel-store.sgml
@@ -561,6 +561,31 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_get_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ folder_name: 
+ flags: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_get_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_get_folder_info_sync ##### -->
 <para>
 
@@ -574,6 +599,31 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_get_folder_info ##### -->
+<para>
+
+</para>
+
+ store: 
+ top: 
+ flags: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_get_folder_info_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_get_inbox_folder_sync ##### -->
 <para>
 
@@ -585,6 +635,29 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_get_inbox_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_get_inbox_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_get_junk_folder_sync ##### -->
 <para>
 
@@ -596,6 +669,29 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_get_junk_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_get_junk_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_get_trash_folder_sync ##### -->
 <para>
 
@@ -607,6 +703,29 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_get_trash_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_get_trash_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_create_folder_sync ##### -->
 <para>
 
@@ -620,6 +739,31 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_create_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ parent_name: 
+ folder_name: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_create_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_delete_folder_sync ##### -->
 <para>
 
@@ -632,15 +776,64 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_delete_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ folder_name: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_delete_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_rename_folder_sync ##### -->
 <para>
 
 </para>
 
 @store: 
- old_namein: 
+ old_name: 
+ new_name: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION camel_store_rename_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ old_name: 
 @new_name: 
+ io_priority: 
 @cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_rename_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
 @error: 
 @Returns: 
 
@@ -657,6 +850,30 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_subscribe_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ folder_name: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_subscribe_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_unsubscribe_folder_sync ##### -->
 <para>
 
@@ -669,6 +886,30 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_unsubscribe_folder ##### -->
+<para>
+
+</para>
+
+ store: 
+ folder_name: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_unsubscribe_folder_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_synchronize_sync ##### -->
 <para>
 
@@ -681,6 +922,30 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_synchronize ##### -->
+<para>
+
+</para>
+
+ store: 
+ expunge: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_synchronize_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
 <!-- ##### FUNCTION camel_store_noop_sync ##### -->
 <para>
 
@@ -692,3 +957,26 @@ CamelStore
 @Returns: 
 
 
+<!-- ##### FUNCTION camel_store_noop ##### -->
+<para>
+
+</para>
+
+ store: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION camel_store_noop_finish ##### -->
+<para>
+
+</para>
+
+ store: 
+ result: 
+ error: 
+ Returns: 
+
+
diff --git a/docs/reference/camel/tmpl/camel-transport.sgml b/docs/reference/camel/tmpl/camel-transport.sgml
index c6bd743..ba5ff96 100644
--- a/docs/reference/camel/tmpl/camel-transport.sgml
+++ b/docs/reference/camel/tmpl/camel-transport.sgml
@@ -26,6 +26,31 @@ CamelTransport
 </para>
 
 
+<!-- ##### ENUM CamelTransportLock ##### -->
+<para>
+
+</para>
+
+ CAMEL_TRANSPORT_SEND_LOCK: 
+
+<!-- ##### FUNCTION camel_transport_lock ##### -->
+<para>
+
+</para>
+
+ transport: 
+ lock: 
+
+
+<!-- ##### FUNCTION camel_transport_unlock ##### -->
+<para>
+
+</para>
+
+ transport: 
+ lock: 
+
+
 <!-- ##### FUNCTION camel_transport_send_to_sync ##### -->
 <para>
 
@@ -40,28 +65,29 @@ CamelTransport
 @Returns: 
 
 
-<!-- ##### ENUM CamelTransportLock ##### -->
-<para>
-
-</para>
-
- CAMEL_TRANSPORT_SEND_LOCK: 
-
-<!-- ##### FUNCTION camel_transport_lock ##### -->
+<!-- ##### FUNCTION camel_transport_send_to ##### -->
 <para>
 
 </para>
 
 @transport: 
- lock: 
+ message: 
+ from: 
+ recipients: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
 
 
-<!-- ##### FUNCTION camel_transport_unlock ##### -->
+<!-- ##### FUNCTION camel_transport_send_to_finish ##### -->
 <para>
 
 </para>
 
 @transport: 
- lock: 
+ result: 
+ error: 
+ Returns: 
 
 
diff --git a/docs/reference/camel/tmpl/camel-unused.sgml b/docs/reference/camel/tmpl/camel-unused.sgml
index 152229e..cadb274 100644
--- a/docs/reference/camel/tmpl/camel-unused.sgml
+++ b/docs/reference/camel/tmpl/camel-unused.sgml
@@ -4522,6 +4522,18 @@ streams
 @error: 
 @Returns: 
 
+<!-- ##### FUNCTION camel_cipher_decrypt_sync ##### -->
+<para>
+
+</para>
+
+ context: 
+ ipart: 
+ opart: 
+ cancellable: 
+ error: 
+ Returns: 
+
 <!-- ##### FUNCTION camel_cipher_encrypt ##### -->
 <para>
 
@@ -4536,6 +4548,20 @@ streams
 @error: 
 @Returns: 
 
+<!-- ##### FUNCTION camel_cipher_encrypt_sync ##### -->
+<para>
+
+</para>
+
+ context: 
+ userid: 
+ recipients: 
+ ipart: 
+ opart: 
+ cancellable: 
+ error: 
+ Returns: 
+
 <!-- ##### FUNCTION camel_cipher_export_keys ##### -->
 <para>
 
@@ -4548,96 +4574,129 @@ streams
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_cipher_import_keys ##### -->
+<!-- ##### FUNCTION camel_cipher_export_keys_sync ##### -->
 <para>
 
 </para>
 
 @context: 
- istream: 
+ keys: 
+ ostream: 
 @cancellable: 
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_cipher_sign ##### -->
+<!-- ##### FUNCTION camel_cipher_hash_to_id ##### -->
 <para>
 
 </para>
 
 @context: 
- userid: 
 @hash: 
- ipart: 
- opart: 
- cancellable: 
- error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_cipher_verify ##### -->
+<!-- ##### FUNCTION camel_cipher_id_to_hash ##### -->
 <para>
 
 </para>
 
 @context: 
- ipart: 
+ id: 
+ Returns: 
+
+<!-- ##### FUNCTION camel_cipher_import_keys ##### -->
+<para>
+
+</para>
+
+ context: 
+ istream: 
 @cancellable: 
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_data_cache_clear ##### -->
+<!-- ##### FUNCTION camel_cipher_import_keys_sync ##### -->
 <para>
 
 </para>
 
- cache: 
- path: 
- ex: 
+ context: 
+ istream: 
+ cancellable: 
+ error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_data_cache_rename ##### -->
+<!-- ##### FUNCTION camel_cipher_sign ##### -->
 <para>
 
 </para>
 
- cache: 
- old: 
- new: 
- ex: 
+ context: 
+ userid: 
+ hash: 
+ ipart: 
+ opart: 
+ cancellable: 
+ error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_data_wrapper_construct_from_stream ##### -->
+<!-- ##### FUNCTION camel_cipher_sign_sync ##### -->
 <para>
 
 </para>
 
- data_wrapper: 
- stream: 
+ context: 
+ userid: 
+ hash: 
+ ipart: 
+ opart: 
 @cancellable: 
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_data_wrapper_decode_to_stream ##### -->
+<!-- ##### FUNCTION camel_cipher_verify ##### -->
 <para>
 
 </para>
 
- data_wrapper: 
- stream: 
+ context: 
+ ipart: 
 @cancellable: 
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_data_wrapper_write_to_stream ##### -->
+<!-- ##### FUNCTION camel_cipher_verify_sync ##### -->
 <para>
 
 </para>
 
- data_wrapper: 
- stream: 
+ context: 
+ ipart: 
 @cancellable: 
 @error: 
 @Returns: 
 
+<!-- ##### FUNCTION camel_data_cache_clear ##### -->
+<para>
+
+</para>
+
+ cache: 
+ path: 
+ ex: 
+ Returns: 
+
+<!-- ##### FUNCTION camel_data_cache_rename ##### -->
+<para>
+
+</para>
+
+ cache: 
+ old: 
+ new: 
+ ex: 
+ Returns: 
+
 <!-- ##### FUNCTION camel_digest_folder_new ##### -->
 <para>
 
@@ -4786,19 +4845,6 @@ streams
 @n: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_folder_append_message ##### -->
-<para>
-
-</para>
-
- folder: 
- message: 
- info: 
- appended_uid: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_folder_construct ##### -->
 <para>
 
@@ -4809,37 +4855,6 @@ streams
 @full_name: 
 @name: 
 
-<!-- ##### FUNCTION camel_folder_expunge ##### -->
-<para>
-
-</para>
-
- folder: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_folder_get_message ##### -->
-<para>
-
-</para>
-
- folder: 
- uid: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_folder_refresh_info ##### -->
-<para>
-
-</para>
-
- folder: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_folder_summary_array_free ##### -->
 <para>
 
@@ -4912,20 +4927,6 @@ streams
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_folder_transfer_messages_to ##### -->
-<para>
-
-</para>
-
- source: 
- uids: 
- dest: 
- transferred_uids: 
- delete_originals: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_groupwise_journal_append ##### -->
 <para>
 
@@ -6808,17 +6809,6 @@ streams
 @stream: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_mime_part_construct_from_parser ##### -->
-<para>
-
-</para>
-
- mime_part: 
- parser: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_mime_part_get_content_MD5 ##### -->
 <para>
 
@@ -7480,17 +7470,6 @@ streams
 
 @Param1: 
 
-<!-- ##### FUNCTION camel_offline_folder_downsync ##### -->
-<para>
-
-</para>
-
- offline: 
- expression: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_offline_store_get_network_state ##### -->
 <para>
 
@@ -7535,6 +7514,13 @@ streams
 
 @cc: 
 
+<!-- ##### FUNCTION camel_operation_end ##### -->
+<para>
+
+</para>
+
+ cancellable: 
+
 <!-- ##### FUNCTION camel_operation_mute ##### -->
 <para>
 
@@ -7573,6 +7559,24 @@ streams
 @void: 
 @Returns: 
 
+<!-- ##### FUNCTION camel_operation_start ##### -->
+<para>
+
+</para>
+
+ cancellable: 
+ what: 
+ Varargs: 
+
+<!-- ##### FUNCTION camel_operation_start_transient ##### -->
+<para>
+
+</para>
+
+ cancellable: 
+ what: 
+ Varargs: 
+
 <!-- ##### ENUM camel_operation_status_t ##### -->
 <para>
 
@@ -7802,28 +7806,6 @@ streams
 @sasl: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_sasl_challenge ##### -->
-<para>
-
-</para>
-
- sasl: 
- token: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_sasl_challenge_base64 ##### -->
-<para>
-
-</para>
-
- sasl: 
- token: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_search_build_match_regex ##### -->
 <para>
 
@@ -8096,53 +8078,6 @@ streams
 @xevline: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_store_create_folder ##### -->
-<para>
-
-</para>
-
- store: 
- parent_name: 
- folder_name: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_store_delete_folder ##### -->
-<para>
-
-</para>
-
- store: 
- folder_name: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_store_get_folder ##### -->
-<para>
-
-</para>
-
- store: 
- folder_name: 
- flags: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_store_get_folder_info ##### -->
-<para>
-
-</para>
-
- store: 
- top: 
- flags: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_store_get_inbox ##### -->
 <para>
 
@@ -8173,39 +8108,6 @@ streams
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_store_noop ##### -->
-<para>
-
-</para>
-
- store: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_store_rename_folder ##### -->
-<para>
-
-</para>
-
- store: 
- old_namein: 
- new_name: 
- cancellable: 
- error: 
- Returns: 
-
-<!-- ##### FUNCTION camel_store_subscribe_folder ##### -->
-<para>
-
-</para>
-
- store: 
- folder_name: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_store_sync ##### -->
 <para>
 
@@ -8217,17 +8119,6 @@ streams
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION camel_store_unsubscribe_folder ##### -->
-<para>
-
-</para>
-
- store: 
- folder_name: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### FUNCTION camel_stream_filter_new_with_stream ##### -->
 <para>
 
@@ -8357,19 +8248,6 @@ streams
 
 @Returns: 
 
-<!-- ##### FUNCTION camel_transport_send_to ##### -->
-<para>
-
-</para>
-
- transport: 
- message: 
- from: 
- recipients: 
- cancellable: 
- error: 
- Returns: 
-
 <!-- ##### MACRO camel_type_get_global_classfuncs ##### -->
 <para>
 



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