[evolution-data-server] Replace CamelSessionThreadMsg with a more modern API.



commit 0dbb8896bbd8ebb779f42ac02bc281fbb9b17ee1
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Apr 23 09:45:35 2011 -0400

    Replace CamelSessionThreadMsg with a more modern API.
    
    This introduces camel_session_submit_job() to replace the older
    CamelSessionThreadMsg API, providing a simpler mechanism for providers
    to initiate low-priority background jobs.  Jobs can be submitted from
    any thread, but execution of the job is always as follows:
    
    1) A "job-started" signal is emitted from the thread in which the
       CamelSession was created.  This is typically the same thread that
       hosts the global default GMainContext, or "main" thread.
    
    2) The callback function passed to camel_session_submit_job() is invoked
       from a different thread where it's safe to call synchronous functions.
    
    3) Once the callback has returned, a "job-finished" signal is emitted
       from the same thread as "job-started" was emitted.
    
    4) If a GDestroyNotify callback was passed to camel_session_submit_job(),
       it is invoked and passed the callback closure so it can be freed.
    
    The signature of the callback function is easier to work with:
    
        void  (*CamelSessionCallback)  (CamelSession *session,
                                        GCancellable *cancellable,
                                        gpointer user_data,
                                        GError **error)
    
    The cancellable is actually a CamelOperation, so status messages can be
    pushed and popped and progress reported through the CamelOperation API.
    The GError pointer is never NULL, so you can safely dereference it in
    the callback function to check for errors.

 camel/camel-disco-folder.c                         |   86 +++---
 camel/camel-folder-summary.c                       |  126 +++-----
 camel/camel-folder.c                               |  222 +++++++------
 camel/camel-marshal.list                           |    1 +
 camel/camel-offline-folder.c                       |   88 +++---
 camel/camel-session.c                              |  347 +++++++++----------
 camel/camel-session.h                              |   75 ++---
 camel/camel-vee-folder.c                           |   62 ++--
 camel/providers/groupwise/camel-groupwise-folder.c |   85 +++---
 camel/providers/imap/camel-imap-store.c            |   59 ++---
 camel/providers/imapx/camel-imapx-store.c          |   44 +--
 docs/reference/camel/camel-sections.txt            |    7 +-
 docs/reference/camel/tmpl/camel-session.sgml       |   63 ++---
 docs/reference/camel/tmpl/camel-unused.sgml        |   49 +++
 14 files changed, 638 insertions(+), 676 deletions(-)
---
diff --git a/camel/camel-disco-folder.c b/camel/camel-disco-folder.c
index 6227a03..f9064c4 100644
--- a/camel/camel-disco-folder.c
+++ b/camel/camel-disco-folder.c
@@ -36,9 +36,7 @@ struct _CamelDiscoFolderPrivate {
 	gboolean offline_sync;
 };
 
-struct _cdf_sync_msg {
-	CamelSessionThreadMsg msg;
-
+struct _cdf_sync_data {
 	CamelFolder *folder;
 	CamelFolderChangeInfo *changes;
 };
@@ -53,54 +51,55 @@ enum {
 G_DEFINE_TYPE (CamelDiscoFolder, camel_disco_folder, CAMEL_TYPE_FOLDER)
 
 static void
-cdf_sync_offline (CamelSession *session, CamelSessionThreadMsg *mm)
+cdf_sync_free (struct _cdf_sync_data *data)
 {
-	struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
-	gint i;
+	if (data->changes != NULL)
+		camel_folder_change_info_free (data->changes);
+	g_object_unref (data->folder);
 
+	g_slice_free (struct _cdf_sync_data, data);
+}
+
+static void
+cdf_sync_offline (CamelSession *session,
+                  GCancellable *cancellable,
+                  struct _cdf_sync_data *data,
+                  GError **error)
+{
 	camel_operation_push_message (
-		mm->cancellable,
+		cancellable,
 		_("Downloading new messages for offline mode"));
 
-	if (m->changes) {
-		for (i=0;i<m->changes->uid_added->len;i++) {
-			gint pc = i * 100 / m->changes->uid_added->len;
+	if (data->changes != NULL) {
+		GPtrArray *uid_added;
+		gint ii;
+
+		uid_added = data->changes->uid_added;
 
-			camel_operation_progress (mm->cancellable, pc);
-			camel_disco_folder_cache_message ((CamelDiscoFolder *)m->folder,
-							 m->changes->uid_added->pdata[i],
-							 NULL, &mm->error);
+		for (ii = 0; ii < uid_added->len; ii++) {
+			gint pc = ii * 100 / uid_added->len;
+
+			camel_operation_progress (cancellable, pc);
+			camel_disco_folder_cache_message (
+				CAMEL_DISCO_FOLDER (data->folder),
+				uid_added->pdata[ii], NULL, error);
 		}
 	} else {
-		camel_disco_folder_prepare_for_offline ((CamelDiscoFolder *)m->folder,
-						       "(match-all)",
-						       NULL, &mm->error);
+		camel_disco_folder_prepare_for_offline (
+			CAMEL_DISCO_FOLDER (data->folder),
+			"(match-all)", NULL, error);
 	}
 
-	camel_operation_pop_message (mm->cancellable);
-}
-
-static void
-cdf_sync_free (CamelSession *session, CamelSessionThreadMsg *mm)
-{
-	struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
-
-	if (m->changes)
-		camel_folder_change_info_free (m->changes);
-	g_object_unref (m->folder);
+	camel_operation_pop_message (cancellable);
 }
 
-static CamelSessionThreadOps cdf_sync_ops = {
-	cdf_sync_offline,
-	cdf_sync_free,
-};
-
 static void
 cdf_folder_changed (CamelFolder *folder,
                     CamelFolderChangeInfo *changes)
 {
 	CamelService *parent_service;
 	CamelStore *parent_store;
+	CamelSession *session;
 	CamelURL *url;
 	gboolean offline_sync;
 
@@ -108,21 +107,24 @@ cdf_folder_changed (CamelFolder *folder,
 
 	parent_service = CAMEL_SERVICE (parent_store);
 	url = camel_service_get_camel_url (parent_service);
+	session = camel_service_get_session (parent_service);
 
 	offline_sync = camel_disco_folder_get_offline_sync (
 		CAMEL_DISCO_FOLDER (folder));
 
 	if (changes->uid_added->len > 0 && (offline_sync
 		|| camel_url_get_param (url, "offline_sync"))) {
-		CamelSession *session;
-		struct _cdf_sync_msg *m;
-
-		session = camel_service_get_session (parent_service);
-		m = camel_session_thread_msg_new (session, &cdf_sync_ops, sizeof (*m));
-		m->changes = camel_folder_change_info_new ();
-		camel_folder_change_info_cat (m->changes, changes);
-		m->folder = g_object_ref (folder);
-		camel_session_thread_queue (session, &m->msg, 0);
+		struct _cdf_sync_data *data;
+
+		data = g_slice_new0 (struct _cdf_sync_data);
+		data->changes = camel_folder_change_info_new ();
+		camel_folder_change_info_cat (data->changes, changes);
+		data->folder = g_object_ref (folder);
+
+		camel_session_submit_job (
+			session,
+			(CamelSessionCallback) cdf_sync_offline,
+			data, (GDestroyNotify) cdf_sync_free);
 	}
 }
 
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 3de1edb4..a540940 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -1496,29 +1496,27 @@ remove_item (gchar *key, CamelMessageInfoBase *info, GSList **to_free_list)
 	return FALSE;
 }
 
-struct _folder_summary_free_msg {
-	CamelSessionThreadMsg msg;
-	CamelFolderSummary *summary;
-};
-
 static void
-remove_cache (CamelSession *session, CamelSessionThreadMsg *msg)
+remove_cache (CamelSession *session,
+              GCancellable *cancellable,
+              CamelFolderSummary *summary,
+              GError **error)
 {
-	struct _folder_summary_free_msg *m = (struct _folder_summary_free_msg *)msg;
-	CamelFolderSummary *s = m->summary;
 	GSList *to_free_list = NULL, *l;
 
 	CAMEL_DB_RELEASE_SQLITE_MEMORY;
 
-	if (time (NULL) - s->cache_load_time < SUMMARY_CACHE_DROP)
+	if (time (NULL) - summary->cache_load_time < SUMMARY_CACHE_DROP)
 		return;
 
 	/* FIXME[disk-summary] hack. fix it */
-	camel_folder_summary_lock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+	camel_folder_summary_lock (
+		summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
-	camel_folder_summary_lock (s, CAMEL_FOLDER_SUMMARY_REF_LOCK);
-	g_hash_table_foreach_remove  (s->loaded_infos, (GHRFunc) remove_item, &to_free_list);
-	camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_REF_LOCK);
+	camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_REF_LOCK);
+	g_hash_table_foreach_remove (
+		summary->loaded_infos, (GHRFunc) remove_item, &to_free_list);
+	camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_REF_LOCK);
 
 	/* Deferred freeing as _free function will try to remove
 	   entries from the hash_table in foreach_remove otherwise */
@@ -1526,46 +1524,36 @@ remove_cache (CamelSession *session, CamelSessionThreadMsg *msg)
 		camel_message_info_free (l->data);
 	g_slist_free (to_free_list);
 
-	dd(printf("   done .. now %d\n", g_hash_table_size (s->loaded_infos)));
-	camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-
-	s->cache_load_time = time (NULL);
-}
+	camel_folder_summary_unlock (
+		summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
-static void remove_cache_end (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-		struct _folder_summary_free_msg *m = (struct _folder_summary_free_msg *)msg;
-		g_object_unref (m->summary);
+	summary->cache_load_time = time (NULL);
 }
 
-static CamelSessionThreadOps remove_timeout_ops = {
-	remove_cache,
-	remove_cache_end,
-};
-
 static gboolean
-cfs_try_release_memory (CamelFolderSummary *s)
+cfs_try_release_memory (CamelFolderSummary *summary)
 {
-	struct _folder_summary_free_msg *m;
 	CamelStore *parent_store;
 	CamelSession *session;
 
 	/* If folder is freed or if the cache is nil then clean up */
-	if (!s->folder || !g_hash_table_size (s->loaded_infos)) {
-		s->cache_load_time = 0;
-		s->timeout_handle = 0;
+	if (!summary->folder || !g_hash_table_size (summary->loaded_infos)) {
+		summary->cache_load_time = 0;
+		summary->timeout_handle = 0;
 		return FALSE;
 	}
 
-	parent_store = camel_folder_get_parent_store (s->folder);
+	parent_store = camel_folder_get_parent_store (summary->folder);
 	session = camel_service_get_session (CAMEL_SERVICE (parent_store));
 
-	if (time (NULL) - s->cache_load_time < SUMMARY_CACHE_DROP)
+	if (time (NULL) - summary->cache_load_time < SUMMARY_CACHE_DROP)
 		return TRUE;
 
-	m = camel_session_thread_msg_new (session, &remove_timeout_ops, sizeof (*m));
-	m->summary = g_object_ref (s);
-	camel_session_thread_queue (session, &m->msg, 0);
+	camel_session_submit_job (
+		session,
+		(CamelSessionCallback) remove_cache,
+		g_object_ref (summary),
+		(GDestroyNotify) g_object_unref);
 
 	return TRUE;
 }
@@ -1604,13 +1592,6 @@ cfs_cache_size (CamelFolderSummary *s)
 
 /* Update preview of cached messages */
 
-struct _preview_update_msg {
-	CamelSessionThreadMsg msg;
-
-	CamelFolder *folder;
-	GError *error;
-};
-
 static void
 msg_update_preview (const gchar *uid, gpointer value, CamelFolder *folder)
 {
@@ -1652,55 +1633,45 @@ fill_mi (const gchar *uid, const gchar *msg, CamelFolder *folder)
 }
 
 static void
-preview_update_exec (CamelSession *session, CamelSessionThreadMsg *msg)
+preview_update (CamelSession *session,
+                GCancellable *cancellable,
+                CamelFolder *folder,
+                GError **error)
 {
-	struct _preview_update_msg *m = (struct _preview_update_msg *)msg;
 	/* FIXME: Either lock & use or copy & use.*/
-	GPtrArray *uids_uncached= camel_folder_get_uncached_uids (m->folder, m->folder->summary->uids, NULL);
-	GHashTable *hash = camel_folder_summary_get_hashtable (m->folder->summary);
+	GPtrArray *uids_uncached= camel_folder_get_uncached_uids (folder, folder->summary->uids, NULL);
+	GHashTable *hash = camel_folder_summary_get_hashtable (folder->summary);
 	GHashTable *preview_data;
 	CamelStore *parent_store;
 	const gchar *full_name;
 	gint i;
 
-	full_name = camel_folder_get_full_name (m->folder);
-	parent_store = camel_folder_get_parent_store (m->folder);
+	full_name = camel_folder_get_full_name (folder);
+	parent_store = camel_folder_get_parent_store (folder);
 	preview_data = camel_db_get_folder_preview (parent_store->cdb_r, full_name, NULL);
 	if (preview_data) {
-		g_hash_table_foreach_remove (preview_data, (GHRFunc)fill_mi, m->folder);
+		g_hash_table_foreach_remove (preview_data, (GHRFunc)fill_mi, folder);
 		g_hash_table_destroy (preview_data);
 	}
 
-	camel_folder_summary_lock (m->folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-	g_hash_table_foreach (m->folder->summary->loaded_infos, (GHFunc)pick_uids, uids_uncached);
-	camel_folder_summary_unlock (m->folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+	camel_folder_summary_lock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+	g_hash_table_foreach (folder->summary->loaded_infos, (GHFunc)pick_uids, uids_uncached);
+	camel_folder_summary_unlock (folder->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
 	for (i=0; i < uids_uncached->len; i++) {
 		g_hash_table_remove (hash, uids_uncached->pdata[i]);
 		camel_pstring_free (uids_uncached->pdata[i]); /* unref the hash table key */
 	}
 
-	camel_folder_lock (m->folder, CAMEL_FOLDER_REC_LOCK);
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
 	camel_db_begin_transaction (parent_store->cdb_w, NULL);
-	g_hash_table_foreach (hash, (GHFunc)msg_update_preview, m->folder);
+	g_hash_table_foreach (hash, (GHFunc)msg_update_preview, folder);
 	camel_db_end_transaction (parent_store->cdb_w, NULL);
-	camel_folder_unlock (m->folder, CAMEL_FOLDER_REC_LOCK);
-	camel_folder_free_uids (m->folder, uids_uncached);
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+	camel_folder_free_uids (folder, uids_uncached);
 	camel_folder_summary_free_hashtable (hash);
 }
 
-static void
-preview_update_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _preview_update_msg *m = (struct _preview_update_msg *)msg;
-
-	m=m;
-}
-static CamelSessionThreadOps preview_update_ops = {
-	preview_update_exec,
-	preview_update_free,
-};
-
 /* end */
 
 static gint
@@ -1731,15 +1702,12 @@ cfs_reload_from_db (CamelFolderSummary *s, GError **error)
 
 	cfs_schedule_info_release_timer (s);
 
-	if (s->priv->need_preview) {
-		struct _preview_update_msg *m;
-
-		m = camel_session_thread_msg_new (
-			session, &preview_update_ops, sizeof (*m));
-		m->folder = s->folder;
-		m->error = NULL;
-		camel_session_thread_queue (session, &m->msg, 0);
-	}
+	if (s->priv->need_preview)
+		camel_session_submit_job (
+			session,
+			(CamelSessionCallback) preview_update,
+			g_object_ref (s->folder),
+			(GDestroyNotify) g_object_unref);
 
 	return ret == 0 ? 0 : -1;
 }
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 2a762f6..8a9240f 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -47,6 +47,7 @@
 
 typedef struct _AsyncContext AsyncContext;
 typedef struct _SignalData SignalData;
+typedef struct _FolderFilterData FolderFilterData;
 
 struct _CamelFolderPrivate {
 	GStaticRecMutex lock;
@@ -91,15 +92,12 @@ struct _SignalData {
 	gchar *folder_name;
 };
 
-struct _folder_filter_msg {
-	CamelSessionThreadMsg msg;
-
+struct _FolderFilterData {
 	GPtrArray *recents;
 	GPtrArray *junk;
 	GPtrArray *notjunk;
 	CamelFolder *folder;
 	CamelFilterDriver *driver;
-	GError *error;
 };
 
 enum {
@@ -192,10 +190,32 @@ folder_emit_renamed_cb (SignalData *data)
 }
 
 static void
-filter_filter (CamelSession *session,
-               CamelSessionThreadMsg *tmsg)
+folder_filter_data_free (FolderFilterData *data)
+{
+	if (data->driver != NULL)
+		g_object_unref (data->driver);
+	if (data->recents != NULL)
+		camel_folder_free_deep (data->folder, data->recents);
+	if (data->junk != NULL)
+		camel_folder_free_deep (data->folder, data->junk);
+	if (data->notjunk != NULL)
+		camel_folder_free_deep (data->folder, data->notjunk);
+
+	/* XXX Too late to pass a GError here. */
+	camel_folder_summary_save_to_db (data->folder->summary, NULL);
+
+	camel_folder_thaw (data->folder);
+	g_object_unref (data->folder);
+
+	g_slice_free (FolderFilterData, data);
+}
+
+static void
+folder_filter (CamelSession *session,
+               GCancellable *cancellable,
+               FolderFilterData *data,
+               GError **error)
 {
-	struct _folder_filter_msg *m = (struct _folder_filter_msg *) tmsg;
 	CamelMessageInfo *info;
 	CamelStore *parent_store;
 	gint i, status = 0;
@@ -203,71 +223,97 @@ filter_filter (CamelSession *session,
 	gchar *source_url;
 	CamelJunkPlugin *csp;
 	const gchar *full_name;
-	GError *local_error = NULL;
 
-	full_name = camel_folder_get_full_name (m->folder);
-	parent_store = camel_folder_get_parent_store (m->folder);
+	full_name = camel_folder_get_full_name (data->folder);
+	parent_store = camel_folder_get_parent_store (data->folder);
 	csp = session->junk_plugin;
 
-	if (m->junk) {
-		/* Translators: The %s is replaced with a folder name where the operation is running. */
+	if (data->junk) {
+		/* Translators: The %s is replaced with the
+		 * folder name where the operation is running. */
 		camel_operation_push_message (
-			tmsg->cancellable, ngettext (
+			cancellable, ngettext (
 			"Learning new spam message in '%s'",
 			"Learning new spam messages in '%s'",
-			m->junk->len), full_name);
+			data->junk->len), full_name);
 
-		for (i = 0; i < m->junk->len; i++) {
-			/* FIXME Pass a GCancellable */
-			CamelMimeMessage *msg = camel_folder_get_message_sync (
-				m->folder, m->junk->pdata[i], NULL, NULL);
-			gint pc = 100 * i / m->junk->len;
+		for (i = 0; i < data->junk->len; i++) {
+			CamelMimeMessage *message;
+			gint pc = 100 * i / data->junk->len;
 
-			camel_operation_progress (tmsg->cancellable, pc);
+			if (g_cancellable_set_error_if_cancelled (
+				cancellable, error))
+				break;
 
-			if (msg) {
-				camel_junk_plugin_report_junk (csp, msg);
-				g_object_unref (msg);
-			}
+			message = camel_folder_get_message_sync (
+				data->folder, data->junk->pdata[i],
+				cancellable, error);
+
+			if (message == NULL)
+				break;
+
+			camel_operation_progress (cancellable, pc);
+			camel_junk_plugin_report_junk (csp, message);
+			g_object_unref (message);
 		}
-		camel_operation_pop_message (tmsg->cancellable);
+
+		camel_operation_pop_message (cancellable);
 	}
 
-	if (m->notjunk) {
-		/* Translators: The %s is replaced with a folder name where the operation is running. */
+	if (*error != NULL)
+		return;
+
+	if (data->notjunk) {
+		/* Translators: The %s is replaced with the
+		 * folder name where the operation is running. */
 		camel_operation_push_message (
-			tmsg->cancellable, ngettext (
+			cancellable, ngettext (
 			"Learning new ham message in '%s'",
 			"Learning new ham messages in '%s'",
-			m->notjunk->len), full_name);
-		for (i = 0; i < m->notjunk->len; i++) {
-			/* FIXME Pass a GCancellable */
-			CamelMimeMessage *msg = camel_folder_get_message_sync (
-				m->folder, m->notjunk->pdata[i], NULL, NULL);
-			gint pc = 100 * i / m->notjunk->len;
-
-			camel_operation_progress (tmsg->cancellable, pc);
-
-			if (msg) {
-				camel_junk_plugin_report_notjunk (csp, msg);
-				g_object_unref (msg);
-			}
+			data->notjunk->len), full_name);
+
+		for (i = 0; i < data->notjunk->len; i++) {
+			CamelMimeMessage *message;
+			gint pc = 100 * i / data->notjunk->len;
+
+			if (g_cancellable_set_error_if_cancelled (
+				cancellable, error))
+				break;
+
+			message = camel_folder_get_message_sync (
+				data->folder, data->notjunk->pdata[i],
+				cancellable, error);
+
+			if (message == NULL)
+				break;
+
+			camel_operation_progress (cancellable, pc);
+			camel_junk_plugin_report_notjunk (csp, message);
+			g_object_unref (message);
 		}
-		camel_operation_pop_message (tmsg->cancellable);
+
+		camel_operation_pop_message (cancellable);
 	}
 
-	if (m->junk || m->notjunk)
+	if (*error != NULL)
+		return;
+
+	if (data->junk || data->notjunk)
 		camel_junk_plugin_commit_reports (csp);
 
-	if (m->driver && m->recents) {
-		/* Translators: The %s is replaced with a folder name where the operation is running. */
+	if (data->driver && data->recents) {
+		CamelService *service;
+
+		/* Translators: The %s is replaced with the
+		 * folder name where the operation is running. */
 		camel_operation_push_message (
-			tmsg->cancellable, ngettext (
+			cancellable, ngettext (
 			"Filtering new message in '%s'",
 			"Filtering new messages in '%s'",
-			m->recents->len), full_name);
+			data->recents->len), full_name);
 
-		source_url = camel_service_get_url (CAMEL_SERVICE (parent_store));
+		service = CAMEL_SERVICE (parent_store);
+		source_url = camel_service_get_url (service);
 		uri = camel_url_new (source_url, NULL);
 		g_free (source_url);
 
@@ -282,60 +328,36 @@ filter_filter (CamelSession *session,
 		source_url = camel_url_to_string (uri, CAMEL_URL_HIDE_ALL);
 		camel_url_free (uri);
 
-		for (i=0;status == 0 && i<m->recents->len;i++) {
-			gchar *uid = m->recents->pdata[i];
-			gint pc = 100 * i / m->recents->len;
+		for (i = 0; status == 0 && i < data->recents->len; i++) {
+			gchar *uid = data->recents->pdata[i];
+			gint pc = 100 * i / data->recents->len;
 
-			camel_operation_progress (tmsg->cancellable, pc);
+			camel_operation_progress (cancellable, pc);
 
-			info = camel_folder_get_message_info (m->folder, uid);
+			info = camel_folder_get_message_info (
+				data->folder, uid);
 			if (info == NULL) {
-				g_warning ("uid %s vanished from folder: %s", uid, source_url);
+				g_warning (
+					"uid '%s' vanished from folder '%s'",
+					uid, source_url);
 				continue;
 			}
 
-			/* FIXME Pass a GCancellable */
 			status = camel_filter_driver_filter_message (
-				m->driver, NULL, info, uid, m->folder,
-				source_url, source_url, NULL, NULL);
+				data->driver, NULL, info, uid, data->folder,
+				source_url, source_url, cancellable, error);
 
-			camel_folder_free_message_info (m->folder, info);
+			camel_folder_free_message_info (data->folder, info);
 		}
 
-		camel_filter_driver_flush (m->driver, &local_error);
-		if (local_error != NULL)
-			g_propagate_error (&m->error, local_error);
-
 		g_free (source_url);
 
-		camel_operation_pop_message (tmsg->cancellable);
-	}
-}
-
-static void
-filter_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _folder_filter_msg *m = (struct _folder_filter_msg *)msg;
-
-	if (m->driver)
-		g_object_unref (m->driver);
-	if (m->recents)
-		camel_folder_free_deep (m->folder, m->recents);
-	if (m->junk)
-		camel_folder_free_deep (m->folder, m->junk);
-	if (m->notjunk)
-		camel_folder_free_deep (m->folder, m->notjunk);
+		camel_operation_pop_message (cancellable);
 
-	camel_folder_summary_save_to_db (m->folder->summary, &m->error);
-	camel_folder_thaw (m->folder);
-	g_object_unref (m->folder);
+		camel_filter_driver_flush (data->driver, error);
+	}
 }
 
-static CamelSessionThreadOps filter_ops = {
-	filter_filter,
-	filter_free
-};
-
 static gint
 cmp_array_uids (gconstpointer a,
                 gconstpointer b,
@@ -1435,24 +1457,28 @@ folder_changed (CamelFolder *folder,
 	}
 
 	if (driver || junk || notjunk) {
-		struct _folder_filter_msg *msg;
+		FolderFilterData *data;
 
-		d (printf ("* launching filter thread %d new mail, %d junk and %d not junk\n",
-			 recents?recents->len:0, junk?junk->len:0, notjunk?notjunk->len:0));
+		data = g_slice_new0 (FolderFilterData);
+		data->recents = recents;
+		data->junk = junk;
+		data->notjunk = notjunk;
+		data->folder = g_object_ref (folder);
+		data->driver = driver;
 
-		msg = camel_session_thread_msg_new (session, &filter_ops, sizeof (*msg));
-		msg->recents = recents;
-		msg->junk = junk;
-		msg->notjunk = notjunk;
-		msg->folder = g_object_ref (folder);
 		camel_folder_freeze (folder);
+
 		/* Copy changes back to changed_frozen list to retain
 		 * them while we are filtering */
 		camel_folder_lock (folder, CAMEL_FOLDER_CHANGE_LOCK);
-		camel_folder_change_info_cat (folder->priv->changed_frozen, info);
+		camel_folder_change_info_cat (
+			folder->priv->changed_frozen, info);
 		camel_folder_unlock (folder, CAMEL_FOLDER_CHANGE_LOCK);
-		msg->driver = driver;
-		camel_session_thread_queue (session, &msg->msg, 0);
+
+		camel_session_submit_job (
+			session, (CamelSessionCallback) folder_filter,
+			data, (GDestroyNotify) folder_filter_data_free);
+
 		g_signal_stop_emission (folder, signals[CHANGED], 0);
 	}
 }
diff --git a/camel/camel-marshal.list b/camel/camel-marshal.list
index daee534..2409e23 100644
--- a/camel/camel-marshal.list
+++ b/camel/camel-marshal.list
@@ -1,2 +1,3 @@
 NONE:STRING,INT
 NONE:STRING,POINTER
+NONE:OBJECT,POINTER
diff --git a/camel/camel-offline-folder.c b/camel/camel-offline-folder.c
index 27e8f83..e25f298 100644
--- a/camel/camel-offline-folder.c
+++ b/camel/camel-offline-folder.c
@@ -34,6 +34,7 @@
 #include "camel-store.h"
 
 typedef struct _AsyncContext AsyncContext;
+typedef struct _OfflineDownsyncData OfflineDownsyncData;
 
 struct _CamelOfflineFolderPrivate {
 	gboolean offline_sync;
@@ -44,9 +45,7 @@ struct _AsyncContext {
 	gchar *expression;
 };
 
-struct _offline_downsync_msg {
-	CamelSessionThreadMsg msg;
-
+struct _OfflineDownsyncData {
 	CamelFolder *folder;
 	CamelFolderChangeInfo *changes;
 };
@@ -69,51 +68,54 @@ async_context_free (AsyncContext *async_context)
 }
 
 static void
-offline_downsync_sync (CamelSession *session, CamelSessionThreadMsg *mm)
+offline_downsync_data_free (OfflineDownsyncData *data)
 {
-	struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm;
-	gint i;
+	if (data->changes != NULL)
+		camel_folder_change_info_free (data->changes);
+
+	g_object_unref (data->folder);
 
+	g_slice_free (OfflineDownsyncData, data);
+}
+
+static void
+offline_folder_downsync_background (CamelSession *session,
+                                    GCancellable *cancellable,
+                                    OfflineDownsyncData *data,
+                                    GError **error)
+{
 	camel_operation_push_message (
-		mm->cancellable,
+		cancellable,
 		_("Downloading new messages for offline mode"));
 
-	if (m->changes) {
-		for (i = 0; i < m->changes->uid_added->len; i++) {
-			gint pc = i * 100 / m->changes->uid_added->len;
+	if (data->changes) {
+		GPtrArray *uid_added;
+		gboolean success = TRUE;
+		gint ii;
+
+		uid_added = data->changes->uid_added;
+
+		for (ii = 0; success && ii < uid_added->len; ii++) {
+			const gchar *uid;
+			gint percent;
 
-			camel_operation_progress (mm->cancellable, pc);
-			/* FIXME Pass a GCancellable */
-			camel_folder_synchronize_message_sync (
-				m->folder, m->changes->uid_added->pdata[i],
-				NULL, &mm->error);
+			percent = ii * 100 / uid_added->len;
+			uid = g_ptr_array_index (uid_added, ii);
+
+			camel_operation_progress (cancellable, percent);
+
+			success = camel_folder_synchronize_message_sync (
+				data->folder, uid, cancellable, error);
 		}
 	} else {
-		/* FIXME Pass a GCancellable */
 		camel_offline_folder_downsync_sync (
-			(CamelOfflineFolder *) m->folder,
-			"(match-all)", NULL, &mm->error);
+			CAMEL_OFFLINE_FOLDER (data->folder),
+			"(match-all)", cancellable, error);
 	}
 
-	camel_operation_pop_message (mm->cancellable);
-}
-
-static void
-offline_downsync_free (CamelSession *session, CamelSessionThreadMsg *mm)
-{
-	struct _offline_downsync_msg *m = (struct _offline_downsync_msg *) mm;
-
-	if (m->changes)
-		camel_folder_change_info_free (m->changes);
-
-	g_object_unref (m->folder);
+	camel_operation_pop_message (cancellable);
 }
 
-static CamelSessionThreadOps offline_downsync_ops = {
-	offline_downsync_sync,
-	offline_downsync_free,
-};
-
 static void
 offline_folder_changed (CamelFolder *folder,
                         CamelFolderChangeInfo *changes)
@@ -134,15 +136,17 @@ offline_folder_changed (CamelFolder *folder,
 		CAMEL_OFFLINE_FOLDER (folder));
 
 	if (changes->uid_added->len > 0 && (offline_sync || camel_url_get_param (url, "sync_offline"))) {
-		struct _offline_downsync_msg *m;
+		OfflineDownsyncData *data;
 
-		m = camel_session_thread_msg_new (
-			session, &offline_downsync_ops, sizeof (*m));
-		m->changes = camel_folder_change_info_new ();
-		camel_folder_change_info_cat (m->changes, changes);
-		m->folder = g_object_ref (folder);
+		data = g_slice_new0 (OfflineDownsyncData);
+		data->changes = camel_folder_change_info_new ();
+		camel_folder_change_info_cat (data->changes, changes);
+		data->folder = g_object_ref (folder);
 
-		camel_session_thread_queue (session, &m->msg, 0);
+		camel_session_submit_job (
+			session, (CamelSessionCallback)
+			offline_folder_downsync_background, data,
+			(GDestroyNotify) offline_downsync_data_free);
 	}
 }
 
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 8ee61ce..d0a1045 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -39,6 +39,7 @@
 
 #include "camel-debug.h"
 #include "camel-file-utils.h"
+#include "camel-marshal.h"
 #include "camel-session.h"
 #include "camel-store.h"
 #include "camel-string-utils.h"
@@ -51,21 +52,23 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), CAMEL_TYPE_SESSION, CamelSessionPrivate))
 
+#define JOB_PRIORITY G_PRIORITY_LOW
+
 #define d(x)
 
+typedef struct _JobData JobData;
+
 struct _CamelSessionPrivate {
 	GMutex *lock;		/* for locking everything basically */
 	GMutex *thread_lock;	/* locking threads */
 
 	gchar *user_data_dir;
 
-	gint thread_id;
-	GHashTable *thread_active;
-	GThreadPool *thread_pool;
-
 	GHashTable *services;
 	GHashTable *junk_headers;
 
+	GMainContext *context;
+
 	gchar *socks_proxy_host;
 	gint socks_proxy_port;
 
@@ -74,6 +77,14 @@ struct _CamelSessionPrivate {
 	guint online            : 1;
 };
 
+struct _JobData {
+	CamelSession *session;
+	GCancellable *cancellable;
+	CamelSessionCallback callback;
+	gpointer user_data;
+	GDestroyNotify notify;
+};
+
 enum {
 	PROP_0,
 	PROP_CHECK_JUNK,
@@ -82,20 +93,92 @@ enum {
 	PROP_USER_DATA_DIR,
 };
 
+enum {
+	JOB_STARTED,
+	JOB_FINISHED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
 G_DEFINE_TYPE (CamelSession, camel_session, CAMEL_TYPE_OBJECT)
 
 static void
-cs_thread_status (CamelOperation *operation,
-                  const gchar *what,
-                  gint pc,
-                  CamelSessionThreadMsg *msg)
+job_data_free (JobData *job_data)
 {
-	CamelSessionClass *class;
+	g_object_unref (job_data->session);
+	g_object_unref (job_data->cancellable);
 
-	class = CAMEL_SESSION_GET_CLASS (msg->session);
-	g_return_if_fail (class->thread_status != NULL);
+	if (job_data->notify != NULL)
+		job_data->notify (job_data->user_data);
 
-	class->thread_status (msg->session, msg, what, pc);
+	g_slice_free (JobData, job_data);
+}
+
+static void
+session_finish_job_cb (CamelSession *session,
+                       GSimpleAsyncResult *simple)
+{
+	JobData *job_data;
+	GError *error = NULL;
+
+	g_simple_async_result_propagate_error (simple, &error);
+	job_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+	g_signal_emit (
+		job_data->session,
+		signals[JOB_FINISHED], 0,
+		job_data->cancellable, error);
+
+	g_clear_error (&error);
+}
+
+static void
+session_do_job_cb (GSimpleAsyncResult *simple,
+                   CamelSession *session,
+                   GCancellable *cancellable)
+{
+	JobData *job_data;
+	GError *error = NULL;
+
+	job_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+	job_data->callback (
+		session, cancellable,
+		job_data->user_data, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+static gboolean
+session_start_job_cb (JobData *job_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_signal_emit (
+		job_data->session,
+		signals[JOB_STARTED], 0,
+		job_data->cancellable);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (job_data->session),
+		(GAsyncReadyCallback) session_finish_job_cb,
+		NULL, camel_session_submit_job);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, job_data, (GDestroyNotify) job_data_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, (GSimpleAsyncThreadFunc)
+		session_do_job_cb, JOB_PRIORITY,
+		job_data->cancellable);
+
+	g_object_unref (simple);
+
+	return FALSE;
 }
 
 static void
@@ -201,13 +284,9 @@ session_finalize (GObject *object)
 	g_free (priv->user_data_dir);
 
 	g_hash_table_destroy (priv->services);
-	g_hash_table_destroy (priv->thread_active);
 
-	if (priv->thread_pool != NULL) {
-		/* there should be no unprocessed tasks */
-		g_assert (g_thread_pool_unprocessed (priv->thread_pool) == 0);
-		g_thread_pool_free (priv->thread_pool, FALSE, FALSE);
-	}
+	if (priv->context != NULL)
+		g_main_context_unref (priv->context);
 
 	g_mutex_free (priv->lock);
 	g_mutex_free (priv->thread_lock);
@@ -287,95 +366,6 @@ session_add_service (CamelSession *session,
 	return service;
 }
 
-static gpointer
-session_thread_msg_new (CamelSession *session,
-                        CamelSessionThreadOps *ops,
-                        guint size)
-{
-	CamelSessionThreadMsg *m;
-
-	m = g_malloc0 (size);
-	m->ops = ops;
-	m->session = g_object_ref (session);
-	m->cancellable = camel_operation_new ();
-	camel_session_lock (session, CAMEL_SESSION_THREAD_LOCK);
-	m->id = session->priv->thread_id++;
-	g_hash_table_insert (session->priv->thread_active, GINT_TO_POINTER (m->id), m);
-	camel_session_unlock (session, CAMEL_SESSION_THREAD_LOCK);
-
-	g_signal_connect (
-		m->cancellable, "status",
-		G_CALLBACK (cs_thread_status), m);
-
-	return m;
-}
-
-static void
-session_thread_msg_free (CamelSession *session,
-                         CamelSessionThreadMsg *msg)
-{
-	g_return_if_fail (CAMEL_IS_SESSION (session));
-	g_return_if_fail (msg != NULL && msg->ops != NULL);
-
-	d(printf("free message %p session %p\n", msg, session));
-
-	camel_session_lock (session, CAMEL_SESSION_THREAD_LOCK);
-	g_hash_table_remove (session->priv->thread_active, GINT_TO_POINTER (msg->id));
-	camel_session_unlock (session, CAMEL_SESSION_THREAD_LOCK);
-
-	d(printf("free msg, ops->free = %p\n", msg->ops->free));
-
-	if (msg->ops->free)
-		msg->ops->free (session, msg);
-	if (msg->cancellable)
-		g_object_unref (msg->cancellable);
-	g_clear_error (&msg->error);
-	g_object_unref (msg->session);
-	g_free (msg);
-}
-
-static void
-session_thread_proxy (CamelSessionThreadMsg *msg,
-                      CamelSession *session)
-{
-	if (msg->ops->receive)
-		msg->ops->receive (session, msg);
-
-	camel_session_thread_msg_free (session, msg);
-}
-
-static gint
-session_thread_queue (CamelSession *session,
-                      CamelSessionThreadMsg *msg,
-                      gint flags)
-{
-	GThreadPool *thread_pool;
-	gint id;
-
-	camel_session_lock (session, CAMEL_SESSION_THREAD_LOCK);
-	thread_pool = session->priv->thread_pool;
-	if (thread_pool == NULL) {
-		thread_pool = g_thread_pool_new (
-			(GFunc) session_thread_proxy,
-			session, 1, FALSE, NULL);
-		session->priv->thread_pool = thread_pool;
-	}
-	camel_session_unlock (session, CAMEL_SESSION_THREAD_LOCK);
-
-	id = msg->id;
-	g_thread_pool_push (thread_pool, msg, NULL);
-
-	return id;
-}
-
-static void
-session_thread_status (CamelSession *session,
-                       CamelSessionThreadMsg *msg,
-                       const gchar *text,
-                       gint pc)
-{
-}
-
 static void
 camel_session_class_init (CamelSessionClass *class)
 {
@@ -390,10 +380,6 @@ camel_session_class_init (CamelSessionClass *class)
 	object_class->finalize = session_finalize;
 
 	class->add_service = session_add_service;
-	class->thread_msg_new = session_thread_msg_new;
-	class->thread_msg_free = session_thread_msg_free;
-	class->thread_queue = session_thread_queue;
-	class->thread_status = session_thread_status;
 
 	g_object_class_install_property (
 		object_class,
@@ -442,6 +428,27 @@ camel_session_class_init (CamelSessionClass *class)
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT |
 			G_PARAM_STATIC_STRINGS));
+
+	signals[JOB_STARTED] = g_signal_new (
+		"job-started",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (CamelSessionClass, job_started),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE, 1,
+		G_TYPE_CANCELLABLE);
+
+	signals[JOB_FINISHED] = g_signal_new (
+		"job-finished",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (CamelSessionClass, job_finished),
+		NULL, NULL,
+		camel_marshal_VOID__OBJECT_POINTER,
+		G_TYPE_NONE, 2,
+		G_TYPE_CANCELLABLE,
+		G_TYPE_POINTER);
 }
 
 static void
@@ -459,11 +466,12 @@ camel_session_init (CamelSession *session)
 
 	session->priv->lock = g_mutex_new ();
 	session->priv->thread_lock = g_mutex_new ();
-	session->priv->thread_id = 1;
-	session->priv->thread_active = g_hash_table_new (NULL, NULL);
-	session->priv->thread_pool = NULL;
 	session->priv->services = services;
 	session->priv->junk_headers = NULL;
+
+	session->priv->context = g_main_context_get_thread_default ();
+	if (session->priv->context != NULL)
+		g_main_context_ref (session->priv->context);
 }
 
 /**
@@ -896,85 +904,58 @@ camel_session_get_filter_driver (CamelSession *session,
 }
 
 /**
- * camel_session_thread_msg_new:
+ * camel_session_submit_job:
  * @session: a #CamelSession
- * @ops: thread operations
- * @size: number of bytes
+ * @callback: a #CamelSessionCallback
+ * @user_data: user data passed to the callback
+ * @notify: a #GDestroyNotify function
  *
- * Create a new thread message, using ops as the receive/reply/free
- * ops, of @size bytes.
+ * This function provides a simple mechanism for providers to initiate
+ * low-priority background jobs.  Jobs can be submitted from any thread,
+ * but execution of the jobs is always as follows:
  *
- * @ops points to the operations used to recieve/process and finally
- * free the message.
+ * 1) The #CamelSession:job-started signal is emitted from the thread
+ *    in which @session was created.  This is typically the same thread
+ *    that hosts the global default #GMainContext, or "main" thread.
  *
- * Returns: a new #CamelSessionThreadMsg
- **/
-gpointer
-camel_session_thread_msg_new (CamelSession *session,
-                              CamelSessionThreadOps *ops,
-                              guint size)
-{
-	CamelSessionClass *class;
-
-	g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
-	g_return_val_if_fail (ops != NULL, NULL);
-	g_return_val_if_fail (size >= sizeof (CamelSessionThreadMsg), NULL);
-
-	class = CAMEL_SESSION_GET_CLASS (session);
-	g_return_val_if_fail (class->thread_msg_new != NULL, NULL);
-
-	return class->thread_msg_new (session, ops, size);
-}
-
-/**
- * camel_session_thread_msg_free:
- * @session: a #CamelSession
- * @msg: a #CamelSessionThreadMsg
+ * 2) The @callback function is invoked from a different thread where
+ *    it's safe to call synchronous functions.
  *
- * Free a @msg.  Note that the message must have been allocated using
- * msg_new, and must nto have been submitted to any queue function.
- **/
-void
-camel_session_thread_msg_free (CamelSession *session,
-                               CamelSessionThreadMsg *msg)
-{
-	CamelSessionClass *class;
-
-	g_return_if_fail (CAMEL_IS_SESSION (session));
-	g_return_if_fail (msg != NULL && msg->ops != NULL);
-
-	class = CAMEL_SESSION_GET_CLASS (session);
-	g_return_if_fail (class->thread_msg_free != NULL);
-
-	class->thread_msg_free (session, msg);
-}
-
-/**
- * camel_session_thread_queue:
- * @session: a #CamelSession
- * @msg: a #CamelSessionThreadMsg
- * @flags: queue type flags, currently 0.
+ * 3) Once @callback has returned, the #CamelSesson:job-finished signal
+ *    is emitted from the same thread as #CamelSession:job-started was
+ *    emitted.
  *
- * Queue a thread message in another thread for processing.
- * The operation should be (but needn't) run in a queued manner
- * with other operations queued in this manner.
+ * 4) Finally if a @notify function was provided, it is invoked and
+ *    passed @user_data so that @user_data can be freed.
  *
- * Returns: the id of the operation queued
+ * Since: 3.2
  **/
-gint
-camel_session_thread_queue (CamelSession *session,
-                            CamelSessionThreadMsg *msg,
-                            gint flags)
+void
+camel_session_submit_job (CamelSession *session,
+                          CamelSessionCallback callback,
+                          gpointer user_data,
+                          GDestroyNotify notify)
 {
-	CamelSessionClass *class;
-
-	g_return_val_if_fail (CAMEL_IS_SESSION (session), -1);
-	g_return_val_if_fail (msg != NULL, -1);
+	GSource *source;
+	JobData *job_data;
 
-	class = CAMEL_SESSION_GET_CLASS (session);
-	g_return_val_if_fail (class->thread_queue != NULL, -1);
-
-	return class->thread_queue (session, msg, flags);
+	g_return_if_fail (CAMEL_IS_SESSION (session));
+	g_return_if_fail (callback != NULL);
+
+	job_data = g_slice_new0 (JobData);
+	job_data->session = g_object_ref (session);
+	job_data->cancellable = camel_operation_new ();
+	job_data->callback = callback;
+	job_data->user_data = user_data;
+	job_data->notify = notify;
+
+	source = g_idle_source_new ();
+	g_source_set_priority (source, JOB_PRIORITY);
+	g_source_set_callback (
+		source, (GSourceFunc) session_start_job_cb,
+		job_data, (GDestroyNotify) NULL);
+	g_source_attach (source, job_data->session->priv->context);
+	g_source_unref (source);
 }
 
 /**
diff --git a/camel/camel-session.h b/camel/camel-session.h
index 25e4294..ad48d49 100644
--- a/camel/camel-session.h
+++ b/camel/camel-session.h
@@ -91,8 +91,23 @@ struct _CamelSession {
 	CamelJunkPlugin *junk_plugin;
 };
 
-typedef struct _CamelSessionThreadOps CamelSessionThreadOps;
-typedef struct _CamelSessionThreadMsg CamelSessionThreadMsg;
+/**
+ * CamelSessionCallback:
+ * @session: a #CamelSession
+ * @cancellable: a #CamelOperation cast as a #GCancellable
+ * @user_data: data passed to camel_session_submit_job()
+ * @error: return location for a #GError
+ *
+ * This is the callback signature for jobs submitted to the CamelSession
+ * via camel_session_submit_job().  The @error pointer is always non-%NULL,
+ * so it's safe to dereference to check if a #GError has been set.
+ *
+ * Since: 3.2
+ **/
+typedef void	(*CamelSessionCallback)		(CamelSession *session,
+						 GCancellable *cancellable,
+						 gpointer user_data,
+						 GError **error);
 
 struct _CamelSessionClass {
 	CamelObjectClass parent_class;
@@ -122,21 +137,6 @@ struct _CamelSessionClass {
 			(*get_filter_driver)	(CamelSession *session,
 						 const gchar *type,
 						 GError **error);
-
-	/* mechanism for creating and maintaining multiple threads of control */
-	gpointer	(*thread_msg_new)	(CamelSession *session,
-						 CamelSessionThreadOps *ops,
-						 guint size);
-	void		(*thread_msg_free)	(CamelSession *session,
-						 CamelSessionThreadMsg *msg);
-	gint		(*thread_queue)		(CamelSession *session,
-						 CamelSessionThreadMsg *msg,
-						 gint flags);
-	void		(*thread_status)	(CamelSession *session,
-						 CamelSessionThreadMsg *msg,
-						 const gchar *text,
-						 gint pc);
-
 	gboolean	(*lookup_addressbook)	(CamelSession *session,
 						 const gchar *name);
 	gboolean	(*forward_to)		(CamelSession *session,
@@ -144,6 +144,13 @@ struct _CamelSessionClass {
 						 CamelMimeMessage *message,
 						 const gchar *address,
 						 GError **error);
+
+	/* Signals */
+	void		(*job_started)		(CamelSession *session,
+						 GCancellable *cancellable);
+	void		(*job_finished)		(CamelSession *session,
+						 GCancellable *cancellable,
+						 const GError *error);
 };
 
 GType		camel_session_get_type		(void);
@@ -195,36 +202,10 @@ CamelFilterDriver *
 gboolean	camel_session_get_check_junk	(CamelSession *session);
 void		camel_session_set_check_junk	(CamelSession *session,
 						 gboolean check_junk);
-
-struct _CamelSessionThreadOps {
-	void (*receive)(CamelSession *session, CamelSessionThreadMsg *m);
-	void (*free)(CamelSession *session, CamelSessionThreadMsg *m);
-};
-
-struct _CamelSessionThreadMsg {
-	CamelMsg msg;
-
-	gint id;
-
-	GError *error;
-	CamelSessionThreadOps *ops;
-	GCancellable *cancellable;
-	CamelSession *session;
-
-	gpointer data;	/* Free for implementation to define, not
-			 * used by Camel, do not use in client code. */
-
-	/* user fields follow */
-};
-
-gpointer	camel_session_thread_msg_new	(CamelSession *session,
-						 CamelSessionThreadOps *ops,
-						 guint size);
-void		camel_session_thread_msg_free	(CamelSession *session,
-						 CamelSessionThreadMsg *msg);
-gint		camel_session_thread_queue	(CamelSession *session,
-						 CamelSessionThreadMsg *msg,
-						 gint flags);
+void		camel_session_submit_job	(CamelSession *session,
+						 CamelSessionCallback callback,
+						 gpointer user_data,
+						 GDestroyNotify notify);
 gboolean	camel_session_get_network_available
 						(CamelSession *session);
 void		camel_session_set_network_available
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index 8b4a233..8974d77 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -43,6 +43,8 @@
 #define d(x)
 #define dd(x) (camel_debug ("vfolder")?(x):0)
 
+typedef struct _FolderChangedData FolderChangedData;
+
 struct _CamelVeeFolderPrivate {
 	gboolean destroyed;
 	GList *folders;			/* lock using subfolder_lock before changing/accessing */
@@ -63,8 +65,7 @@ struct _update_data {
 	gboolean rebuilt, correlating;
 };
 
-struct _folder_changed_msg {
-	CamelSessionThreadMsg msg;
+struct _FolderChangedData {
 	CamelFolderChangeInfo *changes;
 	CamelFolder *sub;
 	CamelVeeFolder *vee_folder;
@@ -72,6 +73,16 @@ struct _folder_changed_msg {
 
 G_DEFINE_TYPE (CamelVeeFolder, camel_vee_folder, CAMEL_TYPE_FOLDER)
 
+static void
+folder_changed_data_free (FolderChangedData *data)
+{
+	camel_folder_change_info_free (data->changes);
+	g_object_unref (data->vee_folder);
+	g_object_unref (data->sub);
+
+	g_slice_free (FolderChangedData, data);
+}
+
 /* must be called with summary_lock held */
 static CamelVeeMessageInfo *
 vee_folder_add_uid (CamelVeeFolder *vf,
@@ -303,13 +314,15 @@ folder_changed_change_uid (CamelFolder *sub, const gchar *uid, const gchar hash[
 }
 
 static void
-folder_changed_change (CamelSession *session, CamelSessionThreadMsg *msg)
+folder_changed_change (CamelSession *session,
+                       GCancellable *cancellable,
+                       FolderChangedData *data,
+                       GError **error)
 {
-	struct _folder_changed_msg *m = (struct _folder_changed_msg *)msg;
-	CamelFolder *sub = m->sub;
-	CamelFolder *folder = (CamelFolder *)m->vee_folder;
-	CamelVeeFolder *vf = m->vee_folder;
-	CamelFolderChangeInfo *changes = m->changes;
+	CamelFolder *sub = data->sub;
+	CamelFolder *folder = CAMEL_FOLDER (data->vee_folder);
+	CamelVeeFolder *vf = data->vee_folder;
+	CamelFolderChangeInfo *changes = data->changes;
 	CamelStore *parent_store;
 	gchar *vuid = NULL, hash[8];
 	const gchar *uid;
@@ -647,21 +660,6 @@ subfolder_renamed_update (CamelVeeFolder *vf, CamelFolder *sub, gchar hash[8])
 	}
 }
 
-static void
-folder_changed_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _folder_changed_msg *m = (struct _folder_changed_msg *)msg;
-
-	camel_folder_change_info_free (m->changes);
-	g_object_unref (m->vee_folder);
-	g_object_unref (m->sub);
-}
-
-static CamelSessionThreadOps folder_changed_ops = {
-	folder_changed_change,
-	folder_changed_free,
-};
-
 static gint
 vee_folder_rebuild_folder (CamelVeeFolder *vee_folder,
                            CamelFolder *source,
@@ -1888,7 +1886,7 @@ vee_folder_folder_changed (CamelVeeFolder *vee_folder,
                            CamelFolderChangeInfo *changes)
 {
 	CamelVeeFolderPrivate *p = vee_folder->priv;
-	struct _folder_changed_msg *m;
+	FolderChangedData *data;
 	CamelStore *parent_store;
 	CamelSession *session;
 
@@ -1898,12 +1896,16 @@ vee_folder_folder_changed (CamelVeeFolder *vee_folder,
 	parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (vee_folder));
 	session = camel_service_get_session (CAMEL_SERVICE (parent_store));
 
-	m = camel_session_thread_msg_new (session, &folder_changed_ops, sizeof (*m));
-	m->changes = camel_folder_change_info_new ();
-	camel_folder_change_info_cat (m->changes, changes);
-	m->sub = g_object_ref (sub);
-	m->vee_folder = g_object_ref (vee_folder);
-	camel_session_thread_queue (session, &m->msg, 0);
+	data = g_slice_new0 (FolderChangedData);
+	data->changes = camel_folder_change_info_new ();
+	camel_folder_change_info_cat (data->changes, changes);
+	data->sub = g_object_ref (sub);
+	data->vee_folder = g_object_ref (vee_folder);
+
+	camel_session_submit_job (
+		session, (CamelSessionCallback)
+		folder_changed_change, data,
+		(GDestroyNotify) folder_changed_data_free);
 }
 
 static void
diff --git a/camel/providers/groupwise/camel-groupwise-folder.c b/camel/providers/groupwise/camel-groupwise-folder.c
index b9bfd16..bbb0fde 100644
--- a/camel/providers/groupwise/camel-groupwise-folder.c
+++ b/camel/providers/groupwise/camel-groupwise-folder.c
@@ -993,9 +993,9 @@ camel_gw_folder_new (CamelStore *store,
 	return folder;
 }
 
-struct _folder_update_msg {
-	CamelSessionThreadMsg msg;
+typedef struct _FolderUpdateData FolderUpdateData;
 
+struct _FolderUpdateData {
 	EGwConnection *cnc;
 	CamelFolder *folder;
 	gchar *container_id;
@@ -1004,10 +1004,23 @@ struct _folder_update_msg {
 };
 
 static void
+folder_update_data_free (FolderUpdateData *data)
+{
+	g_free (data->t_str);
+	g_free (data->container_id);
+	g_object_unref (data->folder);
+	g_slist_foreach (data->slist, (GFunc) g_free, NULL);
+	g_slist_free (data->slist);
+
+	g_slice_free (FolderUpdateData, data);
+}
+
+static void
 update_update (CamelSession *session,
-               CamelSessionThreadMsg *msg)
+               GCancellable *cancellable,
+               FolderUpdateData *data,
+               GError **error)
 {
-	struct _folder_update_msg *m = (struct _folder_update_msg *)msg;
 	EGwConnectionStatus status;
 	CamelGroupwiseStore *gw_store;
 	CamelStore *parent_store;
@@ -1018,14 +1031,14 @@ update_update (CamelSession *session,
 	const gchar *position = E_GW_CURSOR_POSITION_END;
 	gboolean done;
 
-	parent_store = camel_folder_get_parent_store (m->folder);
+	parent_store = camel_folder_get_parent_store (data->folder);
 	gw_store = CAMEL_GROUPWISE_STORE (parent_store);
 
 	service = CAMEL_SERVICE (gw_store);
 
 	/* Hold the connect_lock.
 	   In case if user went offline, don't do anything.
-	   m->cnc would have become invalid, as the store disconnect unrefs it.
+	   data->cnc would have become invalid, as the store disconnect unrefs it.
 	 */
 	camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 
@@ -1037,20 +1050,20 @@ update_update (CamelSession *session,
 	}
 
 	camel_operation_push_message (
-		msg->cancellable,
+		cancellable,
 		_("Checking for deleted messages %s"),
-		camel_folder_get_name (m->folder));
+		camel_folder_get_name (data->folder));
 
-	status = e_gw_connection_create_cursor (m->cnc, m->container_id, "id", NULL, &cursor);
+	status = e_gw_connection_create_cursor (data->cnc, data->container_id, "id", NULL, &cursor);
 	if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-		status = e_gw_connection_create_cursor (m->cnc, m->container_id, "id", NULL, &cursor);
+		status = e_gw_connection_create_cursor (data->cnc, data->container_id, "id", NULL, &cursor);
 	if (status != E_GW_CONNECTION_STATUS_OK) {
 		g_warning ("ERROR update update\n");
 		goto end1;
 	}
 
 	done = FALSE;
-	m->slist = NULL;
+	data->slist = NULL;
 
 	while (!done) {
 
@@ -1061,10 +1074,10 @@ update_update (CamelSession *session,
 		}
 
 		item_list = NULL;
-		status = e_gw_connection_get_all_mail_uids (m->cnc, m->container_id, cursor, FALSE, READ_CURSOR_MAX_IDS, position, &item_list);
+		status = e_gw_connection_get_all_mail_uids (data->cnc, data->container_id, cursor, FALSE, READ_CURSOR_MAX_IDS, position, &item_list);
 		if (status != E_GW_CONNECTION_STATUS_OK) {
 			g_warning ("ERROR update update\n");
-			e_gw_connection_destroy_cursor (m->cnc, m->container_id, cursor);
+			e_gw_connection_destroy_cursor (data->cnc, data->container_id, cursor);
 			goto end1;
 		}
 
@@ -1086,7 +1099,7 @@ update_update (CamelSession *session,
 		}
 		position = E_GW_CURSOR_POSITION_CURRENT;
 	}
-	e_gw_connection_destroy_cursor (m->cnc, m->container_id, cursor);
+	e_gw_connection_destroy_cursor (data->cnc, data->container_id, cursor);
 
 	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 	/* Take out only the first part in the list until the @ since it is guaranteed
@@ -1109,13 +1122,13 @@ 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_pop_message (msg->cancellable);
+	gw_update_all_items (data->folder, items_full_list, NULL, NULL);
+	camel_operation_pop_message (cancellable);
 
 	return;
  end1:
 	camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
-	camel_operation_pop_message (msg->cancellable);
+	camel_operation_pop_message (cancellable);
 	if (items_full_list) {
 		g_list_foreach (items_full_list, (GFunc)g_free, NULL);
 		g_list_free (items_full_list);
@@ -1123,24 +1136,6 @@ update_update (CamelSession *session,
 	return;
 }
 
-static void
-update_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _folder_update_msg *m = (struct _folder_update_msg *)msg;
-
-	g_free (m->t_str);
-	g_free (m->container_id);
-	g_object_unref (m->folder);
-	g_slist_foreach (m->slist, (GFunc) g_free, NULL);
-	g_slist_free (m->slist);
-	m->slist = NULL;
-}
-
-static CamelSessionThreadOps update_ops = {
-	update_update,
-	update_free,
-};
-
 static gint
 check_for_new_mails_count (CamelGroupwiseSummary *gw_summary, GSList *ids)
 {
@@ -1244,7 +1239,6 @@ groupwise_refresh_folder (CamelFolder *folder,
 	const gchar *full_name;
 	gchar *container_id = NULL;
 	gchar *old_sync_time = NULL, *new_sync_time = NULL, *modified_sync_time = NULL;
-	struct _folder_update_msg *msg;
 	gboolean sync_deleted = FALSE;
 	EGwContainer *container;
 	gint new_item_count = 0;
@@ -1384,13 +1378,18 @@ groupwise_refresh_folder (CamelFolder *folder,
 	 */
 	/*create a new session thread for the update all operation*/
 	if (sync_deleted || is_proxy) {
-		msg = camel_session_thread_msg_new (session, &update_ops, sizeof (*msg));
-		msg->cnc = cnc;
-		msg->t_str = g_strdup (old_sync_time);
-		msg->container_id = g_strdup (container_id);
-		msg->folder = g_object_ref (folder);
-		camel_session_thread_queue (session, &msg->msg, 0);
-		/*thread creation and queueing done*/
+		FolderUpdateData *data;
+
+		data = g_slice_new0 (FolderUpdateData);
+		data->cnc = cnc;
+		data->t_str = g_strdup (old_sync_time);
+		data->container_id = g_strdup (container_id);
+		data->folder = g_object_ref (folder);
+
+		camel_session_submit_job (
+			session, (CamelSessionCallback)
+			update_update, data,
+			(GDestroyNotify) folder_update_data_free);
 	}
 
 end3:
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index dc8cd8e..233e171 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -2773,52 +2773,36 @@ fill_fi (CamelStore *store, CamelFolderInfo *fi, guint32 flags)
 	}
 }
 
-struct _refresh_msg {
-	CamelSessionThreadMsg msg;
-
-	CamelStore *store;
-	GError *error;
-};
-
 static void
-refresh_refresh (CamelSession *session, CamelSessionThreadMsg *msg)
+refresh_refresh (CamelSession *session,
+                 GCancellable *cancellable,
+                 CamelImapStore *store,
+                 GError **error)
 {
-	struct _refresh_msg *m = (struct _refresh_msg *)msg;
-	CamelImapStore *store = (CamelImapStore *)m->store;
-
-	camel_service_lock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
+	camel_service_lock (
+		CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 
-	if (!camel_imap_store_connected (store, &m->error))
+	if (!camel_imap_store_connected (store, error))
 		goto done;
 
 	if (store->users_namespace && store->users_namespace[0]) {
-		if (!get_folders_sync (store, "INBOX", NULL, &m->error))
+		if (!get_folders_sync (store, "INBOX", cancellable, error))
 			goto done;
 	} else {
-		get_folders_sync (store, "*", NULL, NULL);
+		if (!get_folders_sync (store, "*", cancellable, error))
+			goto done;
 	}
 
 	/* look in all namespaces */
-	get_folders_sync (store, NULL, NULL, &m->error);
-	camel_store_summary_save ((CamelStoreSummary *)store->summary);
-done:
-	camel_service_unlock (CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
-}
+	get_folders_sync (store, NULL, cancellable, error);
 
-static void
-refresh_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _refresh_msg *m = (struct _refresh_msg *)msg;
+	camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
 
-	g_object_unref (m->store);
-	g_clear_error (&m->error);
+done:
+	camel_service_unlock (
+		CAMEL_SERVICE (store), CAMEL_SERVICE_REC_CONNECT_LOCK);
 }
 
-static CamelSessionThreadOps refresh_ops = {
-	refresh_refresh,
-	refresh_free,
-};
-
 static CamelFolderInfo *
 imap_store_get_folder_info_sync (CamelStore *store,
                                  const gchar *top,
@@ -2861,16 +2845,13 @@ imap_store_get_folder_info_sync (CamelStore *store,
 				service, CAMEL_SERVICE_REC_CONNECT_LOCK);
 			ref = now > imap_store->refresh_stamp+60*60*1;
 			if (ref) {
-				struct _refresh_msg *m;
-
 				imap_store->refresh_stamp = now;
 
-				m = camel_session_thread_msg_new (
-					session, &refresh_ops, sizeof (*m));
-				m->store = g_object_ref (store);
-				m->error = NULL;
-				camel_session_thread_queue (
-					session, &m->msg, 0);
+				camel_session_submit_job (
+					session, (CamelSessionCallback)
+					refresh_refresh,
+					g_object_ref (store),
+					(GDestroyNotify) g_object_unref);
 			}
 			camel_service_unlock (
 				service, CAMEL_SERVICE_REC_CONNECT_LOCK);
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index bb644ad..22549b8 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -1008,41 +1008,24 @@ sync_folders (CamelIMAPXStore *istore,
 	return TRUE;
 }
 
-struct _imapx_refresh_msg {
-	CamelSessionThreadMsg msg;
-	CamelStore *store;
-};
-
 static void
-imapx_refresh_finfo (CamelSession *session, CamelSessionThreadMsg *msg)
+imapx_refresh_finfo (CamelSession *session,
+                     GCancellable *cancellable,
+                     CamelIMAPXStore *store,
+                     GError **error)
 {
-	struct _imapx_refresh_msg *m = (struct _imapx_refresh_msg *)msg;
-	CamelIMAPXStore *istore = (CamelIMAPXStore *)m->store;
-
-	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore)))
+	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
 		return;
 
-	if (!camel_service_connect_sync ((CamelService *)istore, &msg->error))
+	if (!camel_service_connect_sync (CAMEL_SERVICE (store), error))
 		return;
 
 	/* look in all namespaces */
-	sync_folders (istore, "", FALSE, msg->cancellable, &msg->error);
-	camel_store_summary_save ((CamelStoreSummary *)istore->summary);
-}
+	sync_folders (store, "", FALSE, cancellable, error);
 
-static void
-imapx_refresh_free (CamelSession *session, CamelSessionThreadMsg *msg)
-{
-	struct _imapx_refresh_msg *m = (struct _imapx_refresh_msg *)msg;
-
-	g_object_unref (m->store);
+	camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
 }
 
-static CamelSessionThreadOps imapx_refresh_ops = {
-	imapx_refresh_finfo,
-	imapx_refresh_free,
-};
-
 static void
 discover_inbox (CamelStore *store,
                 GCancellable *cancellable)
@@ -1172,12 +1155,13 @@ imapx_store_get_folder_info_sync (CamelStore *store,
 		time_t now = time (NULL);
 
 		if (now - istore->last_refresh_time > FINFO_REFRESH_INTERVAL) {
-			struct _imapx_refresh_msg *m;
-
 			istore->last_refresh_time = time (NULL);
-			m = camel_session_thread_msg_new (session, &imapx_refresh_ops, sizeof (*m));
-			m->store = g_object_ref (store);
-			camel_session_thread_queue (session, &m->msg, 0);
+
+			camel_session_submit_job (
+				session, (CamelSessionCallback)
+				imapx_refresh_finfo,
+				g_object_ref (store),
+				(GDestroyNotify) g_object_unref);
 		}
 
 		fi = get_folder_info_offline (store, top, flags, error);
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index 6375105..3f95d87 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -1910,8 +1910,6 @@ camel_service_error_quark
 <TITLE>CamelSession</TITLE>
 CamelSession
 CamelSessionAlertType
-CamelSessionThreadOps
-CamelSessionThreadMsg
 camel_session_get_user_data_dir
 camel_session_set_socks_proxy
 camel_session_get_socks_proxy
@@ -1928,9 +1926,8 @@ camel_session_set_online
 camel_session_get_filter_driver
 camel_session_get_check_junk
 camel_session_set_check_junk
-camel_session_thread_msg_new
-camel_session_thread_msg_free
-camel_session_thread_queue
+CamelSessionCallback
+camel_session_submit_job
 camel_session_get_network_available
 camel_session_set_network_available
 camel_session_get_junk_headers
diff --git a/docs/reference/camel/tmpl/camel-session.sgml b/docs/reference/camel/tmpl/camel-session.sgml
index 2303f7b..fdd6495 100644
--- a/docs/reference/camel/tmpl/camel-session.sgml
+++ b/docs/reference/camel/tmpl/camel-session.sgml
@@ -26,55 +26,51 @@ CamelSession
 </para>
 
 
-<!-- ##### ARG CamelSession:check-junk ##### -->
+<!-- ##### SIGNAL CamelSession::job-finished ##### -->
 <para>
 
 </para>
 
-<!-- ##### ARG CamelSession:network-available ##### -->
+ camelsession: the object which received the signal.
+ arg1: 
+ arg2: 
+
+<!-- ##### SIGNAL CamelSession::job-started ##### -->
 <para>
 
 </para>
 
-<!-- ##### ARG CamelSession:online ##### -->
+ camelsession: the object which received the signal.
+ arg1: 
+
+<!-- ##### ARG CamelSession:check-junk ##### -->
 <para>
 
 </para>
 
-<!-- ##### ARG CamelSession:user-data-dir ##### -->
+<!-- ##### ARG CamelSession:network-available ##### -->
 <para>
 
 </para>
 
-<!-- ##### ENUM CamelSessionAlertType ##### -->
+<!-- ##### ARG CamelSession:online ##### -->
 <para>
 
 </para>
 
- CAMEL_SESSION_ALERT_INFO: 
- CAMEL_SESSION_ALERT_WARNING: 
- CAMEL_SESSION_ALERT_ERROR: 
-
-<!-- ##### STRUCT CamelSessionThreadOps ##### -->
+<!-- ##### ARG CamelSession:user-data-dir ##### -->
 <para>
 
 </para>
 
- receive: 
- free: 
-
-<!-- ##### STRUCT CamelSessionThreadMsg ##### -->
+<!-- ##### ENUM CamelSessionAlertType ##### -->
 <para>
 
 </para>
 
- msg: 
- id: 
- error: 
- ops: 
- cancellable: 
- session: 
- data: 
+ CAMEL_SESSION_ALERT_INFO: 
+ CAMEL_SESSION_ALERT_WARNING: 
+ CAMEL_SESSION_ALERT_ERROR: 
 
 <!-- ##### FUNCTION camel_session_get_user_data_dir ##### -->
 <para>
@@ -245,35 +241,26 @@ CamelSession
 @check_junk: 
 
 
-<!-- ##### FUNCTION camel_session_thread_msg_new ##### -->
+<!-- ##### USER_FUNCTION CamelSessionCallback ##### -->
 <para>
 
 </para>
 
 @session: 
- ops: 
- size: 
- Returns: 
-
-
-<!-- ##### FUNCTION camel_session_thread_msg_free ##### -->
-<para>
-
-</para>
-
- session: 
- msg: 
+ cancellable: 
+ user_data: 
+ error: 
 
 
-<!-- ##### FUNCTION camel_session_thread_queue ##### -->
+<!-- ##### FUNCTION camel_session_submit_job ##### -->
 <para>
 
 </para>
 
 @session: 
- msg: 
- flags: 
- Returns: 
+ callback: 
+ user_data: 
+ notify: 
 
 
 <!-- ##### FUNCTION camel_session_get_network_available ##### -->
diff --git a/docs/reference/camel/tmpl/camel-unused.sgml b/docs/reference/camel/tmpl/camel-unused.sgml
index c4200f6..0731365 100644
--- a/docs/reference/camel/tmpl/camel-unused.sgml
+++ b/docs/reference/camel/tmpl/camel-unused.sgml
@@ -4393,6 +4393,27 @@ streams
 </para>
 
 
+<!-- ##### STRUCT CamelSessionThreadMsg ##### -->
+<para>
+
+</para>
+
+ msg: 
+ id: 
+ error: 
+ ops: 
+ cancellable: 
+ session: 
+ data: 
+
+<!-- ##### STRUCT CamelSessionThreadOps ##### -->
+<para>
+
+</para>
+
+ receive: 
+ free: 
+
 <!-- ##### STRUCT CamelSimpleDataWrapper ##### -->
 <para>
 
@@ -8632,6 +8653,34 @@ streams
 @session: 
 @network_state: 
 
+<!-- ##### FUNCTION camel_session_thread_msg_free ##### -->
+<para>
+
+</para>
+
+ session: 
+ msg: 
+
+<!-- ##### FUNCTION camel_session_thread_msg_new ##### -->
+<para>
+
+</para>
+
+ session: 
+ ops: 
+ size: 
+ Returns: 
+
+<!-- ##### FUNCTION camel_session_thread_queue ##### -->
+<para>
+
+</para>
+
+ session: 
+ msg: 
+ flags: 
+ Returns: 
+
 <!-- ##### FUNCTION camel_spool_folder_new ##### -->
 <para>
 



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