Index: evolution-data-server/camel/camel-vee-folder.c
===================================================================
--- evolution-data-server/camel/camel-vee-folder.c	(revision 9793)
+++ evolution-data-server/camel/camel-vee-folder.c	(working copy)
@@ -83,7 +83,6 @@
 static void subfolder_deleted(CamelFolder *f, void *event_data, CamelVeeFolder *vf);
 static void folder_renamed(CamelFolder *f, const char *old, CamelVeeFolder *vf);
 
-static void folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf);
 static void summary_reloaded(CamelObject *o, void *event_data, void *data);
 
 static CamelFolderClass *camel_vee_folder_parent;
@@ -605,12 +604,7 @@
 	camel_db_write_folder_info_record (folder->parent_store->cdb, record, ex);
 	g_free (record);
 #endif	
-	if (node == NULL) {
-		CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
-		g_list_free(p->folders_changed);
-		p->folders_changed = NULL;
-		CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
-	}
+	/* Don't clear the folders_changed list without actually rebuilding! */
 
 	CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
 
@@ -839,8 +833,19 @@
 /* ********************************************************************** *
    utility functions */
 
-#define COUNT_ADD_EXPR(lval, sexpr) expr = g_strdup_printf("and (%s %s)", vf->expression, sexpr); lval += count_folder(f, expr, ex); g_free(expr);
-#define COUNT_DEL_EXPR(lval, sexpr) expr = g_strdup_printf("and (%s %s)", vf->expression, sexpr); lval -= count_folder(ssummary->folder, expr, NULL); g_free(expr);
+/* A "correlating" expression has the property that whether a message matches
+ * depends on the other messages being searched.  folder_changed_change on a
+ * vfolder with a correlating expression may not make all the necessary updates,
+ * so the query is redone on the entire changed source folder the next time
+ * the vfolder is opened.
+ * 
+ * The only current example of a correlating expression is one that uses
+ * "match-threads". */
+static gboolean
+expression_is_correlating(const char *expr)
+{
+	return (strstr(expr, "match-threads") != NULL);
+}
 
 /* must be called with summary_lock held */
 static CamelVeeMessageInfo *
@@ -865,7 +870,6 @@
 	GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
 	CamelFolderSummary *ssummary = source->summary;
 	int killun = FALSE;
-	char *expr;
 	
 	if (vf == folder_unmatched)
 		return;
@@ -967,11 +971,6 @@
 	if (last != -1)
 		camel_folder_summary_remove_range(folder->summary, start, last);
 	
-	COUNT_DEL_EXPR(folder->summary->junk_count, "(match-all (system-flag  \"junk\"))");
-	COUNT_DEL_EXPR(folder->summary->deleted_count, "(match-all (system-flag  \"deleted\"))");
-	COUNT_DEL_EXPR(folder->summary->unread_count, "(match-all (not (system-flag  \"Seen\")))");
-	COUNT_DEL_EXPR(folder->summary->visible_count, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))");
-	COUNT_DEL_EXPR(folder->summary->junk_not_deleted_count, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))");
 				
 	if (folder_unmatched) {
 		if (camel_folder_change_info_changed(folder_unmatched->changes)) {
@@ -1092,17 +1091,10 @@
 		match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
 		d(printf("len = %d %d for %s %s\n", match ? match->len:0, rebuilded, source->full_name, shash));
 		if (!match) {
-			char *expr;
 			match = camel_folder_search_by_expression(f, vf->expression, ex);
 			if (match == NULL)
-				return 0;
+				match = g_ptr_array_new();
 			rebuilded = TRUE;
-			/* Update the counts */
-			COUNT_ADD_EXPR(folder->summary->junk_count, "(match-all (system-flag  \"junk\"))");
-			COUNT_ADD_EXPR(folder->summary->deleted_count, "(match-all (system-flag  \"deleted\"))");
-			COUNT_ADD_EXPR(folder->summary->unread_count, "(match-all (not (system-flag  \"Seen\")))");
-			COUNT_ADD_EXPR(folder->summary->visible_count, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))");
-			COUNT_ADD_EXPR(folder->summary->junk_not_deleted_count, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))");
 		}
 		
 	}
@@ -1362,7 +1354,8 @@
 		
 /* Hold all these with summary lock and unmatched summary lock held */
 static void
-folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf,
+		gboolean update_db)
 {
 	CamelFolder *folder = (CamelFolder *)vf;	
 	CamelVeeMessageInfo *vinfo;
@@ -1378,7 +1371,8 @@
 		return;
 	
 	vuid = camel_message_info_uid(vinfo);
-	camel_db_add_to_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, (char *)vuid, NULL);
+	if (update_db)
+		camel_db_add_to_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, (char *)vuid, NULL);
 	camel_folder_change_info_add_uid(vf->changes,  vuid);
 	/* old flags and new flags should  be same, since we sync all times  */
 	update_summary (vinfo, camel_message_info_flags(vinfo), 0, TRUE, FALSE);
@@ -1399,7 +1393,8 @@
 }
 
 static void
-folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf)
+folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf,
+		gboolean update_db)
 {
 	CamelFolder *folder = (CamelFolder *)vf;
 	char *vuid, *oldkey;
@@ -1420,7 +1415,8 @@
 	}
 	camel_folder_change_info_remove_uid(vf->changes, vuid);
         /* FIXME[disk-summary] Handle exception */
-	camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, vuid, NULL);
+	if (update_db)
+		camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, vuid, NULL);
 	camel_folder_summary_remove_uid_fast(folder->summary, vuid);
 
 	if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
@@ -1456,7 +1452,8 @@
 }
 
 static void
-folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf,
+		gboolean update_db)
 {
 	char *vuid;
 	CamelVeeMessageInfo *vinfo, *uinfo = NULL;
@@ -1490,7 +1487,7 @@
 			camel_folder_free_message_info(sub, info);
 		} else {
 			if (vinfo) {
-				folder_changed_remove_uid(sub, uid, hash, FALSE, vf);
+				folder_changed_remove_uid(sub, uid, hash, FALSE, vf, update_db);
 				camel_message_info_free((CamelMessageInfo *)vinfo);
 			}
 			if (uinfo)
@@ -1528,6 +1525,8 @@
 	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 correlating = expression_is_correlating(vf->expression);
+	gboolean update_db = TRUE;
 
 	/* Check the folder hasn't beem removed while we weren't watching */
 	CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
@@ -1538,6 +1537,14 @@
 
 	camel_vee_folder_hash_folder(sub, hash);
 
+	if (correlating) {
+		/* Delete the old matches from the database to force the next
+		 * vee_rebuild_folder to re-run the query. */
+		camel_vee_summary_delete_ids((CamelVeeSummary *) folder->summary, hash);
+		/* Don't try to incrementally update matches we have already
+		 * cleared. */
+		update_db = FALSE;
+	}
 
 	/* Lookup anything before we lock anything, to avoid deadlock with build_folder */
 
@@ -1598,7 +1605,7 @@
 	/* Always remove removed uid's, in any case */
 	for (i=0;i<changes->uid_removed->len;i++) {
 		dd(printf("  removing uid '%s'\n", (char *)changes->uid_removed->pdata[i]));
-		folder_changed_remove_uid(sub, changes->uid_removed->pdata[i], hash, FALSE, vf);
+		folder_changed_remove_uid(sub, changes->uid_removed->pdata[i], hash, FALSE, vf, update_db);
 	}
 
 	/* Add any newly matched or to unmatched folder if they dont */
@@ -1612,7 +1619,7 @@
 			uid = changes->uid_added->pdata[i];
 			if (g_hash_table_lookup(matches_hash, uid)) {
 				dd(printf("  adding uid '%s' [newly matched]\n", (char *)uid));
-				folder_changed_add_uid(sub, uid, hash, vf);
+				folder_changed_add_uid(sub, uid, hash, vf, update_db);
 			} else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
 				if (strlen(uid)+9 > vuidlen) {
 					vuidlen = strlen(uid)+64;
@@ -1638,20 +1645,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 (correlating) {
+			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, update_db);
+		} 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, update_db);
+				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, update_db);
+			}
+	
+			g_hash_table_destroy (ht_present);
 		}
-
-		g_hash_table_destroy (ht_present);
 		g_ptr_array_free(always_changed, TRUE);
 	}
 
@@ -1679,21 +1694,21 @@
 				if (g_hash_table_lookup(matches_hash, uid)) {
 					/* A uid we dont have, but now it matches, add it */
 					dd(printf("  adding uid '%s' [newly matched]\n", uid));
-					folder_changed_add_uid(sub, uid, hash, vf);
+					folder_changed_add_uid(sub, uid, hash, vf, update_db);
 				} else {
 					/* A uid we still don't have, just change it (for unmatched) */
-					folder_changed_change_uid(sub, uid, hash, vf);
+					folder_changed_change_uid(sub, uid, hash, vf, update_db);
 				}
 			} else {
 				if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
 				    || g_hash_table_lookup(matches_hash, uid)) {
 					/* still match, or we're not auto-updating, change event, (if it changed) */
 					dd(printf("  changing uid '%s' [still matches]\n", uid));
-					folder_changed_change_uid(sub, uid, hash, vf);
+					folder_changed_change_uid(sub, uid, hash, vf, update_db);
 				} else {
 					/* No longer matches, remove it, but keep it in unmatched (potentially) */
 					dd(printf("  removing uid '%s' [did match]\n", uid));
-					folder_changed_remove_uid(sub, uid, hash, TRUE, vf);
+					folder_changed_remove_uid(sub, uid, hash, TRUE, vf, update_db);
 				}
 				camel_message_info_free((CamelMessageInfo *)vinfo);
 			}
@@ -1702,7 +1717,7 @@
 	} else {
 		/* stuff didn't match but it changed - check unmatched folder for changes */
 		for (i=0;i<changed->len;i++)
-			folder_changed_change_uid(sub, changed->pdata[i], hash, vf);
+			folder_changed_change_uid(sub, changed->pdata[i], hash, vf, update_db);
 	}
 
 	if (folder_unmatched != NULL) {
@@ -1745,15 +1760,19 @@
 		camel_folder_change_info_free(unmatched_changes);
 	}
 	
+	/* Add to folders_changed if we need to call vee_rebuild_folder, which
+	 * could be the case for two reasons:
+	 * - vfolder changed and is not auto-updating; need to re-sync
+	 * - vfolder is correlating; need to re-run query on entire source folder
+	 */
+	if ((vf_changes && (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) || correlating) {
+		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);
 	}
Index: evolution-data-server/camel/camel-db.c
===================================================================
--- evolution-data-server/camel/camel-db.c	(revision 9793)
+++ evolution-data-server/camel/camel-db.c	(working copy)
@@ -681,7 +681,24 @@
 	 return array;
 }
 
+/* MATT - Based on camel_db_delete_uid_from_vfolder, camel_db_get_vuids_from_vfolder */
 int
+camel_db_delete_vuids_from_vfolder (CamelDB *db, char *folder_name, char *filter, CamelException *ex)
+{
+	 char *del_query;
+	 char *tmp = g_strdup_printf("%s%%", filter ? filter:"");
+	 int ret;
+	 del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid LIKE %Q", folder_name, tmp);
+	 g_free(tmp);
+
+	 ret = camel_db_command (db, del_query, ex);
+	 
+	 sqlite3_free (del_query);
+	 CAMEL_DB_RELEASE_SQLITE_MEMORY;
+	 return ret;
+}
+
+int
 camel_db_add_to_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex)
 {
 	 char *ins_query;
Index: evolution-data-server/camel/camel-db.h
===================================================================
--- evolution-data-server/camel/camel-db.h	(revision 9793)
+++ evolution-data-server/camel/camel-db.h	(working copy)
@@ -152,6 +152,7 @@
 int camel_db_delete_uid_from_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 int camel_db_delete_uid_from_vfolder_transaction (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 GPtrArray * camel_db_get_vuids_from_vfolder (CamelDB *db, char *folder_name, char *filter, CamelException *ex);
+int camel_db_delete_vuids_from_vfolder (CamelDB *db, char *folder_name, char *filter, CamelException *ex);
 int camel_db_add_to_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 int camel_db_add_to_vfolder_transaction (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
 
Index: evolution-data-server/camel/camel-vee-summary.c
===================================================================
--- evolution-data-server/camel/camel-vee-summary.c	(revision 9793)
+++ evolution-data-server/camel/camel-vee-summary.c	(working copy)
@@ -412,6 +412,21 @@
 	return array;
 }
 
+/* MATT - Based on camel_vee_summary_get_ids */
+int
+camel_vee_summary_delete_ids (CamelVeeSummary *summary, char hash[8])
+{
+	char *shash = g_strdup_printf("%c%c%c%c%c%c%c%c", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]);
+	CamelFolderSummary *cfs = (CamelFolderSummary *)summary;
+	int ret;
+
+	/* FIXME[disk-summary] fix exception passing */
+	ret = camel_db_delete_vuids_from_vfolder(cfs->folder->parent_store->cdb_w, cfs->folder->full_name, shash, NULL);
+	g_free(shash);
+
+	return ret;
+}
+
 CamelVeeMessageInfo *
 camel_vee_summary_add(CamelVeeSummary *s, CamelFolderSummary *summary, const char *uid, const char hash[8])
 {
Index: evolution-data-server/camel/camel-vee-summary.h
===================================================================
--- evolution-data-server/camel/camel-vee-summary.h	(revision 9793)
+++ evolution-data-server/camel/camel-vee-summary.h	(working copy)
@@ -62,6 +62,7 @@
 
 CamelVeeMessageInfo * camel_vee_summary_add(CamelVeeSummary *s, CamelFolderSummary *summary, const char *uid, const char hash[8]);
 GPtrArray * camel_vee_summary_get_ids (CamelVeeSummary *summary, char hash[8]);
+int camel_vee_summary_delete_ids (CamelVeeSummary *summary, char hash[8]);
 
 G_END_DECLS
 
