[Fwd: pending patches]



-- 
Philip Van Hoof, freelance software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://pvanhoof.be/blog
http://codeminded.be
--- Begin Message ---
Hi,

   So I think I have them all ! To try keep it simple, I kept the numbering from Rob. Below some comments. The patch marked as "approved" had somehow a consensus on the mailing list so should be safe to commit. I let you decide for the others

* [PATCH_02_18]_Give_tny_folder_store_get_folders_a_refresh_parameter.patch
    includes additionnal patch to make compile with -DDBC
    => approved

* [PATCH_03_18]_New_observer_behaviour.patch
    also includes the patch to adapt the rest of the code to the new api
    some arguments from Sergio were answered by Rob
    => waiting for a confirmation from Sergio

* [PATCH_05_18]_Attempt_to_fix_the_queue_account_refcount.patch
    => approved

* [PATCH_06_18]_Fix_ref_leak_with_the_iter_store.patch
   Sergio found a problem with the original patch
   Discussed with Rob, the unref was indeed intented for iter_store and not store
    => approved

* [PATCH_07_18]Add_tny_camel_queue_stop.patch
   One remark from Sergio about a weird typedef but overall approved
   => approved

* [PATCH_10_18]_Make_TnySendQueue_interface_depend_on_TnyFolderStore.patch
   Original patch + renaming from observer-mixin.h to observer-mixin-priv.h
   => waiting for more review

* [PATCH_11_18]_Add_tny_camel_send_queue_new_with_folders.patch
   => approved

* [PATCH_12_18]_Create_TnyMergeFolderStore.patch
   original patch + renaming from observer-mixin.h to observer-mixin-priv.h
   => under discussion whether observer-mixin is a public or private type

* [PATCH_15_18]_In_TnyCamelFolder_don_t_emit_folder_store_change.patch
  => approved


We also have a new patch that has never been submitted to the ML. I'll wait a bit for the above to get reviewed/commited and will submit it a bit later. Tell me if you have any trouble.
Happy hacking !

--
Martin
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(révision 11)
+++ libtinymail-camel/tny-camel-folder.c	(révision 12)
@@ -3176,7 +3176,7 @@
 		TnyList *folders = tny_simple_list_new ();
 		TnyIterator *iter;
 
-		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, &nerr);
+		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, TRUE, &nerr);
 
 		if (nerr != NULL)
 		{
@@ -3348,7 +3348,7 @@
 	g_object_unref (acc);
 
 	list = func (list, cpy_event_new (TNY_FOLDER_STORE (into), folder));
-	tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, NULL);
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 	while (!tny_iterator_is_done (iter))
 	{
@@ -4884,8 +4884,8 @@
 		TnyList *folders = tny_simple_list_new ();
 		TnyIterator *iter;
 
-		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), 
-				folders, NULL, &nerr);
+		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder),
+				folders, NULL, TRUE, &nerr);
 
 		if (nerr != NULL)
 		{
@@ -5328,13 +5328,13 @@
 }
 
 static void
-tny_camel_folder_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_folder_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
-	TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders(self, list, query, err);
+	TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
 }
 
 static void 
-tny_camel_folder_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_folder_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
 	gboolean cant_reuse_iter = TRUE;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5365,7 +5365,11 @@
 
 		g_return_if_fail (priv->folder_name != NULL);
 
-		priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+		if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
+			priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store,  priv->folder_name, 0, &ex);
+		} else {
+			priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+		}
 
 		priv->cant_reuse_iter = FALSE;
 
@@ -5429,7 +5433,6 @@
 	return;
 }
 
-
 typedef struct 
 {
 	TnyCamelQueueable parent;
@@ -5439,6 +5442,7 @@
 	TnyList *list;
 	TnyGetFoldersCallback callback;
 	TnyFolderStoreQuery *query;
+	gboolean refresh;
 	gpointer user_data;
 	TnySessionCamel *session;
 	gboolean cancelled;
@@ -5489,7 +5493,7 @@
 	GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
 
 	tny_folder_store_get_folders (TNY_FOLDER_STORE (info->self),
-		info->list, info->query, &info->err);
+		info->list, info->query, info->refresh, &info->err);
 
 	info->cancelled = FALSE;
 	if (info->err != NULL) {
@@ -5536,14 +5540,14 @@
 }
 
 static void 
-tny_camel_folder_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_folder_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
-	TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+	TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
 }
 
 
 static void 
-tny_camel_folder_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_folder_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
 	GetFoldersInfo *info;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5557,6 +5561,7 @@
 	info->callback = callback;
 	info->user_data = user_data;
 	info->query = query;
+	info->refresh = refresh;
 	info->err = NULL;
 
 	/* thread reference */
@@ -5579,7 +5584,201 @@
 	return;
 }
 
+static void
+tny_camel_folder_store_refresh (TnyFolderStore *self, GError **err)
+{
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+	CamelFolderInfo *iter;
+	TnyAccount *account = NULL;
+	CamelStore *store = priv->store;
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 
+	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), 
+			priv->account, err, TNY_ERROR_DOMAIN,
+			TNY_SERVICE_ERROR_GET_FOLDERS))
+		return;
+
+	account = tny_folder_get_account (TNY_FOLDER (self));
+
+	g_return_if_fail (priv->folder_name != NULL);
+
+	priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+	priv->cant_reuse_iter = FALSE;
+
+	if (camel_exception_is_set (&ex))
+	{
+		_tny_camel_exception_to_tny_error (&ex, err);
+		camel_exception_clear (&ex);
+		_tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
+
+		if (priv->iter == NULL)
+			return;
+	}
+
+	priv->iter_parented = FALSE;
+
+	iter = priv->iter;
+ 
+	if (iter)
+	{
+	  iter = iter->child;
+	  while (iter)
+	  {
+		/* Also take a look at camel-maildir-store.c:525 */
+		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && priv->account)
+		{
+			gboolean was_new = FALSE;
+			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+				TNY_CAMEL_STORE_ACCOUNT (priv->account),
+				iter->full_name, &was_new);
+			if (was_new) {
+				TnyFolderStoreChange *change;
+				_tny_camel_folder_set_folder_info (self, folder, iter);
+				change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+				tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+				notify_folder_store_observers_about_in_idle (self,
+					change,
+					TNY_FOLDER_PRIV_GET_SESSION (priv));
+				g_object_unref(change);
+			}
+			g_object_unref (folder);
+		}
+		iter = iter->next;
+	  }
+	}
+
+
+	_tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
+
+	return;
+}
+
+typedef struct
+{
+	TnyCamelQueueable parent;
+
+	GError *err;
+	TnyFolderStore *self;
+	TnyFolderStoreCallback callback;
+	gpointer user_data;
+	TnySessionCamel *session;
+	gboolean cancelled;
+} StoreRefreshInfo;
+
+
+static void
+tny_camel_folder_store_refresh_async_destroyer (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+
+	/* thread reference */
+	_tny_camel_folder_unreason (priv);
+	g_object_unref (info->self);
+
+	if (info->err)
+		g_error_free (info->err);
+
+	_tny_session_stop_operation (info->session);
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_folder_store_refresh_async_callback (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, info->cancelled, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+
+static gpointer 
+tny_camel_folder_store_refresh_async_thread (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = (StoreRefreshInfo*) thr_user_data;
+
+	tny_camel_folder_store_refresh (TNY_FOLDER_STORE (info->self), &info->err);
+
+	info->cancelled = FALSE;
+	if (info->err != NULL) {
+		if (camel_strstrcase (info->err->message, "cancel") != NULL)
+			info->cancelled = TRUE;
+	}
+
+	return NULL;
+}
+
+static void
+tny_camel_folder_store_refresh_async_cancelled_destroyer (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+
+	/* thread reference */
+	_tny_camel_folder_unreason (priv);
+	g_object_unref (info->self);
+
+	if (info->err)
+		g_error_free (info->err);
+
+	/**/
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_folder_store_refresh_async_cancelled_callback (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, TRUE, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+static void
+tny_camel_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	StoreRefreshInfo *info;
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+
+	/* Idle info for the callbacks */
+	info = g_slice_new (StoreRefreshInfo);
+	info->session = TNY_FOLDER_PRIV_GET_SESSION (priv);
+	camel_object_ref (info->session);
+	info->self = self;
+	info->callback = callback;
+	info->user_data = user_data;
+	info->err = NULL;
+
+	/* thread reference */
+	_tny_camel_folder_reason (priv);
+	g_object_ref (info->self);
+
+	_tny_camel_queue_launch (TNY_FOLDER_PRIV_GET_QUEUE (priv),
+		tny_camel_folder_store_refresh_async_thread,
+		tny_camel_folder_store_refresh_async_callback,
+		tny_camel_folder_store_refresh_async_destroyer,
+		tny_camel_folder_store_refresh_async_cancelled_callback,
+		tny_camel_folder_store_refresh_async_cancelled_destroyer,
+		&info->cancelled,
+		info, sizeof (StoreRefreshInfo),
+		__FUNCTION__);
+
+	return;
+}
+
 void
 _tny_camel_folder_set_folder (TnyCamelFolder *self, CamelFolder *camel_folder)
 {
@@ -6230,6 +6429,7 @@
 	klass->get_folders_async= tny_camel_folder_get_folders_async;
 	klass->add_observer= tny_camel_folder_store_add_observer;
 	klass->remove_observer= tny_camel_folder_store_remove_observer;
+	klass->refresh_async = tny_camel_folder_store_refresh_async;
 
 	return;
 }
Index: libtinymail-camel/tny-camel-folder.h
===================================================================
--- libtinymail-camel/tny-camel-folder.h	(révision 11)
+++ libtinymail-camel/tny-camel-folder.h	(révision 12)
@@ -92,8 +92,8 @@
 	TnyFolderCaps (*get_caps) (TnyFolder *self);
 	void (*remove_msgs_async) (TnyFolder *self, TnyList *headers, TnyFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 
-	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
-	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
 	void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
 	TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
 	void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(révision 11)
+++ libtinymail-camel/tny-camel-store-account.c	(révision 12)
@@ -952,7 +952,7 @@
 		TnyIterator *iter;
 
 		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), 
-				folders, NULL, &nerr);
+				folders, NULL, TRUE, &nerr);
 
 		if (nerr != NULL)
 		{
@@ -1276,9 +1276,9 @@
 
 
 static void
-tny_camel_store_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_store_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
-	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders(self, list, query, err);
+	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
 }
 
 /**
@@ -1351,7 +1351,7 @@
 }
 
 static void 
-tny_camel_store_account_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_camel_store_account_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
 	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
 	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);    
@@ -1401,9 +1401,15 @@
 
 	iter = priv->iter;
 
-	if (!iter || priv->cant_reuse_iter)
-		iter = camel_store_get_folder_info (store, "", flags, &ex);
+	if (!iter || priv->cant_reuse_iter) {
+		if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
+			priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store,  "", 0, &ex);
+		} else {
+			priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+		}
 
+	}
+
 	/*else
 		iter = priv->iter;*/
 
@@ -1472,6 +1478,7 @@
 	TnyList *list;
 	TnyGetFoldersCallback callback;
 	TnyFolderStoreQuery *query;
+	gboolean refresh;
 	gpointer user_data;
 	TnySessionCamel *session;
 	gboolean cancelled;
@@ -1518,7 +1525,7 @@
 	GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
 
 	tny_folder_store_get_folders (TNY_FOLDER_STORE (info->self),
-		info->list, info->query, &info->err);
+		info->list, info->query, info->refresh, &info->err);
 
 	info->cancelled = FALSE;
 	if (info->err != NULL) {
@@ -1559,13 +1566,13 @@
 }
 
 static void
-tny_camel_store_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_store_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
-	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
 }
 
 static void 
-tny_camel_store_account_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_camel_store_account_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
 	GetFoldersInfo *info;
 	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
@@ -1584,6 +1591,7 @@
 	info->callback = callback;
 	info->user_data = user_data;
 	info->query = query;
+	info->refresh = refresh;
 
 	/* thread reference */
 	g_object_ref (info->self);
@@ -1604,8 +1612,222 @@
 	return;
 }
 
+static void
+tny_camel_store_account_store_refresh (TnyFolderStore *self, GError **err)
+{
+	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
 
+	g_assert (CAMEL_IS_SESSION (apriv->session));
+
+	if (!_tny_session_check_operation (apriv->session, TNY_ACCOUNT (self), err, 
+			TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_GET_FOLDERS))
+		return;
+
+	if (apriv->service == NULL || !CAMEL_IS_SERVICE (apriv->service))
+	{
+		g_set_error (err, TNY_ERROR_DOMAIN,
+				TNY_SERVICE_ERROR_GET_FOLDERS,
+				_("Account not ready for this operation. "
+				"This problem indicates a bug in the software."));
+		_tny_session_stop_operation (apriv->session);
+		return;
+	}
+
+	store = CAMEL_STORE (apriv->service);
+
+	if (camel_exception_is_set (&ex))
+	{
+		_tny_camel_exception_to_tny_error (&ex, err);
+		camel_exception_clear (&ex);
+		_tny_session_stop_operation (apriv->session);
+		return;
+	}
+
+	g_assert (CAMEL_IS_STORE (store));
+
+	flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL |
+		CAMEL_STORE_FOLDER_INFO_RECURSIVE;
+
+	if (!camel_session_is_online ((CamelSession*) apriv->session))
+		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
+
+	priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+
+	if (camel_exception_is_set (&ex))
+	{
+		_tny_camel_exception_to_tny_error (&ex, err);
+		camel_exception_clear (&ex);
+
+		_tny_session_stop_operation (apriv->session);
+
+		return;
+	}
+
+	priv->cant_reuse_iter = FALSE;
+
+	camel_object_ref (CAMEL_OBJECT (store));
+	priv->iter_store = store;
+
+	iter = priv->iter;
+
+	if (iter)
+	{
+	  iter = iter->child;
+	  while (iter)
+	  {
+		/* Also take a look at camel-maildir-store.c:525 */
+		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
+		{
+			gboolean was_new = FALSE;
+			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+				TNY_CAMEL_STORE_ACCOUNT (self),
+				iter->full_name, &was_new);
+			if (was_new) {
+				TnyFolderStoreChange *change;
+				_tny_camel_folder_set_folder_info (self, folder, iter);
+				change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+				tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+				notify_folder_store_observers_about_in_idle (self,
+					change);
+				g_object_unref(change);
+			}
+			g_object_unref (folder);
+		}
+		iter = iter->next;
+	  }
+	}
+
+
+	_tny_session_stop_operation (apriv->session);
+
+	return;
+}
+
+
+typedef struct
+{
+	TnyCamelQueueable parent;
+
+	GError *err;
+	TnyFolderStore *self;
+	TnyFolderStoreCallback callback;
+	gpointer user_data;
+	TnySessionCamel *session;
+	gboolean cancelled;
+
+} StoreRefreshInfo;
+
+
 static void
+tny_camel_store_account_store_refresh_async_destroyer (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+
+	/* gidle reference */
+	g_object_unref (info->self);
+
+	if (info->err)
+		g_error_free (info->err);
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_store_account_store_refresh_async_callback (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, info->cancelled, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+
+static gpointer
+tny_camel_store_account_store_refresh_async_thread (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = (StoreRefreshInfo*) thr_user_data;
+
+	tny_camel_store_account_store_refresh (TNY_FOLDER_STORE (info->self), &info->err);
+
+	info->cancelled = FALSE;
+	if (info->err != NULL) {
+		if (camel_strstrcase (info->err->message, "cancel") != NULL)
+			info->cancelled = TRUE;
+	}
+
+	return NULL;
+}
+
+static void
+tny_camel_store_account_store_refresh_async_cancelled_destroyer (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	/* gidle references */
+	g_object_unref (info->self);
+	if (info->err)
+		g_error_free (info->err);
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_store_account_store_refresh_async_cancelled_callback (gpointer thr_user_data)
+{
+	StoreRefreshInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, TRUE, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+static void
+tny_camel_store_account_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	StoreRefreshInfo *info;
+	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+
+	/* Idle info for the callbacks */
+	info = g_slice_new0 (StoreRefreshInfo);
+	info->session = apriv->session;
+	camel_object_ref (info->session);
+
+	info->err = NULL;
+	info->self = self;
+	info->callback = callback;
+	info->user_data = user_data;
+
+	/* thread reference */
+	g_object_ref (info->self);
+
+	_tny_camel_queue_launch_wflags (priv->queue,
+		tny_camel_store_account_store_refresh_async_thread,
+		tny_camel_store_account_store_refresh_async_callback,
+		tny_camel_store_account_store_refresh_async_destroyer,
+		tny_camel_store_account_store_refresh_async_cancelled_callback,
+		tny_camel_store_account_store_refresh_async_cancelled_destroyer,
+		&info->cancelled, info, sizeof (StoreRefreshInfo),
+		TNY_CAMEL_QUEUE_NORMAL_ITEM|TNY_CAMEL_QUEUE_PRIORITY_ITEM,
+		__FUNCTION__);
+
+	return;
+}
+
+
+static void
 tny_camel_store_account_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
 {
 	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->add_observer(self, observer);
@@ -2072,6 +2294,7 @@
 	klass->get_folders_async= tny_camel_store_account_get_folders_async;
 	klass->add_observer= tny_camel_store_account_add_observer;
 	klass->remove_observer= tny_camel_store_account_remove_observer;
+	klass->refresh_async = tny_camel_store_account_store_refresh_async;
 
 	return;
 }
Index: libtinymail-camel/tny-camel-store-account.h
===================================================================
--- libtinymail-camel/tny-camel-store-account.h	(révision 11)
+++ libtinymail-camel/tny-camel-store-account.h	(révision 12)
@@ -49,8 +49,8 @@
 	TnyCamelAccountClass parent;
 
 	/* virtual methods */
-	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
-	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
 	void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
 	TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
 	void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
Index: ChangeLog
===================================================================
--- ChangeLog	(révision 11)
+++ ChangeLog	(révision 12)
@@ -1,5 +1,19 @@
 2008-09-23  Rob Taylor  <rob taylor codethink co uk>
 
+	* libtinymail-camel/tny-camel-folder.c:
+	* libtinymail-camel/tny-camel-folder.h:
+	* libtinymail-camel/tny-camel-store-account.c:
+	* libtinymail-camel/tny-camel-store-account.h:
+	* libtinymail/tny-combined-account.c:
+	* libtinymail/tny-folder-store.c: (tny_folder_store_get_folders),
+	* libtinymail/tny-folder-store.h:
+	* libtinymail/tny-shared.h:
+	Give tny_folder_store_get_folders a refresh parameter, for optionally not refreshing from the server.
+	Add tny_folder_store_refresh_async that will asynchronously refresh the store from the server, emitting TnyFolderStoreChanged events to observers.
+	Implement it all for camel.
+
+2008-09-23  Rob Taylor  <rob taylor codethink co uk>
+
 	* libtinymail-camel/camel-lite/camel/providers/pop3/camel-pop3-folder.c
 	(pop3_sync): In pop3 provider, do a LIST before a folder sync so
 	failure doesnt happen if wait_for_login_delay kills the store
Index: libtinymail/tny-shared.h
===================================================================
--- libtinymail/tny-shared.h	(révision 11)
+++ libtinymail/tny-shared.h	(révision 12)
@@ -137,6 +137,7 @@
 
 typedef TnyStream* (*TnyStreamCacheOpenStreamFetcher) (TnyStreamCache *self, gint64 *expected_size, gpointer userdata);
 typedef gboolean (*TnyStreamCacheRemoveFilter) (TnyStreamCache *self, const gchar *id, gpointer userdata);
+typedef void (*TnyFolderStoreCallback) (TnyFolderStore *self, gboolean cancelled, GError *err, gpointer user_data);
 
 /** 
  * TnyGetMsgCallback:
Index: libtinymail/tny-combined-account.c
===================================================================
--- libtinymail/tny-combined-account.c	(révision 11)
+++ libtinymail/tny-combined-account.c	(révision 12)
@@ -299,22 +299,30 @@
 }
 
 static void
-tny_combined_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_combined_account_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
 	TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
 
-	tny_folder_store_get_folders (TNY_FOLDER_STORE (priv->store_account), list, query, err);
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (priv->store_account), list, query, refresh, err);
 }
 
 static void
-tny_combined_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_combined_account_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
 	TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
 
-	tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->store_account), list, query, callback, status_callback, user_data);
+	tny_folder_store_get_folders_async (TNY_FOLDER_STORE (priv->store_account), list, query, refresh, callback, status_callback, user_data);
 }
 
 static void
+tny_combined_account_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
+
+	tny_folder_store_refresh_async (TNY_FOLDER_STORE (priv->store_account), callback, status_callback, user_data);
+}
+
+static void
 tny_combined_account_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
 {
 	TnyCombinedAccountPriv *priv = TNY_COMBINED_ACCOUNT_GET_PRIVATE (self);
@@ -540,6 +548,7 @@
 	klass->get_folders_async= tny_combined_account_get_folders_async;
 	klass->add_observer= tny_combined_account_add_observer;
 	klass->remove_observer= tny_combined_account_remove_observer;
+	klass->refresh_async = tny_combined_account_refresh_async;
 }
 
 static void
Index: libtinymail/tny-folder-store.c
===================================================================
--- libtinymail/tny-folder-store.c	(révision 11)
+++ libtinymail/tny-folder-store.c	(révision 12)
@@ -266,6 +266,7 @@
  * @self: a #TnyFolderStore
  * @list: a #TnyList to to which the folders will be prepended
  * @query: (null-ok): a #TnyFolderStoreQuery or NULL
+ * @refresh: synchronize with the service first
  * @err: (null-ok): a #GError or NULL
  *
  * Get a list of child folders from @self. You can use @query to limit the list 
@@ -277,7 +278,7 @@
  * TnyFolderStore *store = ...
  * TnyIterator *iter; TnyFolderStoreQuery *query = ...
  * TnyList *folders = tny_simple_list_new ();
- * tny_folder_store_get_folders (store, folders, query, NULL);
+ * tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
  * iter = tny_list_create_iterator (folders);
  * while (!tny_iterator_is_done (iter))
  * {
@@ -295,7 +296,7 @@
  * audience: application-developer
  **/
 void 
-tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err)
+tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
 {
 #ifdef DBC /* require */
 	g_assert (TNY_IS_FOLDER_STORE (self));
@@ -306,7 +307,7 @@
 	g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->get_folders!= NULL);
 #endif
 
-	TNY_FOLDER_STORE_GET_IFACE (self)->get_folders(self, list, query, err);
+	TNY_FOLDER_STORE_GET_IFACE (self)->get_folders(self, list, query, refresh, err);
 
 #ifdef DBC /* ensure */
 #endif
@@ -343,6 +344,7 @@
  * @self: a #TnyFolderStore
  * @list: a #TnyList to to which the folders will be prepended
  * @query: (null-ok): A #TnyFolderStoreQuery object
+ * @refresh: synchronize with the service first
  * @callback: (null-ok): a #TnyGetFoldersCallback or NULL
  * @status_callback: (null-ok): a #TnyStatusCallback or NULL
  * @user_data: (null-ok): user data that will be passed to the callbacks
@@ -363,7 +365,7 @@
  *         TnyList *folders = tny_simple_list_new ();
  *         g_print ("%s\n", tny_folder_get_name (TNY_FOLDER (folder)));
  *         tny_folder_store_get_folders_async (folder,
- *             folders, NULL, callback, NULL, NULL);
+ *             folders, NULL, true, callback, NULL, NULL);
  *         g_object_unref (folder);
  *         tny_iterator_next (iter);
  *     }
@@ -375,7 +377,7 @@
  *     TnyList *folders;
  *     folders = tny_simple_list_new ();
  *     tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
- *         folders, NULL, callback, NULL, NULL);
+ *         folders, NULL, TRUE, callback, NULL, NULL);
  *     g_object_unref (folders);
  * }
  * </programlisting></informalexample>
@@ -388,7 +390,7 @@
  * audience: application-developer
  **/
 void 
-tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
 {
 #ifdef DBC /* require */
 	g_assert (TNY_IS_FOLDER_STORE (self));
@@ -399,7 +401,7 @@
 	g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async!= NULL);
 #endif
 
-	TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async(self, list, query, callback, status_callback, user_data);
+	TNY_FOLDER_STORE_GET_IFACE (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
 
 #ifdef DBC /* ensure */
 #endif
@@ -408,7 +410,21 @@
 }
 
 
+void tny_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+#ifdef DBC /* require */
+	g_assert (TNY_IS_FOLDER_STORE (self));
+	g_assert (TNY_FOLDER_STORE_GET_IFACE (self)->refresh_async != NULL);
+#endif
 
+	TNY_FOLDER_STORE_GET_IFACE (self)->refresh_async(self, callback, status_callback, user_data);
+
+#ifdef DBC /* ensure */
+#endif
+
+	return;
+}
+
 static void
 tny_folder_store_base_init (gpointer g_class)
 {
Index: libtinymail/tny-folder-store.h
===================================================================
--- libtinymail/tny-folder-store.h	(révision 11)
+++ libtinymail/tny-folder-store.h	(révision 12)
@@ -48,10 +48,11 @@
 	void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
 	TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
 	void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
-	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
-	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
+	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 	void (*add_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
 	void (*remove_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+	void (*refresh_async) (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 
 };
 
@@ -59,12 +60,13 @@
 
 void tny_folder_store_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err);
 void tny_folder_store_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
-void tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+void tny_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 void tny_folder_store_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer);
 void tny_folder_store_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+void tny_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 
 #ifndef TNY_DISABLE_DEPRECATED
-void tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, GError **err);
+void tny_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
 TnyFolder *tny_folder_store_create_folder (TnyFolderStore *self, const gchar *name, GError **err);
 #endif
 
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(révision 12)
+++ libtinymail-camel/tny-camel-folder.c	(révision 15)
@@ -1533,6 +1533,23 @@
 }
 #endif
 
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (user_data);
+	g_hash_table_remove (priv->known_folders, folder);
+}
+
+
+static gboolean
+known_folder_remover (GObject *folder,
+                      gpointer value,
+                      TnyCamelFolder *self)
+{
+	g_object_weak_unref (folder, known_folder_del, self);
+	return TRUE;
+}
+
 void
 _tny_camel_folder_set_account (TnyCamelFolder *self, TnyAccount *account)
 {
@@ -5032,7 +5049,6 @@
 			    "in the software\n");
 
 	_tny_camel_folder_set_name (folder, info->name);
-	_tny_camel_folder_set_iter (folder, info);
 
 	if (TNY_IS_CAMEL_FOLDER (self)) {
 		TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
@@ -5041,6 +5057,7 @@
 		_tny_camel_folder_set_account (folder, TNY_ACCOUNT (self));
 	}
 
+	_tny_camel_folder_set_iter (folder, info);
 	_tny_camel_folder_set_parent (folder, self);
 }
 
@@ -5309,10 +5326,10 @@
 	}
 }
 
-void 
-_tny_camel_folder_set_iter (TnyCamelFolder *folder, CamelFolderInfo *iter)
+void
+_tny_camel_folder_set_iter (TnyCamelFolder *self, CamelFolderInfo *iter)
 {
-	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (folder);
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
 
 	priv->cant_reuse_iter = FALSE;
 	priv->iter = iter;
@@ -5324,6 +5341,32 @@
 
 	priv->iter_parented = TRUE;
 
+	//fill up known-folders with the folders we know about from this iter.
+	if (iter)
+	{
+	  iter = iter->child;
+	  while (iter)
+	  {
+		/* Also take a look at camel-maildir-store.c:525 */
+		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
+		{
+			gboolean was_new = FALSE;
+			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+				TNY_CAMEL_STORE_ACCOUNT (priv->account),
+				iter->full_name, &was_new);
+
+			if (was_new)
+				_tny_camel_folder_set_folder_info (TNY_FOLDER_STORE(self), folder, iter);
+
+			if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+				g_hash_table_insert(priv->known_folders, folder, NULL);
+				g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+			}
+			g_object_unref (folder);
+		}
+		iter = iter->next;
+	  }
+	}
 	return;
 }
 
@@ -5340,6 +5383,7 @@
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
 	CamelFolderInfo *iter;
 	TnyAccount *account = NULL;
+	gboolean first_time = FALSE;
 
 	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), 
 			priv->account, err, TNY_ERROR_DOMAIN,
@@ -5366,11 +5410,15 @@
 		g_return_if_fail (priv->folder_name != NULL);
 
 		if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
-			priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store,  priv->folder_name, 0, &ex);
+			iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store,  priv->folder_name, 0, &ex);
 		} else {
-			priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+			iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
 		}
 
+		if (iter && priv->iter == NULL)  {
+			first_time = TRUE;
+		}
+		priv->iter = iter;
 		priv->cant_reuse_iter = FALSE;
 
 		if (camel_exception_is_set (&ex))
@@ -5388,25 +5436,52 @@
 
 	iter = priv->iter;
  
-	if (iter)
+	if (iter && priv->account)
 	{
+	  TnyFolderStoreChange *change = NULL;
+
 	  iter = iter->child;
 	  while (iter)
 	  {
 		/* Also take a look at camel-maildir-store.c:525 */
-		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && _tny_folder_store_query_passes (query, iter) && priv->account)
+		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
 		{
 			gboolean was_new = FALSE;
 			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
-				TNY_CAMEL_STORE_ACCOUNT (priv->account), 
+				TNY_CAMEL_STORE_ACCOUNT (priv->account),
 				iter->full_name, &was_new);
+
 			if (was_new)
 				_tny_camel_folder_set_folder_info (self, folder, iter);
-			tny_list_prepend (list, G_OBJECT (folder));
+
+			if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+				g_hash_table_insert(priv->known_folders, folder, NULL);
+				g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+				if (!change)
+					change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+				if (first_time) {
+					tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+				} else {
+					tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+				}
+
+			}
+
+			if (_tny_folder_store_query_passes (query, iter)) {
+				tny_list_prepend (list, G_OBJECT (folder));
+			}
 			g_object_unref (folder);
 		}
 		iter = iter->next;
 	  }
+	  if (change) {
+		notify_folder_store_observers_about_in_idle (self, change,
+			TNY_FOLDER_PRIV_GET_SESSION (priv));
+		g_object_unref(change);
+	  }
 	}
 
 #ifdef MERGEFOLDERTEST
@@ -5592,18 +5667,16 @@
 	TnyAccount *account = NULL;
 	CamelStore *store = priv->store;
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	gboolean first_time = FALSE;
 
 	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), 
 			priv->account, err, TNY_ERROR_DOMAIN,
 			TNY_SERVICE_ERROR_GET_FOLDERS))
 		return;
 
-	account = tny_folder_get_account (TNY_FOLDER (self));
-
 	g_return_if_fail (priv->folder_name != NULL);
 
-	priv->iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
-	priv->cant_reuse_iter = FALSE;
+	iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
 
 	if (camel_exception_is_set (&ex))
 	{
@@ -5615,36 +5688,59 @@
 			return;
 	}
 
+	priv->cant_reuse_iter = FALSE;
 	priv->iter_parented = FALSE;
 
-	iter = priv->iter;
- 
-	if (iter)
+	if (iter && priv->iter == NULL)  {
+		first_time = TRUE;
+	}
+
+	priv->iter = iter;
+
+	if (iter && priv->account)
 	{
+	  TnyFolderStoreChange *change = NULL;
 	  iter = iter->child;
 	  while (iter)
 	  {
 		/* Also take a look at camel-maildir-store.c:525 */
-		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && priv->account)
+		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
 		{
 			gboolean was_new = FALSE;
 			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
 				TNY_CAMEL_STORE_ACCOUNT (priv->account),
 				iter->full_name, &was_new);
-			if (was_new) {
-				TnyFolderStoreChange *change;
+			if (was_new)
 				_tny_camel_folder_set_folder_info (self, folder, iter);
-				change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
-				tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
-				notify_folder_store_observers_about_in_idle (self,
-					change,
-					TNY_FOLDER_PRIV_GET_SESSION (priv));
-				g_object_unref(change);
+
+			if (was_new)
+				_tny_camel_folder_set_folder_info (self, folder, iter);
+
+			if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+				g_hash_table_insert(priv->known_folders, folder, NULL);
+				g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+				if (!change)
+					change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+				if (first_time) {
+					tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+				} else {
+					tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+				}
+
 			}
 			g_object_unref (folder);
 		}
 		iter = iter->next;
 	  }
+	  if (change) {
+		notify_folder_store_observers_about_in_idle (self, change,
+			TNY_FOLDER_PRIV_GET_SESSION (priv));
+		g_object_unref(change);
+	  }
+
 	}
 
 
@@ -6094,10 +6190,20 @@
 	g_static_rec_mutex_unlock (priv->obs_lock);
 }
 
+static void build_appeared_change (gpointer key,
+                                   gpointer value,
+                                   gpointer user_data)
+{
+	TnyFolder *folder = key;
+	TnyFolderStoreChange *change = user_data;
+	tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
 static void
 tny_camel_folder_store_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
 {
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+	TnyFolderStoreChange *change = tny_folder_store_change_new (self);
 
 	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
 
@@ -6108,6 +6214,10 @@
 	}
 	g_static_rec_mutex_unlock (priv->obs_lock);
 
+	g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+	notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
+	g_object_unref (change);
+
 	return;
 }
 
@@ -6257,6 +6367,9 @@
 	TnyCamelFolder *self = (TnyCamelFolder*) object;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
 
+	g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+	g_hash_table_unref(priv->known_folders);
+
 	if (priv->store)
 		camel_object_unref (priv->store);
 
@@ -6548,6 +6661,7 @@
 	priv->folder = NULL;
 	priv->cached_name = NULL;
 	priv->cached_folder_type = TNY_FOLDER_TYPE_UNKNOWN;
+	priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
 	priv->remove_strat = tny_camel_msg_remove_strategy_new ();
 	priv->receive_strat = tny_camel_full_msg_receive_strategy_new ();
 	priv->reason_lock = g_new0 (GStaticRecMutex, 1);
Index: libtinymail-camel/tny-camel-store-account-priv.h
===================================================================
--- libtinymail-camel/tny-camel-store-account-priv.h	(révision 12)
+++ libtinymail-camel/tny-camel-store-account-priv.h	(révision 15)
@@ -37,6 +37,7 @@
 	gboolean cant_reuse_iter;
 	GStaticRecMutex *factory_lock, *obs_lock;
 	TnyCamelQueue *queue, *msg_queue;
+	GHashTable *known_folders;
 	gboolean deleted;
 };
 
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(révision 12)
+++ libtinymail-camel/tny-camel-store-account.c	(révision 15)
@@ -767,6 +767,8 @@
 	priv->sobs = NULL;
 	priv->iter = NULL;
 	priv->cant_reuse_iter = TRUE;
+	priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
 	priv->factory_lock = g_new0 (GStaticRecMutex, 1);
 	g_static_rec_mutex_init (priv->factory_lock);
 	priv->obs_lock = g_new0 (GStaticRecMutex, 1);
@@ -798,12 +800,18 @@
 	g_static_rec_mutex_unlock (priv->obs_lock);
 }
 
+
+static gboolean known_folder_remover (GObject *folder, gpointer value, TnyCamelStoreAccount *self);
+
 static void
 tny_camel_store_account_dispose (GObject *object)
 {
 	TnyCamelStoreAccount *self = (TnyCamelStoreAccount *)object;
 	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
 
+	g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+	g_hash_table_unref (priv->known_folders);
+
 	if (priv->sobs) {
 		GList *copy = priv->sobs;
 		while (copy) {
@@ -1313,6 +1321,22 @@
 }
 
 
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (user_data);
+	g_hash_table_remove (priv->known_folders, folder);
+}
+
+static gboolean
+known_folder_remover (GObject *folder,
+                      gpointer value,
+                      TnyCamelStoreAccount *self)
+{
+	g_object_weak_unref (folder, known_folder_del, self);
+	return TRUE;
+}
+
 static TnyFolder * 
 tny_camel_store_account_factor_folder_default (TnyCamelStoreAccount *self, const gchar *full_name, gboolean *was_new)
 {
@@ -1357,6 +1381,7 @@
 	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);    
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;    
 	CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
+	gboolean first_time = FALSE;
 	
 	g_assert (TNY_IS_LIST (list));
 	g_assert (CAMEL_IS_SESSION (apriv->session));
@@ -1403,9 +1428,9 @@
 
 	if (!iter || priv->cant_reuse_iter) {
 		if (!refresh && CAMEL_IS_DISCO_STORE(store)) {
-			priv->iter = CAMEL_DISCO_STORE_CLASS(store)->get_folder_info_offline(store,  "", 0, &ex);
+			iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store,  "", 0, &ex);
 		} else {
-			priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+			iter = camel_store_get_folder_info (store, "", 0, &ex);
 		}
 
 	}
@@ -1424,6 +1449,11 @@
 			return;
 	}
 
+	if (iter && priv->iter == NULL)  {
+		first_time = TRUE;
+	}
+
+
 	priv->iter = iter;
 	priv->cant_reuse_iter = FALSE;
 
@@ -1434,33 +1464,53 @@
 	camel_object_ref (CAMEL_OBJECT (store));
 	priv->iter_store = store;
 
-	if (iter)
-	{
-	  while (iter)
-	  {
-		/* Also take a look at camel-maildir-store.c:525 */
-		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL) && _tny_folder_store_query_passes (query, iter))
-		{
-			gboolean was_new = FALSE;
 
-			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
-				TNY_CAMEL_STORE_ACCOUNT (self), 
-				iter->full_name, &was_new);
+	if (iter) {
+		TnyFolderStoreChange *change = NULL;
 
-			if (was_new && folder != NULL)
-				_tny_camel_folder_set_folder_info (self, folder, iter);
+		while (iter) {
+			/* Also take a look at camel-maildir-store.c:525 */
+			if (!(iter->flags & CAMEL_FOLDER_VIRTUAL)) {
+				gboolean was_new = FALSE;
 
-			if (folder != NULL)
-			{
-				const gchar *name = tny_folder_get_name (TNY_FOLDER(folder));
-				/* TNY TODO: Temporary fix for empty root folders */
-				if (name && strlen(name) > 0)
-					tny_list_prepend (list, G_OBJECT (folder));
+				TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+					TNY_CAMEL_STORE_ACCOUNT (self),
+					iter->full_name, &was_new);
+
+				if (folder != NULL && was_new)
+					_tny_camel_folder_set_folder_info (self, folder, iter);
+
+				if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+					g_hash_table_insert(priv->known_folders, folder, NULL);
+					g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+					if (!change)
+						change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+					if (first_time) {
+						tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+					} else {
+						tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+					}
+
+				}
+
+				if (folder != NULL && _tny_folder_store_query_passes (query, iter))
+				{
+					const gchar *name = tny_folder_get_name (TNY_FOLDER(folder));
+					/* TNY TODO: Temporary fix for empty root folders */
+					if (name && strlen(name) > 0)
+						tny_list_prepend (list, G_OBJECT (folder));
+				}
 				g_object_unref (G_OBJECT (folder));
 			}
+			iter = iter->next;
 		}
-		iter = iter->next;
-	  }
+		if (change) {
+			notify_folder_store_observers_about_in_idle (self, change);
+			g_object_unref(change);
+		}
 	}
 
 	_tny_session_stop_operation (apriv->session);
@@ -1619,6 +1669,7 @@
 	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 	CamelFolderInfo *iter=NULL; guint32 flags; CamelStore *store;
+	gboolean first_time = FALSE;
 
 	g_assert (CAMEL_IS_SESSION (apriv->session));
 
@@ -1655,7 +1706,7 @@
 		flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 
 
-	priv->iter = camel_store_get_folder_info (store, "", 0, &ex);
+	iter = camel_store_get_folder_info (store, "", 0, &ex);
 
 	if (camel_exception_is_set (&ex))
 	{
@@ -1667,41 +1718,55 @@
 		return;
 	}
 
+	if (iter && priv->iter == NULL)  {
+		first_time = TRUE;
+	}
+
 	priv->cant_reuse_iter = FALSE;
-
 	camel_object_ref (CAMEL_OBJECT (store));
 	priv->iter_store = store;
+	priv->iter = iter;
 
-	iter = priv->iter;
+	if (iter) {
+		TnyFolderStoreChange *change = NULL;
 
-	if (iter)
-	{
-	  iter = iter->child;
-	  while (iter)
-	  {
-		/* Also take a look at camel-maildir-store.c:525 */
-		if (!(iter->flags & CAMEL_FOLDER_VIRTUAL))
-		{
-			gboolean was_new = FALSE;
-			TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
-				TNY_CAMEL_STORE_ACCOUNT (self),
-				iter->full_name, &was_new);
-			if (was_new) {
-				TnyFolderStoreChange *change;
-				_tny_camel_folder_set_folder_info (self, folder, iter);
-				change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
-				tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
-				notify_folder_store_observers_about_in_idle (self,
-					change);
-				g_object_unref(change);
+		while (iter) {
+			/* Also take a look at camel-maildir-store.c:525 */
+			if (!(iter->flags & CAMEL_FOLDER_VIRTUAL)) {
+				gboolean was_new = FALSE;
+
+				TnyCamelFolder *folder = (TnyCamelFolder *) tny_camel_store_account_factor_folder (
+					TNY_CAMEL_STORE_ACCOUNT (self),
+					iter->full_name, &was_new);
+
+				if (folder != NULL && was_new)
+					_tny_camel_folder_set_folder_info (self, folder, iter);
+
+				if (folder && !g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+					g_hash_table_insert(priv->known_folders, folder, NULL);
+					g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+
+					if (!change)
+						change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+
+
+					if (first_time) {
+						tny_folder_store_change_add_appeared_folder (change, TNY_FOLDER(folder));
+					} else {
+						tny_folder_store_change_add_created_folder (change, TNY_FOLDER(folder));
+					}
+				}
+
+				g_object_unref(folder);
 			}
-			g_object_unref (folder);
+			iter = iter->next;
 		}
-		iter = iter->next;
-	  }
+		if (change) {
+			notify_folder_store_observers_about_in_idle (self, change);
+			g_object_unref(change);
+		}
 	}
 
-
 	_tny_session_stop_operation (apriv->session);
 
 	return;
@@ -1833,10 +1898,21 @@
 	TNY_CAMEL_STORE_ACCOUNT_GET_CLASS (self)->add_observer(self, observer);
 }
 
+static void build_appeared_change (gpointer key,
+                                   gpointer value,
+                                   gpointer user_data)
+{
+	TnyFolder *folder = key;
+	TnyFolderStoreChange *change = user_data;
+	tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
+
 static void
 tny_camel_store_account_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
 {
 	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+	TnyFolderStoreChange *change = tny_folder_store_change_new (self);
 
 	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
 
@@ -1847,11 +1923,13 @@
 	}
 	g_static_rec_mutex_unlock (priv->obs_lock);
 
+	g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+	notify_folder_store_observers_about_in_idle (self, change);
+	g_object_unref (change);
+
 	return;
 }
 
-
-
 static void
 tny_camel_store_account_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
 {
Index: libtinymail-camel/tny-camel-folder-priv.h
===================================================================
--- libtinymail-camel/tny-camel-folder-priv.h	(révision 12)
+++ libtinymail-camel/tny-camel-folder-priv.h	(révision 15)
@@ -54,6 +54,7 @@
 	CamelException load_ex;
 	GList *obs, *sobs;
 	gboolean cant_reuse_iter;
+	GHashTable *known_folders;
 };
 
 CamelFolder* _tny_camel_folder_get_camel_folder (TnyCamelFolder *self);
Index: tests/functional/folder-lister-async.c
===================================================================
--- tests/functional/folder-lister-async.c	(révision 12)
+++ tests/functional/folder-lister-async.c	(révision 15)
@@ -58,7 +58,7 @@
 		TnyList *folders = tny_simple_list_new ();
 		g_print ("%s\n", tny_folder_get_name (TNY_FOLDER (folder)));
 		tny_folder_store_get_folders_async (folder,
-			folders, NULL, callback, NULL, NULL);
+			folders, NULL, TRUE, callback, NULL, NULL);
 		g_object_unref (G_OBJECT (folder));
 		tny_iterator_next (iter);
 	}
@@ -82,7 +82,7 @@
     
 	folders = tny_simple_list_new ();
     	tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account),
-		folders, NULL, callback, NULL, NULL);
+		folders, NULL, TRUE, callback, NULL, NULL);
     
 	return FALSE;
 }
Index: tests/functional/folder-remove.c
===================================================================
--- tests/functional/folder-remove.c	(révision 12)
+++ tests/functional/folder-remove.c	(révision 15)
@@ -56,7 +56,7 @@
 	TnyIterator *iter;
 	TnyList *folders = tny_simple_list_new ();
 
-	tny_folder_store_get_folders (store, folders, query, NULL);
+	tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter))
Index: tests/functional/account-refresh.c
===================================================================
--- tests/functional/account-refresh.c	(révision 12)
+++ tests/functional/account-refresh.c	(révision 15)
@@ -42,7 +42,7 @@
 	TnyIterator *iter;
 	TnyList *folders = tny_simple_list_new ();
 
-	tny_folder_store_get_folders (store, folders, query, NULL);
+	tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter)) {
@@ -89,6 +89,7 @@
 	tny_folder_store_get_folders (TNY_FOLDER_STORE (account),
 				      all_folders,
 				      NULL,
+				      TRUE,
 				      &error);
 	if (error)
 		goto out;
Index: tests/functional/msg-transfer.c
===================================================================
--- tests/functional/msg-transfer.c	(révision 12)
+++ tests/functional/msg-transfer.c	(révision 15)
@@ -49,7 +49,7 @@
 		return;
 
 	folders = tny_simple_list_new ();
-	tny_folder_store_get_folders (store, folders, query, NULL);
+	tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter) && (!*folder_src || !*folder_dst))
Index: tests/functional/folder-lister.c
===================================================================
--- tests/functional/folder-lister.c	(révision 12)
+++ tests/functional/folder-lister.c	(révision 15)
@@ -42,7 +42,7 @@
 	TnyIterator *iter;
 	TnyList *folders = tny_simple_list_new ();
 
-	tny_folder_store_get_folders (store, folders, query, NULL);
+	tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter))
Index: tests/functional/folder-transfer.c
===================================================================
--- tests/functional/folder-transfer.c	(révision 12)
+++ tests/functional/folder-transfer.c	(révision 15)
@@ -62,7 +62,7 @@
 	TnyIterator *iter;
 	TnyList *folders = tny_simple_list_new ();
 
-	tny_folder_store_get_folders (store, folders, query, NULL);
+	tny_folder_store_get_folders (store, folders, query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter))
Index: tests/c-demo/tny-demoui-summary-view.c
===================================================================
--- tests/c-demo/tny-demoui-summary-view.c	(révision 12)
+++ tests/c-demo/tny-demoui-summary-view.c	(révision 15)
@@ -399,7 +399,7 @@
 	TnyList *folders = tny_simple_list_new ();
 	TnyIterator *f_iter;
 
-	tny_folder_store_get_folders (TNY_FOLDER_STORE (f_store), folders, NULL, NULL);
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (f_store), folders, NULL, TRUE, NULL);
 	f_iter = tny_list_create_iterator (folders);
 	while (!tny_iterator_is_done (f_iter))
 	{
@@ -1178,7 +1178,7 @@
 			tny_folder_store_query_add_item (query, folder_name, TNY_FOLDER_STORE_QUERY_OPTION_MATCH_ON_NAME);
 			g_free (folder_name);
 			list = tny_simple_list_new ();
-			tny_folder_store_get_folders (origin_store, list, query, NULL);
+			tny_folder_store_get_folders (origin_store, list, query, TRUE, NULL);
 			g_object_unref (query);
 			if (tny_list_get_length (list) == 1) {
 				TnyIterator *iter;
Index: tests/memory/memory-test.c
===================================================================
--- tests/memory/memory-test.c	(révision 12)
+++ tests/memory/memory-test.c	(révision 15)
@@ -127,11 +127,11 @@
 	topfolders = tny_simple_list_new ();
 	folders = tny_simple_list_new ();
 
-	tny_folder_store_get_folders (TNY_FOLDER_STORE (account), topfolders, NULL, NULL);
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (account), topfolders, NULL, TRUE, NULL);
 	topiter = tny_list_create_iterator (topfolders);
 	inbox = TNY_FOLDER (tny_iterator_get_current (topiter));
 
-	tny_folder_store_get_folders (TNY_FOLDER_STORE (inbox), folders, NULL, NULL);
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (inbox), folders, NULL, TRUE, NULL);
 
 	if (iter)
 		g_object_unref (iter);
Index: ChangeLog
===================================================================
--- ChangeLog	(révision 12)
+++ ChangeLog	(révision 15)
@@ -1,5 +1,18 @@
 2008-09-23  Rob Taylor  <rob taylor codethink co uk>
 
+	* libtinymailui-gtk/tny-gtk-folder-store-tree-model.c:
+	* tests/c-demo/tny-demoui-summary-view.c: (recurse_poke),
+	* tests/functional/account-refresh.c: (recurse_folders),
+	* tests/functional/folder-lister-async.c: (callback), (dance):
+	* tests/functional/folder-lister.c: (recurse_folders):
+	* tests/functional/folder-remove.c: (recurse_folders):
+	* tests/functional/folder-transfer.c: (recurse_folders):
+	* tests/functional/msg-transfer.c: (find_folders):
+	* tests/memory/memory-test.c: (main):
+	Change all usage of tny_folder_store_get_folders over to the new api
+
+2008-09-23  Rob Taylor  <rob taylor codethink co uk>
+
 	* libtinymail-camel/tny-camel-folder.c:
 	* libtinymail-camel/tny-camel-folder.h:
 	* libtinymail-camel/tny-camel-store-account.c:
@@ -13,7 +26,25 @@
 	Implement it all for camel.
 
 2008-09-23  Rob Taylor  <rob taylor codethink co uk>
+	* libtinymail-camel/tny-camel-folder.c:
+	* libtinymail-camel/tny-camel-store-account.c:
+	Notify observers about existing folders when they're attached.
 
+2008-09-23  Rob Taylor  <rob taylor codethink co uk>
+
+	* libtinymail-camel/tny-camel-folder-priv.h:
+	* libtinymail-camel/tny-camel-folder.c:
+	* libtinymail-camel/tny-camel-store-account-priv.h:
+	* libtinymail-camel/tny-camel-store-account.c:
+	* libtinymail/tny-folder-store-change.c:
+	* libtinymail/tny-folder-store-change.h:
+	New observer behaviour. Observers will get folders_appeared events when a
+	tny_folder_store_refresh or tny_folder_store_get_folders occurs and the cache
+	is loaded for the first time. They get folders_created events when a new folder
+	appears that we didn't know about before.
+
+2008-09-23  Rob Taylor  <rob taylor codethink co uk>
+
 	* libtinymail-camel/camel-lite/camel/providers/pop3/camel-pop3-folder.c
 	(pop3_sync): In pop3 provider, do a LIST before a folder sync so
 	failure doesnt happen if wait_for_login_delay kills the store
Index: libtinymail/tny-folder-store-change.c
===================================================================
--- libtinymail/tny-folder-store-change.c	(révision 12)
+++ libtinymail/tny-folder-store-change.c	(révision 15)
@@ -36,7 +36,7 @@
 
 struct _TnyFolderStoreChangePriv
 {
-	TnyList *created, *removed;
+	TnyList *created, *removed, *appeared;
 	GMutex *lock;
 	TnyFolderStore *folderstore;
 	TnyFolderStoreChangeChanged changed;
@@ -125,6 +125,35 @@
 }
 
 /**
+ * tny_folder_store_change_add_appeared_folder:
+ * @self: a #TnyFolderStoreChange
+ * @folder: a #TnyFolder to add to the changeset
+ *
+ * Add @folder to the changeset of appeared folders. This is an internal
+ * function not intended for application developers to alter.
+ *
+ * since: 1.0
+ * audience: tinymail-developer
+ **/
+void 
+tny_folder_store_change_add_appeared_folder (TnyFolderStoreChange *self, TnyFolder *folder)
+{
+	TnyFolderStoreChangePriv *priv = TNY_FOLDER_STORE_CHANGE_GET_PRIVATE (self);
+
+	g_mutex_lock (priv->lock);
+
+	if (!priv->appeared)
+		priv->appeared = tny_simple_list_new ();
+	tny_list_prepend (priv->appeared, G_OBJECT (folder));
+	priv->changed |= TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS;
+
+	g_mutex_unlock (priv->lock);
+
+	return;
+}
+
+
+/**
  * tny_folder_store_change_get_created_folders:
  * @self: a #TnyFolderStoreChange
  * @folders: a #TnyList where the created folders will be prepended to
@@ -168,8 +197,6 @@
 }
 
 
-
-
 /**
  * tny_folder_store_change_get_removed_folders:
  * @self: a #TnyFolderStoreChange
@@ -213,7 +240,52 @@
 	return;
 }
 
+
+
 /**
+ * tny_folder_store_change_get_appeared_folders:
+ * @self: a #TnyFolderStoreChange
+ * @folders: a #TnyList where the appeared folders will be prepended to
+ *
+ * Get the appeared folders in this changeset
+ *
+ * since: 1.0
+ * audience: application-developer
+ **/
+void 
+tny_folder_store_change_get_appeared_folders (TnyFolderStoreChange *self, TnyList *folders)
+{
+	TnyFolderStoreChangePriv *priv = TNY_FOLDER_STORE_CHANGE_GET_PRIVATE (self);
+	TnyIterator *iter;
+
+	g_assert (TNY_IS_LIST (folders));
+
+	g_mutex_lock (priv->lock);
+
+	if (!priv->appeared)
+	{
+		g_mutex_unlock (priv->lock);
+		return;
+	}
+
+	iter = tny_list_create_iterator (priv->appeared);
+
+	while (!tny_iterator_is_done (iter))
+	{
+		GObject *folder = tny_iterator_get_current (iter);
+		tny_list_prepend (folders, folder);
+		g_object_unref (folder);
+		tny_iterator_next (iter);
+	}
+
+	g_object_unref (iter);
+
+	g_mutex_unlock (priv->lock);
+
+	return;
+}
+
+/**
  * tny_folder_store_change_reset:
  * @self: a #TnyFolderStoreChange
  *
@@ -321,8 +393,11 @@
 		g_object_unref (G_OBJECT (priv->created));
 	if (priv->removed)
 		g_object_unref (G_OBJECT (priv->removed));
+	if (priv->appeared)
+		g_object_unref (G_OBJECT (priv->appeared));
 	priv->created = NULL;
 	priv->removed = NULL;
+	priv->appeared = NULL;
 
 	if (priv->folderstore)
 		g_object_unref (G_OBJECT (priv->folderstore));
Index: libtinymail/tny-folder-store-change.h
===================================================================
--- libtinymail/tny-folder-store-change.h	(révision 12)
+++ libtinymail/tny-folder-store-change.h	(révision 15)
@@ -45,7 +45,8 @@
 enum _TnyFolderStoreChangeChanged
 {
 	TNY_FOLDER_STORE_CHANGE_CHANGED_CREATED_FOLDERS = 1<<0,
-	TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS = 1<<1
+	TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS = 1<<1,
+	TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS = 1<<2
 };
 
 typedef enum _TnyFolderStoreChangeChanged TnyFolderStoreChangeChanged;
@@ -68,9 +69,11 @@
 
 void tny_folder_store_change_add_created_folder (TnyFolderStoreChange *self, TnyFolder *folder);
 void tny_folder_store_change_add_removed_folder (TnyFolderStoreChange *self, TnyFolder *folder);
+void tny_folder_store_change_add_appeared_folder (TnyFolderStoreChange *self, TnyFolder *folder);
 
 void tny_folder_store_change_get_created_folders (TnyFolderStoreChange *self, TnyList *folders);
 void tny_folder_store_change_get_removed_folders (TnyFolderStoreChange *self, TnyList *folders);
+void tny_folder_store_change_get_appeared_folders (TnyFolderStoreChange *self, TnyList *folders);
 
 void tny_folder_store_change_reset (TnyFolderStoreChange *self);
 TnyFolderStore* tny_folder_store_change_get_folder_store (TnyFolderStoreChange *self);
Index: libtinymailui-gtk/tny-gtk-folder-store-tree-model.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-store-tree-model.c	(révision 12)
+++ libtinymailui-gtk/tny-gtk-folder-store-tree-model.c	(révision 15)
@@ -115,7 +115,7 @@
 	TnyList *folders = tny_simple_list_new ();
 
 	/* TODO add error checking and reporting here */
-	tny_folder_store_get_folders (store, folders, self->query, NULL);
+	tny_folder_store_get_folders (store, folders, self->query, TRUE, NULL);
 	iter = tny_list_create_iterator (folders);
 
 	while (!tny_iterator_is_done (iter))
@@ -343,7 +343,7 @@
 
 	list = tny_simple_list_new ();
 	tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account), 
-		list, self->query, get_folders_cb, NULL, g_object_ref (self));
+		list, self->query, TRUE, get_folders_cb, NULL, g_object_ref (self));
 
 	return;
 }
@@ -522,7 +522,7 @@
 	 * before this one) */
 
 	tny_folder_store_get_folders_async (TNY_FOLDER_STORE (folder_store), 
-		folders, self->query, get_folders_cb, NULL, g_object_ref (self));
+		folders, self->query, TRUE,  get_folders_cb, NULL, g_object_ref (self));
 
 	/* recurse_folders_sync (self, TNY_FOLDER_STORE (folder_store), &name_iter);  */
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(révision 16)
+++ libtinymail-camel/tny-camel-store-account.c	(révision 17)
@@ -1724,6 +1724,10 @@
 	}
 
 	priv->cant_reuse_iter = FALSE;
+
+	if (priv->iter_store) {
+		camel_object_unref (CAMEL_OBJECT (priv->iter_store));
+	}
 	camel_object_ref (CAMEL_OBJECT (store));
 	priv->iter_store = store;
 	priv->iter = iter;
Index: libtinymail-camel/tny-camel-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-queue-priv.h	(révision 15)
+++ libtinymail-camel/tny-camel-queue-priv.h	(révision 16)
@@ -85,6 +85,7 @@
 void _tny_camel_queue_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
 void _tny_camel_queue_cancel_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
 gboolean _tny_camel_queue_has_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
+void _tny_camel_queue_stop (TnyCamelQueue *queue);
 
 G_END_DECLS
 
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c	(révision 15)
+++ libtinymail-camel/tny-camel-queue.c	(révision 16)
@@ -271,20 +271,20 @@
 			g_slice_free (QueueItem, item);
 
 		if (wait) {
+			g_object_ref (queue);
 			g_mutex_lock (queue->mutex);
 			queue->is_waiting = TRUE;
 			g_cond_wait (queue->condition, queue->mutex);
 			queue->is_waiting = FALSE;
 			g_mutex_unlock (queue->mutex);
+			g_object_unref (queue);
 		}
 	}
 
-	queue->thread = NULL;
 	queue->stopped = TRUE;
 
 	g_object_unref (queue);
-
-	return NULL;
+	g_thread_exit (NULL);
 }
 
 
@@ -443,7 +443,7 @@
 		queue->stopped = FALSE;
 		g_object_ref (queue);
 		queue->thread = g_thread_create (tny_camel_queue_thread_main_func, 
-			queue, FALSE, &err);
+			queue, TRUE, &err);
 		if (err) {
 			queue->stopped = TRUE;
 		}
@@ -514,6 +514,27 @@
 	return retval;
 }
 
+/**
+ * _tny_camel_queue_stop
+ * @queue: the queue
+ *
+ * Stop the thread and wait for it to finish
+ */
+void
+_tny_camel_queue_stop (TnyCamelQueue *queue)
+{
+
+	if (queue->thread) {
+		queue->stopped = TRUE;
+		g_mutex_lock (queue->mutex);
+		if (queue->is_waiting)
+			g_cond_broadcast (queue->condition);
+		g_mutex_unlock (queue->mutex);
+
+		g_thread_join (queue->thread);
+	}
+}
+
 static void 
 tny_camel_queue_class_init (TnyCamelQueueClass *class)
 {
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(révision 15)
+++ libtinymail-camel/tny-camel-store-account.c	(révision 16)
@@ -832,6 +832,7 @@
 		camel_object_unref (CAMEL_OBJECT (priv->iter_store));
 	}
 
+	_tny_camel_queue_stop (priv->msg_queue);
 	g_object_unref (priv->msg_queue);
 
 	return;
Index: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c	(révision 15)
+++ libtinymail-camel/tny-camel-account.c	(révision 16)
@@ -2198,6 +2198,7 @@
 
 	g_static_rec_mutex_unlock (priv->service_lock);
 
+	_tny_camel_queue_stop (priv->queue);
 	g_object_unref (priv->queue);
 	g_object_unref (priv->con_strat);
 
Index: libtinymail-camel/tny-camel-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-queue-priv.h	(révision 17)
+++ libtinymail-camel/tny-camel-queue-priv.h	(révision 18)
@@ -37,6 +37,7 @@
 typedef struct _TnyCamelQueue TnyCamelQueue;
 typedef struct _TnyCamelQueueable TnyCamelQueueable;
 typedef struct _TnyCamelQueueClass TnyCamelQueueClass;
+typedef void (*TnyCamelQueueStopCb)(gpointer);
 
 struct _TnyCamelQueue
 {
@@ -49,8 +50,13 @@
 	GMutex *mutex;
 	gboolean is_waiting;
 	GStaticRecMutex *lock;
-	gboolean stopped, next_uncancel;
+	gboolean stop;
+	gboolean running;
+	gboolean dead;
+	gboolean next_uncancel;
 	gpointer current;
+	TnyCamelQueueStopCb stop_callback;
+	gpointer stop_user_data;
 };
 
 struct _TnyCamelQueueClass 
@@ -85,7 +91,7 @@
 void _tny_camel_queue_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
 void _tny_camel_queue_cancel_remove_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
 gboolean _tny_camel_queue_has_items (TnyCamelQueue *queue, TnyCamelQueueItemFlags flags);
-void _tny_camel_queue_stop (TnyCamelQueue *queue);
+void _tny_camel_queue_stop (TnyCamelQueue *queue, TnyCamelQueueStopCb stop_cb, gpointer user_data);
 
 G_END_DECLS
 
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c	(révision 17)
+++ libtinymail-camel/tny-camel-queue.c	(révision 18)
@@ -46,7 +46,7 @@
 {
 	TnyCamelQueue *self = (TnyCamelQueue*) object;
 
-	self->stopped = TRUE;
+	self->stop = TRUE;
 
 	g_mutex_lock (self->mutex);
 	if (self->account)
@@ -75,7 +75,7 @@
 {
 	g_mutex_lock (queue->mutex);
 	queue->account = NULL;
-	queue->stopped = TRUE;
+	queue->stop = TRUE;
 	if (queue->is_waiting) {
 		g_cond_broadcast (queue->condition);
 	}
@@ -101,6 +101,32 @@
 	return TNY_CAMEL_QUEUE (self);
 }
 
+typedef struct _StopCallbackData StopCallbackData;
+struct _StopCallbackData
+{
+	TnyCamelQueueStopCb cb;
+	gpointer data;
+};
+
+static gboolean
+call_stop_callback (gpointer user_data)
+{
+	StopCallbackData *data = user_data;
+	data->cb(data->data);
+	g_slice_free (StopCallbackData, data);
+	return FALSE;
+}
+
+static void
+idle_add_stop_callback (TnyCamelQueueStopCb cb, gpointer data)
+{
+	StopCallbackData *scd = g_slice_new (StopCallbackData);
+	scd->cb = cb;
+	scd->data = data;
+	g_idle_add (call_stop_callback, scd);
+}
+
+
 typedef struct
 {
 	GThreadFunc func;
@@ -184,7 +210,7 @@
 {
 	TnyCamelQueue *queue = user_data;
 
-	while (!queue->stopped)
+	while (!queue->stop || queue->list)
 	{
 		GList *first = NULL;
 		QueueItem *item = NULL;
@@ -270,7 +296,7 @@
 		if (item)
 			g_slice_free (QueueItem, item);
 
-		if (wait) {
+		if (wait && !queue->stop) {
 			g_object_ref (queue);
 			g_mutex_lock (queue->mutex);
 			queue->is_waiting = TRUE;
@@ -281,8 +307,15 @@
 		}
 	}
 
-	queue->stopped = TRUE;
+	queue->running = FALSE;
 
+	g_static_rec_mutex_lock (queue->lock);
+	if (queue->stop_callback) {
+		g_debug("Calling stop callback");
+		idle_add_stop_callback (queue->stop_callback, queue->stop_user_data);
+	}
+	g_static_rec_mutex_unlock (queue->lock);
+
 	g_object_unref (queue);
 	g_thread_exit (NULL);
 }
@@ -396,8 +429,17 @@
 void 
 _tny_camel_queue_launch_wflags (TnyCamelQueue *queue, GThreadFunc func, GSourceFunc callback, GDestroyNotify destroyer, GSourceFunc cancel_callback, GDestroyNotify cancel_destroyer, gboolean *cancel_field, gpointer data, gsize data_size, TnyCamelQueueItemFlags flags, const gchar *name)
 {
-	QueueItem *item = g_slice_new (QueueItem);
+	QueueItem *item;
 
+	if (queue->dead) {
+		/* just cancel straight away if this queue is dead*/
+		cancel_callback (data);
+		cancel_destroyer (data);
+		return;
+	}
+
+	item = g_slice_new (QueueItem);
+
 	if (!g_thread_supported ())
 		g_thread_init (NULL);
 
@@ -437,15 +479,18 @@
 	} else /* Normal items simply get appended */
 		queue->list = g_list_append (queue->list, item);
 
-	if (queue->stopped) 
+	if (!queue->running) 
 	{
 		GError *err = NULL;
-		queue->stopped = FALSE;
+		queue->stop = FALSE;
 		g_object_ref (queue);
+
+		queue->running = TRUE;
+
 		queue->thread = g_thread_create (tny_camel_queue_thread_main_func, 
 			queue, TRUE, &err);
 		if (err) {
-			queue->stopped = TRUE;
+			g_object_unref (queue);
 		}
 	} else {
 		g_mutex_lock (queue->mutex);
@@ -521,18 +566,38 @@
  * Stop the thread and wait for it to finish
  */
 void
-_tny_camel_queue_stop (TnyCamelQueue *queue)
+_tny_camel_queue_stop (TnyCamelQueue *queue, TnyCamelQueueStopCb stop_cb, gpointer user_data)
 {
 
-	if (queue->thread) {
-		queue->stopped = TRUE;
+	g_static_rec_mutex_lock (queue->lock);
+
+	if (queue->dead) {
+		g_warning ("stop called on already dead queue");
+		if (stop_cb)
+			idle_add_stop_callback (stop_cb, user_data);
+		return;
+	}
+	queue->dead = TRUE;
+
+	if (stop_cb) {
+		if (!queue->running) {
+			idle_add_stop_callback (stop_cb, user_data);
+		} else {
+			queue->stop_callback = stop_cb;
+			queue->stop_user_data = user_data;
+		}
+	}
+
+	if (queue->running) {
+		queue->stop = TRUE;
+
 		g_mutex_lock (queue->mutex);
 		if (queue->is_waiting)
 			g_cond_broadcast (queue->condition);
 		g_mutex_unlock (queue->mutex);
+	}
 
-		g_thread_join (queue->thread);
-	}
+	g_static_rec_mutex_unlock (queue->lock);
 }
 
 static void 
@@ -558,7 +623,9 @@
 	self->mutex = g_mutex_new ();
 	self->condition = g_cond_new ();
 	self->account = NULL;
-	self->stopped = TRUE;
+	self->stop = FALSE;
+	self->running = FALSE;
+	self->dead = FALSE;
 	self->list = NULL;
 
 	/* We don't use a GThreadPool because we need control over the queued
Index: libtinymail-camel/tny-camel-store-account.c
===================================================================
--- libtinymail-camel/tny-camel-store-account.c	(révision 17)
+++ libtinymail-camel/tny-camel-store-account.c	(révision 18)
@@ -540,6 +540,50 @@
 	g_static_rec_mutex_unlock (apriv->service_lock);
 }
 
+typedef struct _StopData StopData;
+struct _StopData
+{
+	TnyCamelAccountStopCallback cb;
+	gpointer data;
+	gboolean account_done;
+	gboolean store_account_done;
+};
+
+void account_done_cb (gpointer data)
+{
+	StopData *sd = data;
+	sd->account_done = TRUE;
+	if (sd->account_done && sd->store_account_done) {
+		sd->cb (sd->data);
+		g_slice_free (StopData, sd);
+	}
+}
+
+void store_account_done_cb (gpointer data)
+{
+	StopData *sd = data;
+	sd->store_account_done = TRUE;
+	if (sd->account_done && sd->store_account_done) {
+		sd->cb (sd->data);
+		g_slice_free (StopData, sd);
+	}
+}
+
+static void
+tny_camel_store_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+	
+	StopData *data = g_slice_new0 (StopData);
+	data->cb = callback;
+	data->data = user_data;
+
+	_tny_camel_queue_stop (apriv->queue, account_done_cb, data);
+	_tny_camel_queue_stop (priv->msg_queue, store_account_done_cb, data);
+}
+
+
 static void 
 tny_camel_store_account_try_connect (TnyAccount *self, GError **err)
 {
@@ -832,7 +876,7 @@
 		camel_object_unref (CAMEL_OBJECT (priv->iter_store));
 	}
 
-	_tny_camel_queue_stop (priv->msg_queue);
+	_tny_camel_queue_stop (priv->msg_queue, NULL, NULL);
 	g_object_unref (priv->msg_queue);
 
 	return;
@@ -2409,6 +2453,7 @@
 
 	TNY_CAMEL_ACCOUNT_CLASS (class)->try_connect= tny_camel_store_account_try_connect;
 	TNY_CAMEL_ACCOUNT_CLASS (class)->prepare= tny_camel_store_account_prepare;
+	TNY_CAMEL_ACCOUNT_CLASS (class)->stop = tny_camel_store_account_stop;
 
 	class->get_folders_async= tny_camel_store_account_get_folders_async_default;
 	class->get_folders= tny_camel_store_account_get_folders_default;
Index: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c	(révision 17)
+++ libtinymail-camel/tny-camel-account.c	(révision 18)
@@ -1871,6 +1871,30 @@
 	}
 }
 
+
+/**
+ * tny_camel_account_stop:
+ * @self: a #TnyCamelAccount object
+ * @callback: a callback when the account has stopped all operations
+ * @user_data: user data for the callback
+ *
+ * Request a stop of all operations on an account
+ * @callback will be called with @user_data when all operations have stopped.
+ * The account will be unusable after calling this function.
+ **/
+void
+tny_camel_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+	TNY_CAMEL_ACCOUNT_GET_CLASS (self)->stop(self, callback, user_data);
+}
+
+void
+tny_camel_account_stop_default (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data)
+{
+	TnyCamelAccountPriv *priv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (self);
+	_tny_camel_queue_stop (priv->queue, callback, user_data);
+}
+
 static gboolean
 tny_camel_account_is_ready (TnyAccount *self)
 {
@@ -2198,7 +2222,7 @@
 
 	g_static_rec_mutex_unlock (priv->service_lock);
 
-	_tny_camel_queue_stop (priv->queue);
+	_tny_camel_queue_stop (priv->queue, NULL, NULL);
 	g_object_unref (priv->queue);
 	g_object_unref (priv->con_strat);
 
@@ -2319,6 +2343,7 @@
 	class->get_options= tny_camel_account_get_options_default;
 
 	class->set_online= tny_camel_account_set_online_default;
+	class->stop = tny_camel_account_stop_default;
 
 	object_class->finalize = tny_camel_account_finalize;
 
Index: libtinymail-camel/tny-camel-account.h
===================================================================
--- libtinymail-camel/tny-camel-account.h	(révision 17)
+++ libtinymail-camel/tny-camel-account.h	(révision 18)
@@ -32,7 +32,7 @@
 #define TNY_CAMEL_ACCOUNT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccount))
 #define TNY_CAMEL_ACCOUNT_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccountClass))
 #define TNY_IS_CAMEL_ACCOUNT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_CAMEL_ACCOUNT))
-#define TNY_IS_ACAMEL_CCOUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_CAMEL_ACCOUNT))
+#define TNY_IS_CAMEL_ACCOUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_CAMEL_ACCOUNT))
 #define TNY_CAMEL_ACCOUNT_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_CAMEL_ACCOUNT, TnyCamelAccountClass))
 
 /* This is an abstract type, you cannot (should not) instantiate it */
@@ -50,6 +50,7 @@
 
 typedef void (*TnyCamelSetOnlineCallback) (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data);
 
+typedef void (*TnyCamelAccountStopCallback) (gpointer user_data);
 
 struct _TnyCamelAccount
 {
@@ -94,6 +95,7 @@
 	void (*get_options) (TnyCamelAccount *self, TnyList *options);
 
 	void (*set_online) (TnyCamelAccount *self, gboolean online, TnyCamelSetOnlineCallback callback, gpointer user_data);
+	void (*stop) (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data);
 
 	/* Abstract methods */
 	void (*prepare) (TnyCamelAccount *self, gboolean recon_if, gboolean reservice);
@@ -115,6 +117,7 @@
 typedef void (*TnyCamelGetSupportedSecureAuthCallback) (TnyCamelAccount *self, gboolean cancelled, TnyList *auth_types, GError *err, gpointer user_data);
 void tny_camel_account_get_supported_secure_authentication(TnyCamelAccount *self, TnyCamelGetSupportedSecureAuthCallback callback, TnyStatusCallback status_callback, gpointer user_data);
 
+void tny_camel_account_stop (TnyCamelAccount *self, TnyCamelAccountStopCallback callback, gpointer user_data);
 G_END_DECLS
 
 #endif
Index: libtinymail-camel/observer-mixin.c
===================================================================
--- libtinymail-camel/observer-mixin.c	(révision 0)
+++ libtinymail-camel/observer-mixin.c	(révision 20)
@@ -0,0 +1,183 @@
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <tny-lockable.h>
+#include <tny-folder-store-observer.h>
+
+#include "observer-mixin-priv.h"
+
+
+void
+_observer_mixin_init (ObserverMixin *mixin)
+{
+	mixin->lock = g_new0 (GStaticRecMutex, 1);
+	g_static_rec_mutex_init (mixin->lock);
+	mixin->list = NULL;
+}
+
+
+void
+_observer_mixin_destroy (gpointer owner, ObserverMixin *mixin)
+{
+	_observer_mixin_remove_all_observers (owner, mixin);
+	g_free (mixin->lock);
+	mixin->lock = NULL;
+}
+
+
+static void
+notify_observer_del (gpointer user_data, GObject *observer)
+{
+	ObserverMixin *mixin = user_data;
+	g_static_rec_mutex_lock (mixin->lock);
+	mixin->list = g_list_remove (mixin->list, observer);
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+	g_static_rec_mutex_lock (mixin->lock);
+	if (!g_list_find (mixin->list, observer)) {
+		mixin->list = g_list_prepend (mixin->list, observer);
+		g_object_weak_ref (G_OBJECT (observer), notify_observer_del, (GObject*)owner);
+	}
+	g_static_rec_mutex_unlock (mixin->lock);
+
+	return;
+}
+
+
+void
+_observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+	GList *found = NULL;
+
+	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+	g_static_rec_mutex_lock (mixin->lock);
+
+	if (!mixin->list) {
+		g_static_rec_mutex_unlock (mixin->lock);
+		return;
+	}
+
+	found = g_list_find (mixin->list, observer);
+	if (found) {
+		mixin->list = g_list_remove_link (mixin->list, found);
+		g_object_weak_unref (found->data, notify_observer_del, (GObject*) owner);
+		g_list_free (found);
+	}
+
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin)
+{
+	g_static_rec_mutex_lock (mixin->lock);
+	if (mixin->list) {
+		GList *copy = mixin->list;
+		while (copy) {
+			g_object_weak_unref ((GObject *) copy->data, notify_observer_del, (GObject *) owner);
+			copy = g_list_next (copy);
+		}
+		g_list_free (mixin->list);
+		mixin->list = NULL;
+	}
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+typedef struct {
+	GObject *mixin_owner;
+	ObserverMixin *mixin;
+	GObject *change;
+	TnyLockable *ui_lock;
+	ObserverUpdateMethod method;
+	GDestroyNotify notify;
+} NotObInIdleInfo;
+
+static void
+do_notify_in_idle_destroy (gpointer user_data)
+{
+	NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+
+	g_object_unref (info->change);
+	if (info->notify)
+		(info->notify)(info->mixin_owner);
+	g_object_unref (info->mixin_owner);
+	g_object_unref (info->ui_lock);
+
+	g_slice_free (NotObInIdleInfo, info);
+}
+
+static void
+notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+	GList *list, *list_iter;
+
+	g_static_rec_mutex_lock (mixin->lock);
+	if (!mixin->list) {
+		g_static_rec_mutex_unlock (mixin->lock);
+		return;
+	}
+	list = g_list_copy (mixin->list);
+	list_iter = list;
+	g_static_rec_mutex_unlock (mixin->lock);
+
+	while (list_iter)
+	{
+		tny_lockable_lock (ui_lock);
+		method (list_iter->data, change);
+		tny_lockable_unlock (ui_lock);
+		list_iter = g_list_next (list_iter);
+	}
+
+	g_list_free (list);
+}
+
+static gboolean
+notify_observers_about_idle (gpointer user_data)
+{
+	NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+	notify_observers_about (info->mixin, info->method, info->change, info->ui_lock);
+	return FALSE;
+}
+
+
+void
+_observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify)
+{
+	NotObInIdleInfo *info = g_slice_new (NotObInIdleInfo);
+
+	info->mixin_owner = g_object_ref (mixin_owner);
+	info->mixin = mixin;
+	info->change = g_object_ref (change);
+	info->ui_lock = g_object_ref (ui_lock);
+	info->method = method;
+	info->notify = done_notify;
+
+	g_idle_add_full (G_PRIORITY_HIGH, notify_observers_about_idle,
+		info, do_notify_in_idle_destroy);
+}
+
Index: libtinymail-camel/tny-camel-send-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-send-queue-priv.h	(révision 18)
+++ libtinymail-camel/tny-camel-send-queue-priv.h	(révision 20)
@@ -22,6 +22,7 @@
 
 #include <tny-camel-transport-account.h>
 #include <tny-folder.h>
+#include <observer-mixin-priv.h>
 
 typedef struct _TnyCamelSendQueuePriv TnyCamelSendQueuePriv;
 
@@ -36,6 +37,8 @@
 	gboolean do_continue, is_running;
 	gboolean observer_attached;
 	gint pending_send_notifies;
+	ObserverMixin store_observers;
+	gboolean first_refresh_happened;
 };
 
 #endif
Index: libtinymail-camel/tny-camel-send-queue.c
===================================================================
--- libtinymail-camel/tny-camel-send-queue.c	(révision 18)
+++ libtinymail-camel/tny-camel-send-queue.c	(révision 20)
@@ -1,5 +1,6 @@
 /* libtinymail-camel - The Tiny Mail base library for Camel
  * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -35,6 +36,9 @@
 #include <tny-store-account.h>
 #include <tny-camel-store-account.h>
 #include <tny-folder-observer.h>
+#include <tny-folder-store.h>
+#include <tny-folder-store-change.h>
+#include <tny-folder-store-observer.h>
 
 static GObjectClass *parent_class = NULL;
 
@@ -959,7 +963,328 @@
 }
 
 
+
 static void
+tny_camel_send_queue_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+	g_set_error (err, TNY_ERROR_DOMAIN,
+			TNY_SERVICE_ERROR_UNSUPPORTED,
+			"You can't use the tny_folder_store_remove_folder API "
+			"on send queues. This problem indicates a bug in the "
+			"software.");
+
+	return;
+}
+
+static TnyFolder*
+tny_camel_send_queue_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
+{
+	g_set_error (err, TNY_ERROR_DOMAIN,
+			TNY_SERVICE_ERROR_UNSUPPORTED,
+			"You can't use the tny_folder_store_create_folder "
+			"API on send queues. This problem indicates a "
+			"bug in the software.");
+
+	return NULL;
+}
+
+typedef struct
+{
+	TnyFolderStore *self;
+	gchar *name;
+	TnyCreateFolderCallback callback;
+	gpointer user_data;
+} CreateFolderInfo;
+
+static gboolean
+tny_camel_send_queue_create_folder_async_callback (gpointer user_data)
+{
+	CreateFolderInfo *info = user_data;
+	if (info->callback) {
+		GError *err;
+		err = g_error_new (TNY_ERROR_DOMAIN,
+				   TNY_SERVICE_ERROR_UNSUPPORTED,
+				   "You can't use the tny_folder_store_create_folder "
+				   "API on send queues. This problem indicates a "
+				   "bug in the software.");
+
+
+		//tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, FALSE, NULL, err, info->user_data);
+		//tny_lockable_unlock (info->session->priv->ui_lock);
+		g_error_free (err);
+	}
+	g_slice_free (CreateFolderInfo, info);
+
+	return FALSE;
+}
+
+static void
+tny_camel_send_queue_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	CreateFolderInfo *info;
+
+	/* Idle info for the callbacks */
+	info = g_slice_new (CreateFolderInfo);
+	info->self = self;
+	info->name = g_strdup (name);
+	info->callback = callback;
+	info->user_data = user_data;
+
+	g_object_ref (info->self);
+
+	g_idle_add (tny_camel_send_queue_create_folder_async_callback, info);
+	return;
+}
+
+
+static void
+tny_camel_send_queue_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+	_observer_mixin_add_observer (self, &(priv->store_observers), observer);
+}
+
+static void
+tny_camel_send_queue_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+	_observer_mixin_remove_observer (self, &(priv->store_observers), observer);
+}
+
+static void
+refresh_observers (TnyCamelSendQueue *self)
+{
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (TNY_CAMEL_ACCOUNT (priv->trans_account));
+	TnySessionCamel *session = apriv->session;
+
+	if (!priv->first_refresh_happened) {
+		TnyFolderStoreChange *change;
+
+		change = tny_folder_store_change_new (TNY_FOLDER_STORE(self));
+		tny_folder_store_change_add_appeared_folder (change,
+				tny_send_queue_get_outbox(TNY_SEND_QUEUE(self)));
+		tny_folder_store_change_add_appeared_folder (change,
+				tny_send_queue_get_sentbox(TNY_SEND_QUEUE(self)));
+
+		_observer_mixin_notify_observers_about_in_idle (self, &(priv->store_observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, session->priv->ui_lock, NULL);
+		priv->first_refresh_happened = TRUE;
+	}
+}
+
+static void
+tny_camel_send_queue_get_folders (TnyFolderStore *store, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+	TnySendQueue *self = TNY_SEND_QUEUE (store);
+
+	gboolean cant_reuse_iter = TRUE;
+
+	g_assert (query == NULL); //yeah, i'll fix this after talking to pvanhoof
+
+	TnyFolder *outbox = tny_send_queue_get_outbox (self);
+	TnyFolder *sentbox = tny_send_queue_get_sentbox (self);
+	tny_list_append (list, G_OBJECT(outbox));
+	tny_list_append (list, G_OBJECT(sentbox));
+	g_object_unref (outbox);
+	g_object_unref (sentbox);
+
+	refresh_observers (TNY_CAMEL_SEND_QUEUE (self));
+}
+
+
+typedef struct
+{
+	TnyCamelQueueable parent;
+
+	GError *err;
+	TnyFolderStore *self;
+	TnyList *list;
+	gboolean refresh;
+	TnyGetFoldersCallback callback;
+	TnyFolderStoreQuery *query;
+	gpointer user_data;
+	gboolean cancelled;
+	TnySessionCamel *session;
+
+} GetFoldersInfo;
+
+
+static void
+tny_camel_send_queue_get_folders_async_destroyer (gpointer thr_user_data)
+{
+	GetFoldersInfo *info = thr_user_data;
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (info->self);
+
+	/* thread reference */
+	g_object_unref (info->self);
+	g_object_unref (info->list);
+
+	if (info->query)
+		g_object_unref (G_OBJECT (info->query));
+
+	if (info->err)
+		g_error_free (info->err);
+
+	_tny_session_stop_operation (info->session);
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_send_queue_get_folders_async_callback (gpointer thr_user_data)
+{
+	GetFoldersInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, info->cancelled, info->list, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+
+static gpointer
+tny_camel_send_queue_get_folders_async_thread (gpointer thr_user_data)
+{
+	GetFoldersInfo *info = (GetFoldersInfo*) thr_user_data;
+
+	tny_camel_send_queue_get_folders (TNY_FOLDER_STORE (info->self),
+		info->list, info->query, info->refresh, &info->err);
+
+	info->cancelled = FALSE;
+	if (info->err != NULL) {
+		if (camel_strstrcase (info->err->message, "cancel") != 0)
+			info->cancelled = TRUE;
+	}
+
+	return NULL;
+}
+
+static void
+tny_camel_send_queue_get_folders_async_cancelled_destroyer (gpointer thr_user_data)
+{
+	GetFoldersInfo *info = thr_user_data;
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (info->self);
+
+	/* thread reference */
+	g_object_unref (info->self);
+	g_object_unref (info->list);
+
+	if (info->err)
+		g_error_free (info->err);
+	if (info->query)
+		g_object_unref (info->query);
+
+	/**/
+
+	camel_object_unref (info->session);
+
+	return;
+}
+
+static gboolean
+tny_camel_send_queue_get_folders_async_cancelled_callback (gpointer thr_user_data)
+{
+	GetFoldersInfo *info = thr_user_data;
+	if (info->callback) {
+		tny_lockable_lock (info->session->priv->ui_lock);
+		info->callback (info->self, TRUE, info->list, info->err, info->user_data);
+		tny_lockable_unlock (info->session->priv->ui_lock);
+	}
+	return FALSE;
+}
+
+static void
+tny_camel_send_queue_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TNY_CAMEL_FOLDER_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
+}
+
+
+static void
+tny_camel_send_queue_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	GetFoldersInfo *info;
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (TNY_CAMEL_ACCOUNT (priv->trans_account));
+	CamelStore *store = (CamelStore*) apriv->service;
+	TnyCamelQueue *queue = apriv->queue;
+
+	/* Idle info for the callbacks */
+	info = g_slice_new (GetFoldersInfo);
+	info->session = apriv->session;
+	camel_object_ref (info->session);
+	info->self = self;
+	info->list = list;
+	info->refresh = refresh;
+	info->callback = callback;
+	info->user_data = user_data;
+	info->query = query;
+	info->err = NULL;
+
+	/* thread reference */
+	g_object_ref (info->self);
+	g_object_ref (info->list);
+	if (info->query)
+		g_object_ref (G_OBJECT (info->query));
+
+	_tny_camel_queue_launch (queue,
+		tny_camel_send_queue_get_folders_async_thread,
+		tny_camel_send_queue_get_folders_async_callback,
+		tny_camel_send_queue_get_folders_async_destroyer,
+		tny_camel_send_queue_get_folders_async_cancelled_callback,
+		tny_camel_send_queue_get_folders_async_cancelled_destroyer,
+		&info->cancelled,
+		info, sizeof (GetFoldersInfo),
+		__FUNCTION__);
+
+	return;
+}
+
+
+
+typedef struct _RefreshAsyncInfo
+{
+	TnyFolderStore *self;
+	TnyFolderStoreCallback callback;
+	TnyStatusCallback status_callback;
+	gpointer user_data;
+} RefreshAsyncInfo;
+
+static gboolean
+refresh_async_idle (gpointer user_data)
+{
+	RefreshAsyncInfo *info = user_data;
+
+	refresh_observers (TNY_CAMEL_SEND_QUEUE(info->self));
+
+	info->callback (info->self, FALSE, NULL, info->user_data);
+	g_object_unref (info->self);
+
+	g_slice_free (RefreshAsyncInfo, info);
+	return FALSE;
+}
+
+static void
+tny_camel_send_queue_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	RefreshAsyncInfo *info = g_slice_new0 (RefreshAsyncInfo);
+
+	info->self = g_object_ref (self);
+	info->callback = callback;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+
+	g_idle_add (refresh_async_idle, info);
+}
+
+
+static void
 tny_camel_send_queue_add (TnySendQueue *self, TnyMsg *msg, GError **err)
 {
 	TNY_CAMEL_SEND_QUEUE_GET_CLASS (self)->add(self, msg, err);
@@ -1238,6 +1563,8 @@
 	TnyCamelAccountPriv *apriv = NULL;
 	TnyFolder *sentbox = NULL;
 
+	_observer_mixin_destroy (self, &(priv->store_observers));
+
 	sentbox = tny_send_queue_get_sentbox (self);
 
 	if (sentbox) {
@@ -1404,6 +1731,22 @@
 	return;
 }
 
+static void
+tny_folder_store_init (gpointer g, gpointer iface_data)
+{
+	TnyFolderStoreIface *klass = (TnyFolderStoreIface *)g;
+
+	klass->remove_folder= tny_camel_send_queue_remove_folder;
+	klass->create_folder= tny_camel_send_queue_create_folder;
+	klass->create_folder_async= tny_camel_send_queue_create_folder_async;
+	klass->get_folders= tny_camel_send_queue_get_folders;
+	klass->get_folders_async= tny_camel_send_queue_get_folders_async;
+	klass->add_observer= tny_camel_send_queue_add_observer;
+	klass->remove_observer= tny_camel_send_queue_remove_observer;
+	klass->refresh_async = tny_camel_send_queue_refresh_async;
+}
+
+
 static void 
 tny_camel_send_queue_class_init (TnyCamelSendQueueClass *class)
 {
@@ -1446,6 +1789,7 @@
 	priv->thread = NULL;
 	priv->pending_send_notifies = 0;
 
+	_observer_mixin_init (&(priv->store_observers));
 	return;
 }
 
@@ -1486,7 +1830,14 @@
 			NULL,         /* interface_finalize */
 			NULL          /* interface_data */
 		};
-	
+
+	static const GInterfaceInfo tny_folder_store_info =
+		{
+			(GInterfaceInitFunc) tny_folder_store_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
 	type = g_type_register_static (G_TYPE_OBJECT,
 				       "TnyCamelSendQueue",
 				       &info, 0);
@@ -1494,9 +1845,13 @@
 	g_type_add_interface_static (type, TNY_TYPE_FOLDER_OBSERVER,
 				     &tny_folder_observer_info);
 	
+	g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE,
+				     &tny_folder_store_info);
+
 	g_type_add_interface_static (type, TNY_TYPE_SEND_QUEUE,
 				     &tny_send_queue_info);
 
+
 	return GUINT_TO_POINTER (type);
 }
 
Index: libtinymail-camel/observer-mixin-priv.h
===================================================================
--- libtinymail-camel/observer-mixin-priv.h	(révision 0)
+++ libtinymail-camel/observer-mixin-priv.h	(révision 20)
@@ -0,0 +1,41 @@
+#ifndef OBSERVER_MIXIN_H
+#define OBSERVER_MIXIN_H
+
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _ObserverMixin {
+	GList *list;
+	GStaticRecMutex *lock;
+} ObserverMixin;
+
+
+typedef void (*ObserverUpdateMethod) (gpointer, gpointer);
+
+void _observer_mixin_init (ObserverMixin *mixin);
+void _observer_mixin_destroy (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify);
+
+#endif
Index: libtinymail-camel/Makefile.am
===================================================================
--- libtinymail-camel/Makefile.am	(révision 18)
+++ libtinymail-camel/Makefile.am	(révision 20)
@@ -60,7 +60,8 @@
 	tny-camel-queue-priv.h \
 	tny-camel-bs-msg-priv.h \
 	tny-camel-bs-mime-part-priv.h \
-	tny-camel-bs-msg-header-priv.h
+	tny-camel-bs-msg-header-priv.h \
+	observer-mixin-priv.h
 
 libtinymail_camel_1_0_la_SOURCES = \
 	$(libtinymail_camel_priv_headers) \
@@ -96,7 +97,8 @@
 	tny-camel-bs-msg-receive-strategy.c \
 	tny-camel-bs-msg-header.c \
 	tny-camel-default-connection-policy.c \
-	tny-camel-recover-connection-policy.c
+	tny-camel-recover-connection-policy.c \
+	observer-mixin.c
 
 libtinymail_camel_1_0_la_LIBADD = \
 	$(LIBTINYMAIL_CAMEL_LIBS) \
Index: libtinymail/tny-send-queue.c
===================================================================
--- libtinymail/tny-send-queue.c	(révision 18)
+++ libtinymail/tny-send-queue.c	(révision 20)
@@ -29,6 +29,7 @@
 
 #include <tny-send-queue.h>
 #include <tny-folder.h>
+#include <tny-folder-store.h>
 #include <tny-msg.h>
 #include <tny-signals-marshal.h>
 
@@ -299,6 +300,7 @@
 	type = g_type_register_static (G_TYPE_INTERFACE, 
 				       "TnySendQueue", &info, 0);
 	g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+	g_type_interface_add_prerequisite (type, TNY_TYPE_FOLDER_STORE);
 
 	return GUINT_TO_POINTER (type);
 }
Index: libtinymail-camel/tny-camel-send-queue.c
===================================================================
--- libtinymail-camel/tny-camel-send-queue.c	(révision 20)
+++ libtinymail-camel/tny-camel-send-queue.c	(révision 21)
@@ -1624,6 +1624,30 @@
 	return TNY_SEND_QUEUE (self);
 }
 
+/**
+ * tny_camel_send_queue_new_with_folders:
+ * @trans_account: A #TnyCamelTransportAccount instance
+ *
+ * Create a new #TnySendQueue instance implemented for Camel,
+ * Using custom-suppied outbox and inbox
+ *
+ * Return value: A new #TnySendQueue instance implemented for Camel
+ **/
+TnySendQueue*
+tny_camel_send_queue_new_with_folders (TnyCamelTransportAccount *trans_account, TnyFolder *outbox, TnyFolder *sentbox)
+{
+	TnyCamelSendQueue *self = g_object_new (TNY_TYPE_CAMEL_SEND_QUEUE, NULL);
+	TnyCamelSendQueuePriv *priv = TNY_CAMEL_SEND_QUEUE_GET_PRIVATE (self);
+
+	g_assert (TNY_IS_CAMEL_TRANSPORT_ACCOUNT (trans_account));
+	priv->outbox_cache  = g_object_ref(outbox);
+	priv->sentbox_cache = g_object_ref(sentbox);
+	tny_camel_send_queue_set_transport_account (self, trans_account);
+
+	return TNY_SEND_QUEUE (self);
+}
+
+
 static void
 on_setonline_happened (TnyCamelAccount *account, gboolean online, gpointer user_data)
 {
Index: libtinymail-camel/tny-camel-send-queue.h
===================================================================
--- libtinymail-camel/tny-camel-send-queue.h	(révision 20)
+++ libtinymail-camel/tny-camel-send-queue.h	(révision 21)
@@ -60,6 +60,8 @@
 
 TnySendQueue* tny_camel_send_queue_new (TnyCamelTransportAccount *trans_account);
 
+TnySendQueue* tny_camel_send_queue_new_with_folders (TnyCamelTransportAccount *trans_account, TnyFolder *outbox, TnyFolder *sentbox);
+
 void tny_camel_send_queue_flush (TnyCamelSendQueue *self);
 
 TnyCamelTransportAccount* tny_camel_send_queue_get_transport_account (TnyCamelSendQueue *self);
Index: libtinymail/observer-mixin.c
===================================================================
--- libtinymail/observer-mixin.c	(révision 0)
+++ libtinymail/observer-mixin.c	(révision 22)
@@ -0,0 +1,198 @@
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <tny-lockable.h>
+#include <tny-folder-store-observer.h>
+
+#include "observer-mixin-priv.h"
+
+
+void
+_observer_mixin_init (ObserverMixin *mixin)
+{
+	mixin->lock = g_new0 (GStaticRecMutex, 1);
+	g_static_rec_mutex_init (mixin->lock);
+	mixin->list = NULL;
+}
+
+
+void
+_observer_mixin_destroy (gpointer owner, ObserverMixin *mixin)
+{
+	_observer_mixin_remove_all_observers (owner, mixin);
+	if (mixin->lock)
+		g_free (mixin->lock);
+	mixin->lock = NULL;
+}
+
+
+static void
+notify_observer_del (gpointer user_data, GObject *observer)
+{
+	ObserverMixin *mixin = user_data;
+	g_static_rec_mutex_lock (mixin->lock);
+	mixin->list = g_list_remove (mixin->list, observer);
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+	g_static_rec_mutex_lock (mixin->lock);
+	if (!g_list_find (mixin->list, observer)) {
+		mixin->list = g_list_prepend (mixin->list, observer);
+		g_object_weak_ref (G_OBJECT (observer), notify_observer_del, (GObject*)owner);
+	}
+	g_static_rec_mutex_unlock (mixin->lock);
+
+	return;
+}
+
+
+void
+_observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer)
+{
+	GList *found = NULL;
+
+	g_assert (TNY_IS_FOLDER_STORE_OBSERVER (observer));
+
+	g_static_rec_mutex_lock (mixin->lock);
+
+	if (!mixin->list) {
+		g_static_rec_mutex_unlock (mixin->lock);
+		return;
+	}
+
+	found = g_list_find (mixin->list, observer);
+	if (found) {
+		mixin->list = g_list_remove_link (mixin->list, found);
+		g_object_weak_unref (found->data, notify_observer_del, (GObject*) owner);
+		g_list_free (found);
+	}
+
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+void
+_observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin)
+{
+	g_static_rec_mutex_lock (mixin->lock);
+	if (mixin->list) {
+		GList *copy = mixin->list;
+		while (copy) {
+			g_object_weak_unref ((GObject *) copy->data, notify_observer_del, (GObject *) owner);
+			copy = g_list_next (copy);
+		}
+		g_list_free (mixin->list);
+		mixin->list = NULL;
+	}
+	g_static_rec_mutex_unlock (mixin->lock);
+}
+
+typedef struct {
+	GObject *mixin_owner;
+	ObserverMixin *mixin;
+	GObject *change;
+	TnyLockable *ui_lock;
+	ObserverUpdateMethod method;
+	GDestroyNotify notify;
+} NotObInIdleInfo;
+
+static void
+do_notify_in_idle_destroy (gpointer user_data)
+{
+	NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+
+	g_object_unref (info->change);
+	if (info->notify)
+		(info->notify)(info->mixin_owner);
+	g_object_unref (info->mixin_owner);
+	if (info->ui_lock)
+		g_object_unref (info->ui_lock);
+
+	g_slice_free (NotObInIdleInfo, info);
+}
+
+static void
+notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+	GList *list, *list_iter;
+
+	g_static_rec_mutex_lock (mixin->lock);
+	if (!mixin->list) {
+		g_static_rec_mutex_unlock (mixin->lock);
+		return;
+	}
+	list = g_list_copy (mixin->list);
+	list_iter = list;
+	g_static_rec_mutex_unlock (mixin->lock);
+
+	while (list_iter)
+	{
+		if (ui_lock)
+			tny_lockable_lock (ui_lock);
+		method (list_iter->data, change);
+		if (ui_lock)
+			tny_lockable_unlock (ui_lock);
+		list_iter = g_list_next (list_iter);
+	}
+
+	g_list_free (list);
+}
+
+static gboolean
+notify_observers_about_idle (gpointer user_data)
+{
+	NotObInIdleInfo *info = (NotObInIdleInfo *) user_data;
+	notify_observers_about (info->mixin, info->method, info->change, info->ui_lock);
+	return FALSE;
+}
+
+
+void
+_observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify)
+{
+	NotObInIdleInfo *info = g_slice_new0 (NotObInIdleInfo);
+
+	info->mixin_owner = g_object_ref (mixin_owner);
+	info->mixin = mixin;
+	info->change = g_object_ref (change);
+	if (ui_lock)
+		info->ui_lock = g_object_ref (ui_lock);
+	info->method = method;
+	info->notify = done_notify;
+
+	g_idle_add_full (G_PRIORITY_HIGH, notify_observers_about_idle,
+		info, do_notify_in_idle_destroy);
+}
+
+void
+_observer_mixin_notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock)
+{
+	if (ui_lock)
+		tny_lockable_lock (ui_lock);
+	notify_observers_about (mixin, method, change, ui_lock);
+	if (ui_lock)
+		tny_lockable_unlock (ui_lock);
+}
+
Index: libtinymail/tny-merge-folder-store.c
===================================================================
--- libtinymail/tny-merge-folder-store.c	(révision 0)
+++ libtinymail/tny-merge-folder-store.c	(révision 22)
@@ -0,0 +1,739 @@
+/* libtinymail - The Tiny Mail base library
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) 2008 Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * TnyMergeFolderStore:
+ *
+ * Merges together two or more folder stores.
+ * All write operations are performed against the base folder store.
+ *
+ * free-function: g_object_unref
+ **/
+
+#include <config.h>
+
+#ifdef DBC
+#include <string.h>
+#endif
+
+#include <tny-folder-store.h>
+#include <tny-folder-store-observer.h>
+#include <tny-merge-folder-store.h>
+#include <tny-list.h>
+#include <tny-simple-list.h>
+#include <tny-error.h>
+#include "observer-mixin-priv.h"
+
+static GObjectClass *parent_class = NULL;
+
+#define TNY_MERGE_FOLDER_STORE_GET_PRIVATE(o)	\
+	(G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStorePriv))
+
+typedef struct _TnyMergeFolderStorePriv TnyMergeFolderStorePriv;
+struct _TnyMergeFolderStorePriv
+{
+	GStaticRecMutex *lock;
+	TnyList *stores;
+	ObserverMixin observers;
+	GHashTable *known_folders;
+	TnyLockable *ui_lock;
+};
+
+
+static void
+known_folder_del (gpointer user_data, GObject *folder)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (user_data);
+	g_hash_table_remove (priv->known_folders, folder);
+}
+
+
+static gboolean
+known_folder_remover (GObject *folder,
+                      gpointer value,
+                      TnyMergeFolderStore *self)
+{
+	g_object_weak_unref (folder, known_folder_del, self);
+	return TRUE;
+}
+
+
+static void
+tny_merge_folder_store_observer_update(TnyFolderStoreObserver *self, TnyFolderStoreChange *change)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+	TnyFolderStoreChangeChanged changed = tny_folder_store_change_get_changed (change);
+
+	g_static_rec_mutex_lock (priv->lock);
+
+	if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_CREATED_FOLDERS) {
+		TnyList *added = tny_simple_list_new();
+		TnyIterator *iter;
+	
+		tny_folder_store_change_get_created_folders (change, added);
+		iter = tny_list_create_iterator (added);
+		while (!tny_iterator_is_done (iter)) {
+			TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+			if (!g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+				g_hash_table_insert(priv->known_folders, folder, NULL);
+				g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+			}
+			g_object_unref (folder);
+			tny_iterator_next (iter);
+		}
+		g_object_unref (iter);
+		g_object_unref (added);
+	}
+	if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_APPEARED_FOLDERS) {
+		TnyList *added = tny_simple_list_new();
+		TnyIterator *iter;
+
+		tny_folder_store_change_get_appeared_folders(change, added);
+		iter = tny_list_create_iterator (added);
+		while (!tny_iterator_is_done (iter)) {
+			TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+			if (!g_hash_table_lookup_extended (priv->known_folders, folder, NULL, NULL)) {
+				g_hash_table_insert(priv->known_folders, folder, NULL);
+				g_object_weak_ref (G_OBJECT(folder), known_folder_del, self);
+			}
+			g_object_unref (folder);
+			tny_iterator_next (iter);
+		}
+		g_object_unref (iter);
+		g_object_unref (added);
+	}
+	if (changed & TNY_FOLDER_STORE_CHANGE_CHANGED_REMOVED_FOLDERS) {
+		TnyList *removed = tny_simple_list_new ();
+		TnyIterator *iter;
+
+		tny_folder_store_change_get_removed_folders (change, removed);
+		iter = tny_list_create_iterator (removed);
+		while (!tny_iterator_is_done (iter)) {
+			TnyFolder *folder = TNY_FOLDER(tny_iterator_get_current (iter));
+			g_hash_table_remove(priv->known_folders, folder);
+			g_object_weak_unref (G_OBJECT(folder), known_folder_del, self);
+			g_object_unref (folder);
+			tny_iterator_next (iter);
+		}
+
+		g_object_unref (iter);
+		g_object_unref (removed);
+	}
+
+	g_static_rec_mutex_unlock (priv->lock);
+
+	_observer_mixin_notify_observers_about (&(priv->observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, priv->ui_lock);
+}
+
+static void build_appeared_change (gpointer key,
+                                   gpointer value,
+                                   gpointer user_data)
+{
+	TnyFolder *folder = key;
+	TnyFolderStoreChange *change = user_data;
+	tny_folder_store_change_add_appeared_folder (change, folder);
+}
+
+static void
+tny_merge_folder_store_add_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+	TnyFolderStoreChange *change = tny_folder_store_change_new (self);
+
+	_observer_mixin_add_observer (self, &(priv->observers), observer);
+
+	g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+	if (tny_folder_store_change_get_changed (change) != 0) 
+		_observer_mixin_notify_observers_about_in_idle (self, &(priv->observers), (ObserverUpdateMethod) tny_folder_store_observer_update, change, priv->ui_lock, NULL);
+	g_object_unref (change);
+}
+
+static void
+tny_merge_folder_store_remove_observer_default (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	_observer_mixin_remove_observer (self, &(priv->observers), observer);
+}
+
+static void
+tny_merge_folder_store_remove_folder_default (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+	g_set_error (err, TNY_ERROR_DOMAIN,
+			TNY_SERVICE_ERROR_UNSUPPORTED,
+			"You can't use the tny_folder_store_remove_folder API "
+			"on send queues. This problem indicates a bug in the "
+			"software.");
+
+	return;
+
+	/* TODO: derive TnyMergeWritableFolderStore which does this:
+	 * if folder in base_store
+		remove_folder (base_store, folder, err)
+	   else
+	      err = not_supported
+		*/
+}
+
+static TnyFolder*
+tny_merge_folder_store_create_folder_default (TnyFolderStore *self, const gchar *name, GError **err)
+{
+	g_set_error (err, TNY_ERROR_DOMAIN,
+			TNY_SERVICE_ERROR_UNSUPPORTED,
+			"You can't use the tny_folder_store_remove_folder API "
+			"on send queues. This problem indicates a bug in the "
+			"software.");
+
+	return;
+
+
+	/* TODO: derive TnyMergeWritableFolderStore which does this:
+	 * create_folder (base_store, name, err); */
+}
+
+typedef struct
+{
+	TnyFolderStore *self;
+	gchar *name;
+	TnyCreateFolderCallback callback;
+	gpointer user_data;
+} CreateFolderInfo;
+
+static gboolean
+create_folder_async_callback (gpointer user_data)
+{
+	CreateFolderInfo *info = user_data;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+	if (info->callback) {
+		GError *err;
+		err = g_error_new (TNY_ERROR_DOMAIN,
+				   TNY_SERVICE_ERROR_UNSUPPORTED,
+				   "You can't use the tny_folder_store_create_folder "
+				   "API on send queues. This problem indicates a "
+				   "bug in the software.");
+
+
+		if (priv->ui_lock)
+			tny_lockable_lock (priv->ui_lock);
+		info->callback (info->self, FALSE, NULL, err, info->user_data);
+		if (priv->ui_lock)
+			tny_lockable_unlock (priv->ui_lock);
+		g_error_free (err);
+	}
+	g_slice_free (CreateFolderInfo, info);
+
+	return FALSE;
+}
+
+static void
+tny_merge_folder_store_create_folder_async_default (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	CreateFolderInfo *info;
+
+	/* Idle info for the callbacks */
+	info = g_slice_new (CreateFolderInfo);
+	info->self = self;
+	info->name = g_strdup (name);
+	info->callback = callback;
+	info->user_data = user_data;
+
+	g_object_ref (info->self);
+
+	g_idle_add (create_folder_async_callback, info);
+
+	/* TODO: derive TnyMergeWritableFolderStore which does this:
+	 * create_folder_async (base_store, name, err); */
+}
+
+static void
+tny_merge_folder_store_get_folders_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	g_static_rec_mutex_lock (priv->lock);
+
+	TnyIterator *iter = tny_list_create_iterator (priv->stores);
+	while (!tny_iterator_is_done(iter)) {
+		TnyFolderStore *store = TNY_FOLDER_STORE(tny_iterator_get_current (iter));
+		tny_folder_store_get_folders (store, list, query, refresh, err);
+		g_object_unref (store);
+
+		if (err)
+			break;
+
+		tny_iterator_next (iter);
+	}
+	g_object_unref (iter);
+	g_static_rec_mutex_unlock (priv->lock);
+}
+
+
+typedef struct _GetFoldersInfo
+{
+	TnyFolderStore *self;
+	TnyList *waiting_items;
+	TnyList *list;
+	TnyGetFoldersCallback callback;
+	TnyStatusCallback status_callback;
+	gpointer user_data;
+	gboolean cancelled;
+	GError *error;
+} GetFoldersInfo;
+
+static void
+get_folders_cb (TnyFolderStore *store,
+                     gboolean cancelled,
+                     TnyList *list,
+                     GError *err,
+                     gpointer user_data)
+{
+	GetFoldersInfo *info = user_data;
+	tny_list_remove (info->waiting_items, G_OBJECT(store));
+	if (cancelled)
+		info->cancelled = TRUE;
+
+	/*we'll only end up reporting the first error that occured, but I can't think of a better option */
+	if (err && info->error == NULL)
+		info->error = g_error_copy (err);
+
+	if (tny_list_get_length (info->waiting_items) == 0) {
+
+		info->callback (info->self, info->cancelled, info->list,
+				info->error, info->user_data);
+		g_object_unref (info->waiting_items);
+		g_object_unref (info->list);
+		g_object_unref (info->self);
+
+		if (info->error)
+			g_error_free (info->error);
+
+		g_slice_free (GetFoldersInfo, info);
+	}
+}
+
+static void
+get_folders_status_cb (GObject *self,
+                            TnyStatus *status,
+                            gpointer user_data)
+{
+	GetFoldersInfo *info = user_data;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+	guint num = tny_list_get_length (priv->stores);
+
+	if (num)
+		status->of_total = status->of_total * num;
+
+	info->status_callback (G_OBJECT(info->self), status, info->user_data);
+}
+
+
+static void
+tny_merge_folder_store_get_folders_async_default (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	GetFoldersInfo *info = g_slice_new0 (GetFoldersInfo);
+
+	info->self = g_object_ref (self);
+	info->list = g_object_ref (list);
+	info->waiting_items = tny_list_copy (priv->stores);
+	info->callback = callback;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+
+	g_static_rec_mutex_lock (priv->lock);
+
+	TnyIterator *iter = tny_list_create_iterator (priv->stores);
+	while (!tny_iterator_is_done(iter)) {
+		TnyFolderStore *store = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
+		tny_folder_store_get_folders_async (store, list, query, refresh, get_folders_cb, get_folders_status_cb, info);
+		g_object_unref (store);
+		tny_iterator_next (iter);
+	}
+	g_object_unref (iter);
+	g_static_rec_mutex_unlock (priv->lock);
+
+}
+
+
+
+/* refresh_async:
+ * call refresh on each store
+ * same thing for status_callback as above
+ * in callback., just count up and call user's callback when its all done.
+ */
+
+typedef struct _RefreshAsyncInfo
+{
+	TnyFolderStore *self;
+	TnyList *waiting_items;
+	TnyFolderStoreCallback callback;
+	TnyStatusCallback status_callback;
+	gpointer user_data;
+	gboolean cancelled;
+	GError *error;
+} RefreshAsyncInfo;
+
+static void
+refresh_async_cb (TnyFolderStore *store,
+                       gboolean cancelled,
+                       GError *err,
+                       gpointer user_data)
+{
+	RefreshAsyncInfo *info = user_data;
+	tny_list_remove (info->waiting_items, G_OBJECT(store));
+	if (cancelled)
+		info->cancelled = TRUE;
+
+	/*we'll only end up reporting the first error that occured, but I can't think of a better option */
+	if (err && info->error == NULL)
+		info->error = g_error_copy (err);
+
+	if (tny_list_get_length (info->waiting_items) == 0) {
+		if (info->callback)
+			info->callback (info->self, info->cancelled, info->error, info->user_data);
+		g_object_unref (info->waiting_items);
+		g_object_unref (info->self);
+
+		if (info->error)
+			g_error_free (info->error);
+
+		g_slice_free (RefreshAsyncInfo, info);
+	}
+}
+
+static void
+refresh_async_status_cb (GObject *self,
+                              TnyStatus *status,
+                              gpointer user_data)
+{
+	RefreshAsyncInfo *info = user_data;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (info->self);
+	guint num = tny_list_get_length (priv->stores);
+
+	if (num)
+		status->of_total = status->of_total * num;
+
+	info->status_callback (G_OBJECT(info->self), status, info->user_data);
+}
+
+static void
+tny_merge_folder_store_refresh_async_default (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	RefreshAsyncInfo *info = g_slice_new0 (RefreshAsyncInfo);
+
+	info->self = g_object_ref (self);
+	info->waiting_items = tny_list_copy (priv->stores);
+	info->callback = callback;
+	info->status_callback = status_callback;
+	info->user_data = user_data;
+
+	g_static_rec_mutex_lock (priv->lock);
+
+	TnyIterator *iter = tny_list_create_iterator (priv->stores);
+	while (!tny_iterator_is_done(iter)) {
+		TnyFolderStore *store = TNY_FOLDER_STORE (tny_iterator_get_current (iter));
+		tny_folder_store_refresh_async (store, refresh_async_cb, refresh_async_status_cb, info);
+		g_object_unref (store);
+		tny_iterator_next (iter);
+	}
+	g_object_unref (iter);
+	g_static_rec_mutex_unlock (priv->lock);
+
+}
+
+/**
+ * tny_merge_folder_store_add_store:
+ * @self: a #TnyMergeFolderStore
+ * @store: a #TnyFoldeStore to add to the TnyMergeFolderStore
+ *
+ * Adds #store as a source for this TnyMergeFolderStore
+ */
+void
+tny_merge_folder_store_add_store (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->add_store (self, store);
+}
+
+static void
+tny_merge_folder_store_add_store_default (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	g_static_rec_mutex_lock (priv->lock);
+	tny_folder_store_add_observer (store, TNY_FOLDER_STORE_OBSERVER (self));
+	tny_list_prepend (priv->stores, G_OBJECT(store));
+	g_static_rec_mutex_unlock (priv->lock);
+}
+
+/**
+ * tny_merge_folder_store_remove_store:
+ * @self: a #TnyMergeFolderStore
+ * @store: a #TnyFoldeStore to remove from the TnyMergeFolderStore
+ *
+ * Removes #store as a source for this TnyMergeFolderStore
+ */
+void
+tny_merge_folder_store_remove_store (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_store (self, store);
+}
+
+static void
+tny_merge_folder_store_remove_store_default (TnyMergeFolderStore *self, TnyFolderStore *store)
+{
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	g_static_rec_mutex_lock (priv->lock);
+	tny_folder_store_remove_observer (store, TNY_FOLDER_STORE_OBSERVER (self));
+	tny_list_remove (priv->stores, G_OBJECT(store));
+	g_static_rec_mutex_unlock (priv->lock);
+}
+
+
+/**
+ * tny_merge_folder_store_new:
+ * @ui_locker: a #TnyLockable for locking your ui
+ *
+ * Creates a a new TnyMergeFolderStore instance that can merge multiple
+ * #TnyFolderStore instances together read only. Upon construction it
+ * instantly sets the ui locker. For Gtk+ you should use a #TnyGtkLockable here.
+ * #ui_locker maybe NULL if your toolkit is unthreaded.
+ *
+ * returns: (caller-owns): a new #TnyMergeFolderStore instance
+ * since: 1.0
+ * audience: application-developer
+ **/
+TnyMergeFolderStore*
+tny_merge_folder_store_new (TnyLockable *ui_locker)
+{
+	TnyMergeFolderStore *self = g_object_new (TNY_TYPE_MERGE_FOLDER_STORE, NULL);
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+	priv->ui_lock = ui_locker;
+	return self;
+}
+
+
+static void
+tny_merge_folder_store_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+	TnyMergeFolderStore *self = (TnyMergeFolderStore *)instance;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	priv->stores = tny_simple_list_new ();
+
+	_observer_mixin_init (&(priv->observers));
+
+	priv->known_folders = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
+	priv->lock = g_new0 (GStaticRecMutex, 1);
+	g_static_rec_mutex_init (priv->lock);
+}
+
+static void
+tny_merge_folder_store_dispose (GObject *object)
+{
+	TnyMergeFolderStore *self = (TnyMergeFolderStore *)object;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	_observer_mixin_destroy (self, &(priv->observers));
+
+	g_static_rec_mutex_lock (priv->lock);
+
+	if (priv->known_folders) {
+		g_hash_table_foreach_remove (priv->known_folders, (GHRFunc) known_folder_remover, self);
+		g_hash_table_unref(priv->known_folders);
+		priv->known_folders = NULL;
+	}
+
+	g_object_unref (priv->stores);
+	priv->stores = NULL;
+
+	g_static_rec_mutex_unlock (priv->lock);
+}
+
+static void
+tny_merge_folder_store_finalize (GObject *object)
+{
+	TnyMergeFolderStore *self = (TnyMergeFolderStore *) object;
+	TnyMergeFolderStorePriv *priv = TNY_MERGE_FOLDER_STORE_GET_PRIVATE (self);
+
+	g_free (priv->lock);
+	priv->lock = NULL;
+
+	(*parent_class->finalize) (object);
+}
+
+static void
+tny_merge_folder_store_class_init (TnyMergeFolderStoreClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	object_class = (GObjectClass*) class;
+	object_class->finalize = tny_merge_folder_store_finalize;
+	object_class->dispose = tny_merge_folder_store_dispose;
+
+	class->get_folders_async= tny_merge_folder_store_get_folders_async_default;
+	class->get_folders= tny_merge_folder_store_get_folders_default;
+	class->create_folder= tny_merge_folder_store_create_folder_default;
+	class->create_folder_async= tny_merge_folder_store_create_folder_async_default;
+	class->remove_folder= tny_merge_folder_store_remove_folder_default;
+	class->add_store_observer= tny_merge_folder_store_add_observer_default;
+	class->remove_store_observer= tny_merge_folder_store_remove_observer_default;
+	class->refresh_async = tny_merge_folder_store_refresh_async_default;
+
+	class->add_store = tny_merge_folder_store_add_store_default;
+	class->remove_store = tny_merge_folder_store_remove_store_default;
+
+	g_type_class_add_private (object_class, sizeof (TnyMergeFolderStorePriv));
+
+	return;
+}
+
+static void
+tny_merge_folder_store_remove_folder (TnyFolderStore *self, TnyFolder *folder, GError **err)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_folder(self, folder, err);
+}
+
+
+static TnyFolder*
+tny_merge_folder_store_create_folder (TnyFolderStore *self, const gchar *name, GError **err)
+{
+	return TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->create_folder(self, name, err);
+}
+
+static void
+tny_merge_folder_store_create_folder_async (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->create_folder_async(self, name, callback, status_callback, user_data);
+}
+
+static void
+tny_merge_folder_store_get_folders (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->get_folders(self, list, query, refresh, err);
+}
+
+static void
+tny_merge_folder_store_get_folders_async (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->get_folders_async(self, list, query, refresh, callback, status_callback, user_data);
+}
+
+static void
+tny_merge_folder_store_add_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->add_store_observer(self, observer);
+}
+
+static void
+tny_merge_folder_store_remove_observer (TnyFolderStore *self, TnyFolderStoreObserver *observer)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->remove_store_observer(self, observer);
+}
+
+
+static void
+tny_merge_folder_store_refresh_async (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data)
+{
+	TNY_MERGE_FOLDER_STORE_GET_CLASS (self)->refresh_async(self, callback, status_callback, user_data);
+}
+
+static void
+tny_folder_store_init (gpointer g, gpointer iface_data)
+{
+	TnyFolderStoreIface *klass = (TnyFolderStoreIface *)g;
+
+	klass->remove_folder= tny_merge_folder_store_remove_folder;
+	klass->create_folder= tny_merge_folder_store_create_folder;
+	klass->create_folder_async= tny_merge_folder_store_create_folder_async;
+	klass->get_folders= tny_merge_folder_store_get_folders;
+	klass->get_folders_async= tny_merge_folder_store_get_folders_async;
+	klass->add_observer= tny_merge_folder_store_add_observer;
+	klass->remove_observer= tny_merge_folder_store_remove_observer;
+	klass->refresh_async = tny_merge_folder_store_refresh_async;
+}
+
+static void
+tny_folder_store_observer_init (gpointer g, gpointer iface_data)
+{
+	TnyFolderStoreObserverIface *klass = (TnyFolderStoreObserverIface *)g;
+
+	klass->update = tny_merge_folder_store_observer_update;
+}
+
+
+static gpointer
+tny_merge_folder_store_register_type (gpointer notused)
+{
+	GType type = 0;
+
+	static const GTypeInfo info =
+		{
+			sizeof (TnyMergeFolderStoreClass),
+			NULL,   /* base_init */
+			NULL,   /* base_finalize */
+			(GClassInitFunc) tny_merge_folder_store_class_init,   /* class_init */
+			NULL,   /* class_finalize */
+			NULL,   /* class_data */
+			sizeof (TnyMergeFolderStore),
+			0,      /* n_preallocs */
+			tny_merge_folder_store_instance_init    /* instance_init */
+		};
+
+	static const GInterfaceInfo tny_folder_store_info =
+		{
+			(GInterfaceInitFunc) tny_folder_store_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+	static const GInterfaceInfo tny_folder_store_observer_info =
+		{
+			(GInterfaceInitFunc) tny_folder_store_observer_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+
+	type = g_type_register_static (G_TYPE_OBJECT,
+				       "TnyMergeFolderStore",
+				       &info, 0);
+
+	g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE,
+				     &tny_folder_store_info);
+
+	g_type_add_interface_static (type, TNY_TYPE_FOLDER_STORE_OBSERVER,
+				     &tny_folder_store_observer_info);
+
+	return GUINT_TO_POINTER (type);
+}
+
+GType
+tny_merge_folder_store_get_type (void)
+{
+	static GOnce once = G_ONCE_INIT;
+	g_once (&once, tny_merge_folder_store_register_type, NULL);
+	return GPOINTER_TO_UINT (once.retval);
+}
Index: libtinymail/tny-merge-folder-store.h
===================================================================
--- libtinymail/tny-merge-folder-store.h	(révision 0)
+++ libtinymail/tny-merge-folder-store.h	(révision 22)
@@ -0,0 +1,72 @@
+#ifndef TNY_MERGE_FOLDER_STORE_H
+#define TNY_MERGE_FOLDER_STORE_H
+
+/* libtinymail - The Tiny Mail base library
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ * Copyright (C) Rob Taylor <rob taylor codethink co uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <tny-shared.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_MERGE_FOLDER_STORE             (tny_merge_folder_store_get_type ())
+#define TNY_MERGE_FOLDER_STORE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStore))
+#define TNY_MERGE_FOLDER_STORE_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStoreClass))
+#define TNY_IS_MERGE_FOLDER_STORE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_MERGE_FOLDER_STORE))
+#define TNY_IS_MERGE_FOLDER_STORE_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_MERGE_FOLDER_STORE))
+#define TNY_MERGE_FOLDER_STORE_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_MERGE_FOLDER_STORE, TnyMergeFolderStoreClass))
+
+typedef struct _TnyMergeFolderStore TnyMergeFolderStore;
+typedef struct _TnyMergeFolderStoreClass TnyMergeFolderStoreClass;
+
+struct _TnyMergeFolderStore
+{
+	GObject parent;
+};
+
+struct _TnyMergeFolderStoreClass
+{
+	GObjectClass parent;
+
+	void (*get_folders_async) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, TnyGetFoldersCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	void (*get_folders) (TnyFolderStore *self, TnyList *list, TnyFolderStoreQuery *query, gboolean refresh, GError **err);
+	void (*remove_folder) (TnyFolderStore *self, TnyFolder *folder, GError **err);
+	TnyFolder* (*create_folder) (TnyFolderStore *self, const gchar *name, GError **err);
+	void (*create_folder_async) (TnyFolderStore *self, const gchar *name, TnyCreateFolderCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+	TnyFolderStore* (*get_folder_store) (TnyFolder *self);
+	void (*add_store_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+	void (*remove_store_observer) (TnyFolderStore *self, TnyFolderStoreObserver *observer);
+	void (*refresh_async) (TnyFolderStore *self, TnyFolderStoreCallback callback, TnyStatusCallback status_callback, gpointer user_data);
+
+	void (*add_store) (TnyMergeFolderStore *self, TnyFolderStore *store);
+	void (*remove_store) (TnyMergeFolderStore *self, TnyFolderStore *store);
+};
+
+GType tny_merge_folder_store_get_type (void);
+
+TnyMergeFolderStore* tny_merge_folder_store_new (TnyLockable *ui_locker);
+
+void tny_merge_folder_store_add_store (TnyMergeFolderStore *self, TnyFolderStore *store);
+void tny_merge_folder_store_remove_store (TnyMergeFolderStore *self, TnyFolderStore *store);
+
+G_END_DECLS
+
+#endif
Index: libtinymail/observer-mixin-priv.h
===================================================================
--- libtinymail/observer-mixin-priv.h	(révision 0)
+++ libtinymail/observer-mixin-priv.h	(révision 22)
@@ -0,0 +1,42 @@
+#ifndef OBSERVER_MIXIN_H
+#define OBSERVER_MIXIN_H
+
+/* libtinymail-camel - The Tiny Mail base library for Camel
+ * Copyright (C) 2006-2007 Philip Van Hoof <pvanhoof gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct _ObserverMixin {
+	GList *list;
+	GStaticRecMutex *lock;
+} ObserverMixin;
+
+
+typedef void (*ObserverUpdateMethod) (gpointer, gpointer);
+
+void _observer_mixin_init (ObserverMixin *mixin);
+void _observer_mixin_destroy (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_add_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_observer (gpointer owner, ObserverMixin *mixin, gpointer observer);
+void _observer_mixin_remove_all_observers (gpointer owner, ObserverMixin *mixin);
+void _observer_mixin_notify_observers_about_in_idle (gpointer mixin_owner, ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock, GDestroyNotify done_notify);
+void _observer_mixin_notify_observers_about (ObserverMixin *mixin, ObserverUpdateMethod method, gpointer change, TnyLockable *ui_lock);
+
+#endif
Index: libtinymail/Makefile.am
===================================================================
--- libtinymail/Makefile.am	(révision 21)
+++ libtinymail/Makefile.am	(révision 22)
@@ -11,7 +11,7 @@
 
 CLEANFILES=tny-signals-marshal.c tny-signals-marshal.h
 
-private_headers = tny-common-priv.h
+private_headers = tny-common-priv.h observer-mixin-priv.h
 
 libtinymail_1_0_headers = \
 	tny-signals-marshal.h \
@@ -54,7 +54,8 @@
 	tny-cached-file.h \
 	tny-cached-file-stream.h \
 	tny-combined-account.h \
-	tny-connection-policy.h 
+	tny-connection-policy.h \
+	tny-merge-folder-store.h
 
 libtinymail_1_0_la_SOURCES = \
 	$(libtinymail_1_0_headers) \
@@ -104,6 +105,8 @@
 	tny-idle-stopper.c \
 	tny-progress-info.c \
 	tny-connection-policy.c \
+	tny-merge-folder-store.c \
+	observer-mixin.c \
 	$(private_headers)
 
 libtinymail_1_0_la_LIBADD = $(LIBTINYMAIL_LIBS)
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(révision 22)
+++ libtinymail-camel/tny-camel-folder.c	(révision 23)
@@ -6215,7 +6215,8 @@
 	g_static_rec_mutex_unlock (priv->obs_lock);
 
 	g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
-	notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
+	if (tny_folder_store_change_get_changed (change) != 0) 
+		notify_folder_store_observers_about_in_idle (self, change, TNY_FOLDER_PRIV_GET_SESSION (priv));
 	g_object_unref (change);
 
 	return;

--- End Message ---


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