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 *
@@ -852,24 +857,30 @@
 	return mi;
 }
 
+/* Declare these helpers ### */
+static void folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8],
+		CamelVeeFolder *vf, gboolean update_db);
+static void folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8],
+		int keep, CamelVeeFolder *vf, gboolean update_db);
+static void folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8],
+		CamelVeeFolder *vf, gboolean update_db);
+
+
 static void
 vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source)
 {
-	int i, count, n, still = FALSE, start, last;
-	char *oldkey;
+	int i, count, still = FALSE, start, last;
 	CamelFolder *folder = (CamelFolder *)vf;
 	char hash[8];
 	CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
-	void *oldval;
 	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;
 	CamelFolderSummary *ssummary = source->summary;
 	int killun = FALSE;
-	char *expr;
 	
 	if (vf == folder_unmatched)
 		return;
 
+	/* See if we just blow all uid's from this folder away from unmatched, regardless */
 	if ((source->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED))
 		killun = TRUE;
 
@@ -885,34 +896,6 @@
 		}
 
 		CAMEL_VEE_FOLDER_LOCK(folder_unmatched, summary_lock);
-
-		/* See if we just blow all uid's from this folder away from unmatched, regardless */
-		if (killun) {
-			start = -1;
-			last = -1;
-			count = camel_folder_summary_count(((CamelFolder *)folder_unmatched)->summary);
-			for (i=0;i<count;i++) {
-				CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)folder_unmatched)->summary, i);
-				
-				if (mi) {
-					if (mi->summary == ssummary) {
-						camel_folder_change_info_remove_uid(folder_unmatched->changes, camel_message_info_uid(mi));
-						if (last == -1) {
-							last = start = i;
-						} else if (last+1 == i) {
-							last = i;
-						} else {
-							camel_folder_summary_remove_range(((CamelFolder *)folder_unmatched)->summary, start, last);
-							i -= (last-start)+1;
-							start = last = i;
-						}
-					}
-					camel_message_info_free((CamelMessageInfo *)mi);
-				}
-			}
-			if (last != -1)
-				camel_folder_summary_remove_range(((CamelFolder *)folder_unmatched)->summary, start, last);
-		}
 	}
 
 	/*FIXME: This can be optimized a lot like, searching for UID in the summary uids */
@@ -923,55 +906,18 @@
 		CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
 		if (mi) {
 			if (mi->summary == ssummary) {
-				const char *uid = camel_message_info_uid(mi);
-
-				camel_folder_change_info_remove_uid(vf->changes, uid);
-
-				if (last == -1) {
-					last = start = i;
-				} else if (last+1 == i) {
-					last = i;
-				} else {
-					camel_folder_summary_remove_range(folder->summary, start, last);
-					i -= (last-start)+1;
-					start = last = i;
-				}
-				if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && folder_unmatched != NULL) {
-					if (still) {
-						if (g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
-							n = GPOINTER_TO_INT (oldval);
-							if (n == 1) {
-								CamelMessageInfo *tinfo;
-								g_hash_table_remove(unmatched_uids, oldkey);
-								if ((tinfo = (CamelMessageInfo *) vee_folder_add_uid(folder_unmatched, source, oldkey+8, hash)) != NULL) {
-									camel_message_info_free (tinfo);
-									camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
-								}
-								g_free(oldkey);
-							} else {
-								g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
-							}
-						}
-					} else {
-						if (g_hash_table_lookup_extended(unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
-							g_hash_table_remove(unmatched_uids, oldkey);
-							g_free(oldkey);
-						}
-					}
-				}
+				/* Calling folder_changed_remove_uid on each message individually
+				 * is probably slower than the previous code, but I am more convinced
+				 * that it will work! - Matt */
+				folder_changed_remove_uid(source, camel_message_info_uid(mi),
+					hash, !killun && still, vf, TRUE);
+				/* Correct for removal from vfolder summary. */
+				i--; count--;
 			}
 			camel_message_info_free((CamelMessageInfo *)mi);
 		}
 	}
 
-	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)) {
@@ -1035,26 +981,8 @@
 static void
 folder_added_uid(char *uidin, void *value, struct _update_data *u)
 {
-	CamelVeeMessageInfo *mi;
-	char *oldkey;
-	void *oldval;
-	int n;
-
-	if ( (mi = vee_folder_add_uid(u->vf, u->source, uidin, u->hash)) ) {
-		camel_folder_change_info_add_uid(u->vf->changes, camel_message_info_uid(mi));
-		#warning "Handle exceptions"
-		#warning "Make all these as transactions, just testing atm"
-		if (u->rebuilt)
-			camel_db_add_to_vfolder_transaction (((CamelFolder *) u->vf)->parent_store->cdb_w, ((CamelFolder *) u->vf)->full_name, (char *) camel_message_info_uid(mi), NULL);
-		if (!CAMEL_IS_VEE_FOLDER(u->source) && u->unmatched_uids != NULL) {
-			if (g_hash_table_lookup_extended(u->unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
-				n = GPOINTER_TO_INT (oldval);
-				g_hash_table_insert(u->unmatched_uids, oldkey, GINT_TO_POINTER(n+1));
-			} else {
-				g_hash_table_insert(u->unmatched_uids, g_strdup(camel_message_info_uid(mi)), GINT_TO_POINTER(1));
-			}
-		}
-	}
+	/* This now does all the work for us. */
+	folder_changed_add_uid(u->source, uidin, u->hash, u->vf, u->rebuilt);
 }
 
 
@@ -1067,7 +995,7 @@
 	GSList *del_list = NULL;
 	CamelFolder *f = source;
 	CamelFolder *folder = (CamelFolder *)vf;
-	int i, n, count, start, last;
+	int i, count, start, last;
 	struct _update_data u;
 	CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
 	CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
@@ -1092,17 +1020,13 @@
 		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;
+				/* We still need to rebuild: we may need to clear out
+				 * matches from a non-auto-updating vfolder that no
+				 * longer has any matches from this source folder. - Matt */
+				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\")))");
 		}
 		
 	}
@@ -1154,31 +1078,12 @@
 
 		if (mi) {
 			if (mi->summary == ssummary) {
-				char *uid = (char *)camel_message_info_uid(mi), *oldkey;
-				void *oldval;
+				char *uid = (char *)camel_message_info_uid(mi);
 				
 				if (g_hash_table_lookup(matchhash, uid+8) == NULL) {
-					if (last == -1) {
-						last = start = i;
-					} else if (last+1 == i) {
-						last = i;
-					} else {
-						camel_folder_summary_remove_range(folder->summary, start, last);
-						i -= (last-start)+1;
-						start = last = i;
-					}
-					camel_folder_change_info_remove_uid(vf->changes, camel_message_info_uid(mi));
-					if (!CAMEL_IS_VEE_FOLDER(source)
-					    && unmatched_uids != NULL
-					    && g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
-						n = GPOINTER_TO_INT (oldval);
-						if (n == 1) {
-							g_hash_table_remove(unmatched_uids, oldkey);
-							g_free(oldkey);
-						} else {
-							g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
-						}
-					}
+					folder_changed_remove_uid(source, uid+8, shash, TRUE, vf, rebuilded);
+					/* Correct for removal from vfolder summary. */
+					i--; count--;
 				} else {
 					g_hash_table_remove(matchhash, uid+8);
 				}
@@ -1186,8 +1091,6 @@
 			camel_message_info_free((CamelMessageInfo *)mi);
 		}
 	}
-	if (last != -1)
-		camel_folder_summary_remove_range(folder->summary, start, last);
 
 	/* now matchhash contains any new uid's, add them, etc */
 	if (rebuilded) {
@@ -1240,10 +1143,10 @@
 
 	CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
 	
-	/* Del the unwanted things from the summary, we don't hold any locks now. */
+	/* Delete from the DB any matches that have been deleted from the
+	 * source folder.  We don't hold any locks now. */
 	if (del_list) {
 		camel_db_delete_vuids(folder->parent_store->cdb_w, folder->full_name, shash, del_list, NULL);
-		((CamelVeeSummary *)folder->summary)->force_counts = TRUE;
 		g_slist_foreach (del_list, (GFunc) camel_pstring_free, NULL);
 		g_slist_free (del_list);	
 	};
@@ -1362,7 +1265,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 +1282,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);
@@ -1398,8 +1303,11 @@
 	}
 }
 
+/* Note: Callers looping through the vfolder summary
+ * need to correct for the removal done by this function. */
 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,11 +1328,13 @@
 	}
 	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) {
 		if (keep) {
+			/* Message is just being removed from vfolder. */
 			if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
 				n = GPOINTER_TO_INT (oldval);
 				if (n == 1) {
@@ -1440,6 +1350,7 @@
 					camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
 			}
 		} else {
+			/* Message was actually deleted from source folder.  Remove from unmatched too. */
 			if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
 				g_hash_table_remove(unmatched_uids, oldkey);
 				g_free(oldkey);
@@ -1456,7 +1367,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 +1402,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 +1440,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 +1452,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 +1520,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 +1534,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 +1560,30 @@
 
 	/* 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]))
+					/* Changed "keep" to TRUE because I think these messages
+					 * haven't been deleted from the source folder. - Matt */
+					folder_changed_remove_uid(sub, always_changed->pdata[i], hash, TRUE, vf, update_db);
+			}
+	
+			g_hash_table_destroy (ht_present);
 		}
-
-		g_hash_table_destroy (ht_present);
 		g_ptr_array_free(always_changed, TRUE);
 	}
 
@@ -1679,21 +1611,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 +1634,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 +1677,19 @@
 		camel_folder_change_info_free(unmatched_changes);
 	}
 	
-	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);
-		}
+	/* 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) {
 		camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
 		camel_folder_change_info_free(vf_changes);
 	}
@@ -2310,3 +2246,4 @@
 	g_hash_table_destroy (vf->loaded);	
 	g_free(p);
 }
+
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
 
