[evolution-data-server/imap-pop-mobile: 9/11] Add mobile support to POP and fix a bug where uids are duplicated.



commit af0cd01f82aa3b63eb9db3c2bb9f539fb0ba696c
Author: Srinivasa Ragavan <sragavan gnome org>
Date:   Thu Jan 12 19:56:32 2012 +0530

    Add mobile support to POP and fix a bug where uids are duplicated.

 camel/providers/pop3/camel-pop3-folder.c |  263 +++++++++++++++++++++++++++++-
 camel/providers/pop3/camel-pop3-folder.h |    7 +
 2 files changed, 266 insertions(+), 4 deletions(-)
---
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index af86fdc..1d6951a 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -34,12 +34,32 @@
 
 #include "camel-pop3-folder.h"
 #include "camel-pop3-store.h"
+#include "camel-pop3-settings.h"
 
-#define d(x)
+#define d(x) if (camel_debug("pop")) x;
 
 G_DEFINE_TYPE (CamelPOP3Folder, camel_pop3_folder, CAMEL_TYPE_FOLDER)
 
 static void
+free_fi (CamelPOP3Folder *pop3_folder,CamelPOP3FolderInfo *fi)
+{
+
+	CamelPOP3Store *pop3_store;
+	CamelStore *store;
+
+	store = camel_folder_get_parent_store ((CamelFolder *)pop3_folder);
+	pop3_store = CAMEL_POP3_STORE(store);
+
+	g_hash_table_remove (pop3_folder->uids_id, GINT_TO_POINTER(fi->id));
+	if (fi->cmd) {
+		camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+		fi->cmd = NULL;
+	}
+	g_free (fi->uid);
+	g_free (fi);
+	
+}
+static void
 cmd_uidl (CamelPOP3Engine *pe,
           CamelPOP3Stream *stream,
           GCancellable *cancellable,
@@ -134,9 +154,19 @@ cmd_list (CamelPOP3Engine *pe,
 	CamelStore *parent_store;
 	CamelPOP3Store *pop3_store;
 	CamelPOP3FolderInfo *fi;
+	int i=0, total, last_uid=-1;
+	CamelPOP3Folder *pop3_folder;
+	CamelService *service;
+	CamelSettings *settings;
+	int batch_fetch_count;
 
 	parent_store = camel_folder_get_parent_store (folder);
 	pop3_store = CAMEL_POP3_STORE (parent_store);
+	pop3_folder = (CamelPOP3Folder *)folder;
+	service = (CamelService *) parent_store;
+	settings = camel_service_get_settings (service);
+
+	batch_fetch_count = camel_pop3_settings_get_batch_fetch_count (CAMEL_POP3_SETTINGS(settings));
 
 	do {
 		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, NULL);
@@ -148,12 +178,140 @@ cmd_list (CamelPOP3Engine *pe,
 				fi->index = ((CamelPOP3Folder *) folder)->uids->len;
 				if ((pop3_store->engine->capa & CAMEL_POP3_CAP_UIDL) == 0)
 					fi->cmd = camel_pop3_engine_command_new(pe, CAMEL_POP3_COMMAND_MULTI, cmd_builduid, fi, cancellable, NULL, "TOP %u 0\r\n", id);
-				g_ptr_array_add (((CamelPOP3Folder *) folder)->uids, fi);
-				g_hash_table_insert (((CamelPOP3Folder *) folder)->uids_id, GINT_TO_POINTER (id), fi);
+				g_ptr_array_add (pop3_folder->uids, fi);
+				g_hash_table_insert (pop3_folder->uids_id, GINT_TO_POINTER (id), fi);
 			}
 		}
 	} while (ret > 0);
-}
+
+	/* Trim the list for mobile devices*/
+	if (pop3_folder->mobile_mode && pop3_folder->uids->len) {
+		int y=0;
+		gboolean save_uid = FALSE;
+		CamelNetworkSettings *network_settings;
+		const gchar *host; 
+
+		network_settings = CAMEL_NETWORK_SETTINGS (settings);
+		host = camel_network_settings_get_host (network_settings);
+		
+		d(printf("*********** Mobile mode *************\n"));
+		d(printf("Total Count: %s: %d\n", host, pop3_folder->uids->len));
+
+		/* Preserve the first message's ID */
+		fi = pop3_folder->uids->pdata[0];
+		pop3_folder->first_id = fi->id;
+
+		total = pop3_folder->uids->len;
+		if (pop3_folder->key_file) {
+			last_uid = g_key_file_get_integer (pop3_folder->key_file, "UIDConfig", "last-saved-uid", NULL);
+			if (!last_uid) {
+				/* First time downloading the POP folder, lets just download only a batch. */
+				last_uid = -1;
+			}
+			d(printf("Last stored' first uid: %d\n", last_uid));
+		}
+
+		if (last_uid == -1)
+			save_uid = TRUE;
+
+		for (i=total-1; i >= 0; i--) {
+			fi = pop3_folder->uids->pdata[i];
+
+			if ((last_uid != -1 && last_uid >= fi->id) || (last_uid == -1 && i == total-batch_fetch_count)) {
+				if (last_uid != -1 && last_uid < fi->id)
+					i++; /* if the last uid was deleted on the server, then we need the last but 1*/
+				break;
+			} 
+			
+		}
+		if (i> 0 && pop3_folder->fetch_type == CAMEL_FETCH_OLD_MESSAGES && pop3_folder->fetch_more) {
+			int k=0;
+			/* Lets pull another window of old messages */
+			save_uid = TRUE;
+			/* Decrement 'i' by another batch count or till we reach the first message */
+			d(printf("Fetch more (%d): from %d", pop3_folder->fetch_more, i));
+			for (k=0; k< pop3_folder->fetch_more && i>= 0; k++, i--);
+			d(printf(" to %d\n", i));
+
+			/* Don't load messages newer than the latest we already had. We had to just get old messages and not 
+			 * new messages. */
+			for (y=i; y<total; y++) {
+				fi = pop3_folder->uids->pdata[y];
+				if (fi->id == pop3_folder->latest_id) {
+					/* Delete everything after this. */
+
+					for (y=k+1; y < total; y++) {
+						fi = pop3_folder->uids->pdata[y];
+						free_fi (pop3_folder, fi);
+					}
+					g_ptr_array_remove_range (pop3_folder->uids, k+1, total-k-1);
+					break;
+				}
+			}
+				
+		} else if (pop3_folder->fetch_more == CAMEL_FETCH_NEW_MESSAGES && pop3_folder->fetch_more) {
+			/* We need to download new messages. */
+			int k=0;
+
+			for (k=i; k<total; k++) {
+				fi = pop3_folder->uids->pdata[k];
+				if (fi->id == pop3_folder->latest_id) {
+					/* We need to just download the specified number of messages. */
+					y= (k+pop3_folder->fetch_more) < total ? (k+pop3_folder->fetch_more) : total-1;
+					break;
+				}
+			}
+
+		}
+		
+		/* Delete the unnecessary old messages */
+		if (i > 0) {
+			int j=0;
+			/* i is the start of the last fetch UID, so remove everything else from 0 to i */
+			for (; j<i; j++) {
+				fi = pop3_folder->uids->pdata[j];
+				free_fi (pop3_folder, fi);
+			}
+			g_ptr_array_remove_range (pop3_folder->uids, 0, i);
+			d(printf("Removing %d uids that are old\n", i));
+			
+		} 
+
+		/* Delete the unnecessary new message references. */
+		if (y+1 < total) {
+			int k;
+
+			for (k=y+1; k < total; k++) {
+				fi = pop3_folder->uids->pdata[k];
+				free_fi (pop3_folder, fi);
+			}
+			g_ptr_array_remove_range (pop3_folder->uids, y+1, total-y-1);
+		}
+
+		if (save_uid) {
+			char *contents;
+			gsize len;
+			const char *root;
+			char *path;
+	
+			/* Save the last fetched UID */
+			fi = pop3_folder->uids->pdata[0];			
+			g_key_file_set_integer (pop3_folder->key_file, "UIDConfig", "last-saved-uid", fi->id);
+			contents = g_key_file_to_data (pop3_folder->key_file, &len, NULL);
+			root = camel_service_get_user_cache_dir (service);
+			path = g_build_filename (root, "uidconfig", NULL);
+			g_file_set_contents (path, contents, len, NULL);
+			g_key_file_load_from_file (pop3_folder->key_file, path, G_KEY_FILE_NONE, NULL);		
+			g_free (contents);
+			g_free (path);
+			d(printf("Saving last uid %d\n", fi->id));
+			
+		}
+
+	}
+
+}	
+
 
 static void
 cmd_tocache (CamelPOP3Engine *pe,
@@ -503,6 +661,36 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
 	camel_operation_push_message (
 		cancellable, _("Retrieving POP summary"));
 
+	/* Get rid of the old cache */
+	if (pop3_folder->uids) {
+		gint i;
+		CamelPOP3FolderInfo *last_fi;
+
+		last_fi = pop3_folder->uids->pdata[pop3_folder->uids->len-1];
+		pop3_folder->latest_id = last_fi->id;
+
+		for (i = 0; i < pop3_folder->uids->len; i++) {
+			CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
+			if (fi->cmd) {
+				camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
+				fi->cmd = NULL;
+			}
+			g_free (fi->uid);
+			g_free (fi);
+		}
+
+		g_ptr_array_free (pop3_folder->uids, TRUE);
+	}
+
+	if (pop3_folder->uids_fi) {
+		g_hash_table_destroy (pop3_folder->uids_fi);
+		pop3_folder->uids_fi = NULL;
+	}
+
+	/* Get a new working set. */
+	pop3_folder->uids = g_ptr_array_new ();
+	pop3_folder->uids_fi = g_hash_table_new (g_str_hash, g_str_equal);
+
 	/* only used during setup */
 	pop3_folder->uids_id = g_hash_table_new (NULL, NULL);
 
@@ -550,6 +738,49 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
 }
 
 static gboolean
+pop3_fetch_messages_sync (CamelFolder *folder, 
+			  CamelFetchType type,
+			  int limit,
+			  GCancellable *cancellable, 
+			  GError **error)
+{
+	CamelPOP3FolderInfo *fi;
+	CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *)folder;
+	int old_len;
+	CamelStore *parent_store;
+	CamelService *service;
+	CamelSettings *settings;
+	int batch_fetch_count;
+
+	parent_store = camel_folder_get_parent_store (folder);
+	service = (CamelService *) parent_store;
+	settings = camel_service_get_settings (service);
+
+	batch_fetch_count = camel_pop3_settings_get_batch_fetch_count (CAMEL_POP3_SETTINGS(settings));
+
+	old_len = pop3_folder->uids->len;
+
+	/* If we have the first message already, then return FALSE */
+	fi = pop3_folder->uids->pdata[0];
+	if (type == CAMEL_FETCH_OLD_MESSAGES && fi->id == pop3_folder->first_id)
+		return FALSE;
+	
+	pop3_folder->fetch_type = type;
+	pop3_folder->fetch_more = (limit > 0) ? limit : batch_fetch_count;
+	pop3_folder_refresh_info_sync (folder, cancellable, error);
+	pop3_folder->fetch_more = 0;
+
+	/* Even if we downloaded the first/oldest message, just now, return TRUE so that we wont waste another cycle */
+	fi = pop3_folder->uids->pdata[0];
+	if (type == CAMEL_FETCH_OLD_MESSAGES && fi->id == pop3_folder->first_id)
+		return FALSE;
+	else if (type == CAMEL_FETCH_NEW_MESSAGES && old_len == pop3_folder->uids->len)
+		return FALSE; /* We didnt fetch any new messages as there were none probably. */
+
+	return TRUE;
+}
+
+static gboolean
 pop3_folder_synchronize_sync (CamelFolder *folder,
                               gboolean expunge,
                               GCancellable *cancellable,
@@ -660,6 +891,7 @@ camel_pop3_folder_class_init (CamelPOP3FolderClass *class)
 	object_class->dispose = pop3_folder_dispose;
 
 	folder_class = CAMEL_FOLDER_CLASS (class);
+	folder_class->fetch_messages_sync = pop3_fetch_messages_sync;	
 	folder_class->get_message_count = pop3_folder_get_message_count;
 	folder_class->get_uids = pop3_folder_get_uids;
 	folder_class->free_uids = camel_folder_free_shallow;
@@ -683,7 +915,13 @@ camel_pop3_folder_new (CamelStore *parent,
                        GError **error)
 {
 	CamelFolder *folder;
+	CamelService *service;
+	CamelSettings *settings;
+	CamelPOP3Folder *pop3_folder;
 
+	service = CAMEL_SERVICE (parent);
+	settings = camel_service_get_settings (service);
+	
 	d(printf("opening pop3 INBOX folder\n"));
 
 	folder = g_object_new (
@@ -691,6 +929,23 @@ camel_pop3_folder_new (CamelStore *parent,
 		"full-name", "inbox", "display-name", "inbox",
 		"parent-store", parent, NULL);
 
+	pop3_folder = (CamelPOP3Folder *) folder;
+	pop3_folder->mobile_mode = camel_pop3_settings_get_mobile_mode (CAMEL_POP3_SETTINGS (settings));
+
+	pop3_folder->fetch_more = 0;
+	if (pop3_folder->mobile_mode) {
+		/* Setup Keyfile */
+		char *path;
+		const char *root;
+
+		pop3_folder->key_file = g_key_file_new();
+		root = camel_service_get_user_cache_dir (service);
+		path = g_build_filename (root, "uidconfig", NULL);
+		g_key_file_load_from_file (pop3_folder->key_file, path, G_KEY_FILE_NONE, NULL);
+
+		g_free (path);
+	}
+
 	if (camel_service_get_connection_status (CAMEL_SERVICE (parent)) != CAMEL_SERVICE_CONNECTED)
 		return folder;
 
diff --git a/camel/providers/pop3/camel-pop3-folder.h b/camel/providers/pop3/camel-pop3-folder.h
index f7ed542..aa39551 100644
--- a/camel/providers/pop3/camel-pop3-folder.h
+++ b/camel/providers/pop3/camel-pop3-folder.h
@@ -69,6 +69,13 @@ struct _CamelPOP3Folder {
 	GPtrArray *uids;
 	GHashTable *uids_fi;	/* messageinfo uid to CamelPOP3FolderInfo *, which is stored in uids array */
 	GHashTable *uids_id;	/* messageinfo by id */
+
+	GKeyFile *key_file;
+	gboolean mobile_mode;
+	int fetch_more;
+	CamelFetchType fetch_type;
+	int first_id;
+	int latest_id;
 };
 
 struct _CamelPOP3FolderClass {



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