Index: evolution-data-server/camel/camel-vee-folder.c
===================================================================
--- evolution-data-server/camel/camel-vee-folder.c	(revision 9783)
+++ evolution-data-server/camel/camel-vee-folder.c	(working copy)
@@ -460,30 +460,6 @@
 	}
 }
 
-static void vee_refresh_info(CamelFolder *folder, CamelException *ex)
-{
-	CamelVeeFolder *vf = (CamelVeeFolder *)folder;
-	struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
-	GList *node, *list;
-
-	CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
-	list = p->folders_changed;
-	p->folders_changed = NULL;
-	CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
-
-	node = list;
-	while (node) {
-		CamelFolder *f = node->data;
-
-		if (camel_vee_folder_rebuild_folder(vf, f, ex) == -1)
-			break;
-
-		node = node->next;
-	}
-
-	g_list_free(list);
-}
-
 static guint32
 count_folder (CamelFolder *f, char *expr, CamelException *ex)
 {
@@ -510,6 +486,43 @@
 	return count;
 }
 
+static void redo_counts(CamelFolderSummary *s, CamelException *ex)
+{
+	s->junk_count = count_result (s, "(match-all (system-flag  \"junk\"))", ex);
+	s->deleted_count = count_result (s, "(match-all (system-flag  \"deleted\"))", ex);
+	s->unread_count = count_result (s, "(match-all (not (system-flag  \"Seen\")))", ex);
+	s->visible_count = count_result (s, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))", ex);
+	s->junk_not_deleted_count = count_result (s, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))", ex);
+}
+
+static void vee_refresh_info(CamelFolder *folder, CamelException *ex)
+{
+	CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+	struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
+	GList *node, *list;
+
+	CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+	list = p->folders_changed;
+	p->folders_changed = NULL;
+	CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+
+	node = list;
+	while (node) {
+		CamelFolder *f = node->data;
+
+		if (camel_vee_folder_rebuild_folder(vf, f, ex) == -1)
+			break;
+
+		node = node->next;
+	}
+
+	/* Redo the counts if requested by folder_changed_change. */
+	if (((CamelVeeSummary *) folder->summary)->force_counts)
+		redo_counts(folder->summary, ex);
+
+	g_list_free(list);
+}
+
 static	CamelFIRecord *
 summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
 {
@@ -545,11 +558,7 @@
 		record->jnd_count = s->junk_not_deleted_count;
 	} else {
 		/* Either first time, or by force we search the count */
-		s->junk_count = count_result (s, "(match-all (system-flag  \"junk\"))", ex);
-		s->deleted_count = count_result (s, "(match-all (system-flag  \"deleted\"))", ex);
-		s->unread_count = count_result (s, "(match-all (not (system-flag  \"Seen\")))", ex);
-		s->visible_count = count_result (s, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))", ex);
-		s->junk_not_deleted_count = count_result (s, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))", ex);
+		redo_counts(s, ex);
 
 		record->junk_count = s->junk_count;
 		record->deleted_count = s->deleted_count;
@@ -1089,7 +1098,16 @@
 		match = g_ptr_array_new();
 	} else {
 		/* Load the folder results from the DB. */
-		match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
+		if (!strstr(vf->expression, "match-threads"))
+			match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
+		else {
+			/* Ignore the old results. */
+			match = NULL;
+			/* Since we don't have access to the old state of the source folder,
+			 * we have no way to decrease the counts by the proper amount.
+			 * Instead, tell vee_refresh_info to redo the counts. */
+			((CamelVeeSummary *) folder->summary)->force_counts = TRUE;
+		}
 		d(printf("len = %d %d for %s %s\n", match ? match->len:0, rebuilded, source->full_name, shash));
 		if (!match) {
 			char *expr;
@@ -1528,6 +1546,7 @@
 	CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
 	GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
 	GPtrArray *present = NULL;
+	gboolean folder_is_threaded = (strstr(vf->expression, "match-threads") != NULL);
 
 	/* Check the folder hasn't beem removed while we weren't watching */
 	CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
@@ -1538,7 +1557,6 @@
 
 	camel_vee_folder_hash_folder(sub, hash);
 
-
 	/* Lookup anything before we lock anything, to avoid deadlock with build_folder */
 
 	/* Find newly added that match */
@@ -1638,20 +1656,28 @@
 
 	/* Change any newly changed */
 	if (always_changed) {
-		GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
-
-		for (i=0;present && i<present->len;i++) {
-			folder_changed_change_uid(sub, present->pdata[i], hash, vf);
-			g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
-		}
-		
-		for (i=0; i<always_changed->len; i++) {
-			if (!present || !g_hash_table_lookup(ht_present, always_changed->pdata[i])) {
-				folder_changed_remove_uid(sub, always_changed->pdata[i], hash, FALSE, vf);
+		if (folder_is_threaded) {
+			for (i=0;i<always_changed->len;i++)
+				/* The changed message might be a pull-in, so we don't want to
+				 * remove it under the user's nose just because the message
+				 * itself doesn't match the expression.  Any necessary removals
+				 * will be done later by vee_rebuild_folder. */
+				folder_changed_change_uid(sub, always_changed->pdata[i], hash, vf);
+		} else {
+			GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
+	
+			for (i=0;present && i<present->len;i++) {
+				folder_changed_change_uid(sub, present->pdata[i], hash, vf);
+				g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
 			}
+			
+			for (i=0; i<always_changed->len; i++) {
+				if (!present || !g_hash_table_lookup(ht_present, always_changed->pdata[i]))
+					folder_changed_remove_uid(sub, always_changed->pdata[i], hash, FALSE, vf);
+			}
+	
+			g_hash_table_destroy (ht_present);
 		}
-
-		g_hash_table_destroy (ht_present);
 		g_ptr_array_free(always_changed, TRUE);
 	}
 
@@ -1745,15 +1771,18 @@
 		camel_folder_change_info_free(unmatched_changes);
 	}
 	
+	/* If not auto-updating, keep track of changed folders for later re-sync */
+	/* If the vfolder is threaded, the source folder needs to be marked changed
+	 * regardless of whether we processed any incremental changes here because
+	 * there might be new pull-ins. */
+	if ((vf_changes || folder_is_threaded) && (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
+		CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+		if (g_list_find(vf->priv->folders_changed, sub) == NULL)
+			vf->priv->folders_changed = g_list_prepend(vf->priv->folders_changed, sub);
+		CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+	}
+
 	if (vf_changes) {
-		/* If not auto-updating, keep track of changed folders for later re-sync */
-		if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
-			CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
-			if (g_list_find(vf->priv->folders_changed, sub) != NULL)
-				vf->priv->folders_changed = g_list_prepend(vf->priv->folders_changed, sub);
-			CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
-		}
-
 		camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
 		camel_folder_change_info_free(vf_changes);
 	}
