commit 1733fcd3955ed4d876ca4a6b0e7e5d18b4c274ef
Author: Johnny Jacob <jjohnny@novell.com>
Date:   Wed Jun 10 14:56:24 2009 +0530

    Fix for BGO 583490 – evolution-mapi not removing listing of message not on server
    
       * camel-mapi-folder.c (deleted_items_sync_cb): Added. Callback function for
       collecting message UIDs from server.
       (mapi_sync_deleted): Added. Downsync deleted items from server.
       (mapi_sync_deleted_free): Added.
       (mapi_refresh_folder): On refresh, downsync deleted items from server.

	Modified src/camel/ChangeLog
diff --git a/src/camel/ChangeLog b/src/camel/ChangeLog
index aa1c12b..1e68740 100644
--- a/src/camel/ChangeLog
+++ b/src/camel/ChangeLog
@@ -1,3 +1,13 @@
+2009-06-10  Johnny Jacob  <jjohnny@novell.com>
+
+	** Fix for BGO 583490 – evolution-mapi not removing listing of message not on server
+
+	* camel-mapi-folder.c (deleted_items_sync_cb): Added. Callback function for
+	collecting message UIDs from server.
+	(mapi_sync_deleted): Added. Downsync deleted items from server.
+	(mapi_sync_deleted_free): Added.
+	(mapi_refresh_folder): On refresh, downsync deleted items from server.
+
 2009-06-03  Johnny Jacob  <jjohnny@novell.com>
 
 	* camel-mapi-store.h: Updates for new util functions.
	Modified src/camel/camel-mapi-folder.c
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index 5e20aba..86f553c 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -40,6 +40,7 @@
 #include <camel/camel-data-wrapper.h>
 #include <camel/camel-multipart.h>
 #include <camel/camel-private.h>
+#include <camel/camel-session.h>
 #include <camel/camel-stream-buffer.h>
 #include <camel/camel-stream-mem.h>
 #include <camel/camel-debug.h>
@@ -462,9 +463,11 @@ mapi_update_cache (CamelFolder *folder, GSList *list, CamelFolderChangeInfo **ch
 			camel_folder_change_info_change_uid (changes, mi->info.uid);
 			camel_message_info_free (pmi);
 		} else {
+			CAMEL_MAPI_FOLDER_REC_LOCK (folder, cache_lock);
 			camel_folder_summary_add (folder->summary,(CamelMessageInfo *)mi);
 			camel_folder_change_info_add_uid (changes, mi->info.uid);
 			camel_folder_change_info_recent_uid (changes, mi->info.uid);
+			CAMEL_MAPI_FOLDER_REC_UNLOCK (folder, cache_lock);
 		}
 
 		/********************* Summary ends *************************/
@@ -495,6 +498,138 @@ mapi_utils_do_flags_diff (flags_diff_t *diff, guint32 old, guint32 _new)
 	diff->bits = _new & diff->changed;
 }
 
+
+struct mapi_update_deleted_msg {
+	CamelSessionThreadMsg msg;
+
+	CamelFolder *folder;
+	mapi_id_t folder_id;
+};
+
+static gboolean
+deleted_items_sync_cb (FetchItemsCallbackData *item_data, gpointer data)
+{
+	GSList **uid_list = (GSList **) data;
+	gchar *msg_uid = exchange_mapi_util_mapi_ids_to_uid (item_data->fid, 
+							     item_data->mid);
+
+	*uid_list = g_slist_prepend (*uid_list, msg_uid);
+
+	/* Progress update */
+	if (item_data->total > 0)
+		camel_operation_progress (NULL, (item_data->index * 100)/item_data->total);
+
+	/* Check if we have to stop */
+	if (camel_operation_cancel_check(NULL))
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+mapi_sync_deleted (CamelSession *session, CamelSessionThreadMsg *msg)
+{
+	struct mapi_update_deleted_msg *m = (struct mapi_update_deleted_msg *)msg;
+
+	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (m->folder->parent_store);
+	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (m->folder);
+	CamelFolderChangeInfo *changes = NULL;
+	CamelMessageInfo *info = NULL;
+
+	guint32 index, count, options = 0;
+	GSList *server_uid_list = NULL;
+	const gchar *uid = NULL;
+	gchar *tmp = NULL;
+
+	/* Currently we don't have simple wrapper over getprops.*/
+	const guint32 prop_list[] = { PR_LAST_MODIFICATION_TIME };
+	
+	CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
+
+	if (((CamelOfflineStore *) mapi_store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL ||
+			((CamelService *)mapi_store)->status == CAMEL_SERVICE_DISCONNECTED) {
+	
+		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+		return;
+	}
+
+	camel_operation_start (NULL, _("Retriving message IDs from server for %s"), m->folder->name);
+
+	/*Get the UID list from server.*/
+	exchange_mapi_connection_fetch_items  (m->folder_id, NULL, NULL,
+					       prop_list, G_N_ELEMENTS (prop_list),
+					       NULL, NULL,
+					       deleted_items_sync_cb, &server_uid_list,
+					       options);
+
+	camel_operation_end (NULL);
+
+	/* Check if we have to stop */
+	if (camel_operation_cancel_check(NULL))
+		return;
+
+	changes = camel_folder_change_info_new ();
+
+	count = camel_folder_summary_count (m->folder->summary);
+	camel_operation_start (NULL, _("Removing deleted messages from cache in %s"), m->folder->name);
+
+	/* Iterate over cache and check if the UID is in server*/
+	for (index = 0; index < count; index++) {
+		/*FIXME :Any other list available ???*/
+		info = camel_folder_summary_index (m->folder->summary, index);
+		if (!info) continue; /*This is bad. *Should* not happen*/
+
+		uid = camel_message_info_uid (info);
+
+		if (server_uid_list) {
+			/* TODO : Find a better way and avoid this linear search */
+			tmp = g_slist_find_custom (server_uid_list, (const gchar *)uid, 
+						  (GCompareFunc) g_strcmp0);
+		}
+
+		/* If it is not in server list, clean our cache */
+		if (!tmp && uid) {
+			CAMEL_MAPI_FOLDER_REC_LOCK (m->folder, cache_lock);
+			camel_folder_summary_remove_uid (m->folder->summary, uid);
+			camel_data_cache_remove (mapi_folder->cache, "cache", uid, NULL);
+			camel_folder_change_info_remove_uid (changes, uid);
+			CAMEL_MAPI_FOLDER_REC_UNLOCK (m->folder, cache_lock);
+		}
+
+		/* Progress update */
+		camel_operation_progress (NULL, (index * 100)/count); /* ;-) */
+
+		/* Check if we have to stop */
+		if (camel_operation_cancel_check(NULL))
+			return;
+	}
+
+	camel_operation_end (NULL);
+
+	camel_object_trigger_event (m->folder, "folder_changed", changes);
+	camel_folder_change_info_free (changes);
+
+	/* Discard server uid list */
+	g_slist_foreach (server_uid_list, (GFunc) g_free, NULL);
+	g_slist_free (server_uid_list);
+
+	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
+}
+
+static void
+mapi_sync_deleted_free (CamelSession *session, CamelSessionThreadMsg *msg)
+{
+	struct mapi_update_deleted_msg *m = (struct mapi_update_deleted_msg *)msg;
+
+	camel_object_unref (m->folder);
+	/* camel_session_thread_msg_free (session, &m->msg); */
+}
+
+static CamelSessionThreadOps deleted_items_sync_ops = {
+	mapi_sync_deleted,
+	mapi_sync_deleted_free,
+};
+
 static void
 mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 {
@@ -507,7 +642,7 @@ mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 	flags_diff_t diff, unset_flags;
 	const char *folder_id;
 	mapi_id_t fid, deleted_items_fid;
-	int count, i;
+	gint count, i;
 	guint32 options =0;
 
 	GSList *deleted_items, *deleted_head;
@@ -600,6 +735,7 @@ mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 		g_slist_free (read_items);
 	}
 
+	/* Remove messages from server*/
 	if (deleted_items) {
 		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
 		if (mapi_folder->type & CAMEL_FOLDER_TYPE_TRASH) {
@@ -611,7 +747,8 @@ mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 
 		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
 	}
-	/*Remove them from cache*/
+
+	/*Remove messages from local cache*/
 	while (deleted_items) {
 		char* deleted_msg_uid = g_strdup_printf ("%016" G_GINT64_MODIFIER "X%016" G_GINT64_MODIFIER "X", fid, *(mapi_id_t *)deleted_items->data);
 
@@ -623,7 +760,6 @@ mapi_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
 		deleted_items = g_slist_next (deleted_items);
 	}
 
-
 	if (unread_items) {
 		CAMEL_SERVICE_REC_LOCK (mapi_store, connect_lock);
 		/* TODO */
@@ -650,12 +786,15 @@ mapi_refresh_folder(CamelFolder *folder, CamelException *ex)
 	CamelMapiStore *mapi_store = CAMEL_MAPI_STORE (folder->parent_store);
 	CamelMapiFolder *mapi_folder = CAMEL_MAPI_FOLDER (folder);
 	CamelMapiSummary *mapi_summary = CAMEL_MAPI_SUMMARY (folder->summary);
+	CamelSession *session = ((CamelService *)folder->parent_store)->session;
+
 	gboolean is_proxy = folder->parent_store->flags & CAMEL_STORE_PROXY;
 	gboolean is_locked = FALSE;
 	gboolean status;
 
 	struct mapi_SRestriction *res = NULL;
 	struct SSortOrderSet *sort = NULL;
+	struct mapi_update_deleted_msg *deleted_items_op_msg;
 	fetch_items_data *fetch_data = g_new0 (fetch_items_data, 1);
 
 	const gchar *folder_id = NULL;
@@ -741,7 +880,7 @@ mapi_refresh_folder(CamelFolder *folder, CamelException *ex)
 			/*BUG : Fix exception string.*/
 			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 					     _("This message is not available in offline mode."));
-			goto end2;
+			goto end1;
 		}
 
 		if (((CamelMapiFolder *)folder)->type & CAMEL_MAPI_FOLDER_PUBLIC)
@@ -758,7 +897,7 @@ mapi_refresh_folder(CamelFolder *folder, CamelException *ex)
 
 		if (!status) {
 			camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Fetching items failed"));
-			goto end2;
+			goto end1;
 		}
 
 		/*Preserve last_modification_time from this fetch for later use with restrictions.*/
@@ -767,17 +906,22 @@ mapi_refresh_folder(CamelFolder *folder, CamelException *ex)
 		camel_folder_summary_touch (folder->summary);
 		mapi_sync_summary (folder, ex);
 
-		camel_object_trigger_event (folder, "folder_changed", fetch_data->changes);
+		/* Downsync deleted items */
+		deleted_items_op_msg = camel_session_thread_msg_new (session, &deleted_items_sync_ops, 
+							 sizeof (*deleted_items_op_msg));
+		deleted_items_op_msg->folder = folder;
+		deleted_items_op_msg->folder_id = temp_folder_id;
+		camel_object_ref (folder);
+
+		camel_session_thread_queue (session, &deleted_items_op_msg->msg, 0);
 
+		camel_object_trigger_event (folder, "folder_changed", fetch_data->changes);
 		camel_folder_change_info_free (fetch_data->changes);
 	}
 
-
 	CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);
 	is_locked = FALSE;
 
-end2:
-	//TODO:
 end1:
 	if (is_locked)
 		CAMEL_SERVICE_REC_UNLOCK (mapi_store, connect_lock);

