Re: Broken behaviour in the demo-ui



Hi there,

I identified the commit that caused the incorrect behaviour. The commit
was http://tinymail.org/trac/tinymail/changeset/3775 which was a commit
that combined all approved patches coming from Rob.

This commit has been reverted with hopefully all changes that came after
3775 kept in tact. Please review your own changes and code to ensure
that the revert kept yours in tact.

This is the revert-commit:

http://tinymail.org/trac/tinymail/changeset/3779

I have attached the exact diff that I used to revert.

The two people who have committed changes after 3775, Sergio and José,
are in CC of this mail. 

I have not further investigated which exact patch caused the behaviour
to be incorrect. I'm sure it's something trivial but regretfully I don't
have time myself to spot the exact problem.

Let's try to be more careful in future (about what we commit) and always
test the patches against at least the demo-user interface. I will
restart doing this more often myself too.

So with regard to Rob's patches this brings us back to Oct 9th:

One of these was responsible:

* [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




On Thu, 2008-10-16 at 21:09 +0200, Philip Van Hoof wrote:
> Recently I decided to push more of the review process of Tinymail
> towards peer-review between Rob Taylor, Sergio Villar and myself.
> 
> Apparently since some time has the behaviour of the demo user interface
> got broken.
> 
> The demo-user interface is among the most simplistic use-case (in code)
> of the Tinymail library. Since conception has the code of the demo-user
> interface never been altered (unless for API changes) and never has the
> demo-user interface been wrong. There's no discussion possible when it's
> about trying to "correct" the demo-user interface: The demo-user
> interface is right, it's *always* the mistake of the library and *has
> always been* the mistake of the library in the past too.
> 
> This means that a commit to the library has broken the expected
> behaviour. Let me be crystal clear about that.
> 
> The broken behaviour is that in the demo-ui every folder underneath
> INBOX appears duplicated in the demo-user interface.
> 
> This problem will of course need to be fixed. I want to release Tinymail
> 1.0 very soon so in case this broken behaviour doesn't get fixed I will
> as a, in my opinion, completely reasonable solution, start rolling back
> patches until the behaviour is correct.
> 
> I urge peer-reviewers to test each patch against the demo-user interface
> instead of *only* their own E-mail clients.
> 
> An immediate consequence is that I hereby block all patches, including
> patches #10 and #12. I don't want to infect the code with more patches
> until the broken behaviour is fixed.
> 
> 
> Hoping this problem gets fixed soon,
> 
> 
> Philip
> 
> 
-- 
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
Index: libtinymail-camel/tny-camel-queue-priv.h
===================================================================
--- libtinymail-camel/tny-camel-queue-priv.h	(revision 3774)
+++ libtinymail-camel/tny-camel-queue-priv.h	(revision 3775)
@@ -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,6 +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, TnyCamelQueueStopCb stop_cb, gpointer user_data);
 
 G_END_DECLS
 
Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(revision 3774)
+++ libtinymail-camel/tny-camel-folder.c	(revision 3775)
@@ -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)
 {
@@ -3176,7 +3193,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 +3365,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 +4901,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)
 		{
@@ -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,22 +5341,49 @@
 
 	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;
 }
 
 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);
 	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,
@@ -5365,8 +5409,16 @@
 
 		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)) {
+			iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store,  priv->folder_name, 0, &ex);
+		} else {
+			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))
@@ -5384,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
@@ -5429,7 +5508,6 @@
 	return;
 }
 
-
 typedef struct 
 {
 	TnyCamelQueueable parent;
@@ -5439,6 +5517,7 @@
 	TnyList *list;
 	TnyGetFoldersCallback callback;
 	TnyFolderStoreQuery *query;
+	gboolean refresh;
 	gpointer user_data;
 	TnySessionCamel *session;
 	gboolean cancelled;
@@ -5489,7 +5568,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 +5615,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 +5636,7 @@
 	info->callback = callback;
 	info->user_data = user_data;
 	info->query = query;
+	info->refresh = refresh;
 	info->err = NULL;
 
 	/* thread reference */
@@ -5579,7 +5659,222 @@
 	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;
+	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;
+
+	g_return_if_fail (priv->folder_name != NULL);
+
+	iter = camel_store_get_folder_info (store, priv->folder_name, 0, &ex);
+
+	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->cant_reuse_iter = FALSE;
+	priv->iter_parented = FALSE;
+
+	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))
+		{
+			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 (self, folder, iter);
+
+			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);
+	  }
+
+	}
+
+
+	_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)
 {
@@ -5895,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));
 
@@ -5909,6 +6214,11 @@
 	}
 	g_static_rec_mutex_unlock (priv->obs_lock);
 
+	g_hash_table_foreach (priv->known_folders, build_appeared_change, change);
+	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;
 }
 
@@ -6058,6 +6368,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);
 
@@ -6230,6 +6543,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;
 }
@@ -6348,6 +6662,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-folder.h
===================================================================
--- libtinymail-camel/tny-camel-folder.h	(revision 3774)
+++ libtinymail-camel/tny-camel-folder.h	(revision 3775)
@@ -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-send-queue.c
===================================================================
--- libtinymail-camel/tny-camel-send-queue.c	(revision 3774)
+++ libtinymail-camel/tny-camel-send-queue.c	(revision 3775)
@@ -1297,6 +1297,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	(revision 3774)
+++ libtinymail-camel/tny-camel-send-queue.h	(revision 3775)
@@ -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-camel/tny-camel-store-account-priv.h
===================================================================
--- libtinymail-camel/tny-camel-store-account-priv.h	(revision 3774)
+++ libtinymail-camel/tny-camel-store-account-priv.h	(revision 3775)
@@ -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-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c	(revision 3774)
+++ libtinymail-camel/tny-camel-queue.c	(revision 3775)
@@ -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,21 +296,28 @@
 		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;
 			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;
+	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);
-
-	return NULL;
+	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, FALSE, &err);
+			queue, TRUE, &err);
 		if (err) {
-			queue->stopped = TRUE;
+			g_object_unref (queue);
 		}
 	} else {
 		g_mutex_lock (queue->mutex);
@@ -514,6 +559,47 @@
 	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, TnyCamelQueueStopCb stop_cb, gpointer user_data)
+{
+
+	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_static_rec_mutex_unlock (queue->lock);
+}
+
 static void 
 tny_camel_queue_class_init (TnyCamelQueueClass *class)
 {
@@ -537,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	(revision 3774)
+++ libtinymail-camel/tny-camel-store-account.c	(revision 3775)
@@ -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)
 {
@@ -767,6 +811,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 +844,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) {
@@ -824,6 +876,7 @@
 		camel_object_unref (CAMEL_OBJECT (priv->iter_store));
 	}
 
+	_tny_camel_queue_stop (priv->msg_queue, NULL, NULL);
 	g_object_unref (priv->msg_queue);
 
 	return;
@@ -952,7 +1005,7 @@
 		TnyIterator *iter;
 
 		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), 
-				folders, NULL, &nerr);
+				folders, NULL, TRUE, &nerr);
 
 		if (nerr != NULL)
 		{
@@ -1276,9 +1329,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);
 }
 
 /**
@@ -1313,6 +1366,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)
 {
@@ -1351,12 +1420,13 @@
 }
 
 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);    
 	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));
@@ -1401,9 +1471,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)) {
+			iter = CAMEL_DISCO_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->get_folder_info_offline(store,  "", 0, &ex);
+		} else {
+			iter = camel_store_get_folder_info (store, "", 0, &ex);
+		}
 
+	}
+
 	/*else
 		iter = priv->iter;*/
 
@@ -1418,6 +1494,11 @@
 			return;
 	}
 
+	if (iter && priv->iter == NULL)  {
+		first_time = TRUE;
+	}
+
+
 	priv->iter = iter;
 	priv->cant_reuse_iter = FALSE;
 
@@ -1428,33 +1509,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);
@@ -1472,6 +1573,7 @@
 	TnyList *list;
 	TnyGetFoldersCallback callback;
 	TnyFolderStoreQuery *query;
+	gboolean refresh;
 	gpointer user_data;
 	TnySessionCamel *session;
 	gboolean cancelled;
@@ -1518,7 +1620,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 +1661,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 +1686,7 @@
 	info->callback = callback;
 	info->user_data = user_data;
 	info->query = query;
+	info->refresh = refresh;
 
 	/* thread reference */
 	g_object_ref (info->self);
@@ -1604,17 +1707,261 @@
 	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;
+	gboolean first_time = FALSE;
 
+	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;
+
+
+	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;
+	}
+
+	if (iter && priv->iter == NULL)  {
+		first_time = TRUE;
+	}
+
+	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;
+
+	if (iter) {
+		TnyFolderStoreChange *change = NULL;
+
+		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);
+			}
+			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;
+}
+
+
+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);
 }
 
+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));
 
@@ -1625,11 +1972,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)
 {
@@ -2072,6 +2421,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;
 }
@@ -2103,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-store-account.h
===================================================================
--- libtinymail-camel/tny-camel-store-account.h	(revision 3774)
+++ libtinymail-camel/tny-camel-store-account.h	(revision 3775)
@@ -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: libtinymail-camel/tny-camel-account.c
===================================================================
--- libtinymail-camel/tny-camel-account.c	(revision 3774)
+++ libtinymail-camel/tny-camel-account.c	(revision 3775)
@@ -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,6 +2222,7 @@
 
 	g_static_rec_mutex_unlock (priv->service_lock);
 
+	_tny_camel_queue_stop (priv->queue, NULL, NULL);
 	g_object_unref (priv->queue);
 	g_object_unref (priv->con_strat);
 
@@ -2318,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-folder-priv.h
===================================================================
--- libtinymail-camel/tny-camel-folder-priv.h	(revision 3774)
+++ libtinymail-camel/tny-camel-folder-priv.h	(revision 3775)
@@ -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: libtinymail-camel/tny-camel-account.h
===================================================================
--- libtinymail-camel/tny-camel-account.h	(revision 3774)
+++ libtinymail-camel/tny-camel-account.h	(revision 3775)
@@ -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: libtinymailui-gtk/tny-gtk-folder-store-tree-model.c
===================================================================
--- libtinymailui-gtk/tny-gtk-folder-store-tree-model.c	(revision 3774)
+++ libtinymailui-gtk/tny-gtk-folder-store-tree-model.c	(revision 3775)
@@ -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: tests/functional/folder-lister-async.c
===================================================================
--- tests/functional/folder-lister-async.c	(revision 3774)
+++ tests/functional/folder-lister-async.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/functional/folder-remove.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/functional/account-refresh.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/functional/msg-transfer.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/functional/folder-lister.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/functional/folder-transfer.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/c-demo/tny-demoui-summary-view.c	(revision 3775)
@@ -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	(revision 3774)
+++ tests/memory/memory-test.c	(revision 3775)
@@ -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	(revision 3774)
+++ ChangeLog	(revision 3775)
@@ -1,5 +1,50 @@
 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:
+	* 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/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-shared.h
===================================================================
--- libtinymail/tny-shared.h	(revision 3774)
+++ libtinymail/tny-shared.h	(revision 3775)
@@ -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	(revision 3774)
+++ libtinymail/tny-combined-account.c	(revision 3775)
@@ -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-change.c
===================================================================
--- libtinymail/tny-folder-store-change.c	(revision 3774)
+++ libtinymail/tny-folder-store-change.c	(revision 3775)
@@ -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	(revision 3774)
+++ libtinymail/tny-folder-store-change.h	(revision 3775)
@@ -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: libtinymail/tny-folder-store.c
===================================================================
--- libtinymail/tny-folder-store.c	(revision 3774)
+++ libtinymail/tny-folder-store.c	(revision 3775)
@@ -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	(revision 3774)
+++ libtinymail/tny-folder-store.h	(revision 3775)
@@ -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
 


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