[evolution-data-server/email-factory] Adds mobile support to camel. Fetch limited mails on pop/imapx.



commit 38ff814be7b50391ba32fd3fc82dadfde4e5bb0f
Author: Srinivasa Ragavan <sragavan gnome org>
Date:   Tue Jun 7 23:18:44 2011 +0530

    Adds mobile support to camel. Fetch limited mails on pop/imapx.

 camel/camel-folder-summary.c                 |   16 +++
 camel/camel-folder-summary.h                 |    3 +
 camel/camel-folder.c                         |   79 ++++++++++++++
 camel/camel-folder.h                         |   10 ++
 camel/camel-provider.h                       |   19 ++++
 camel/providers/imapx/camel-imapx-folder.c   |   42 +++++++
 camel/providers/imapx/camel-imapx-provider.c |    5 +-
 camel/providers/imapx/camel-imapx-server.c   |  113 +++++++++++++++++---
 camel/providers/imapx/camel-imapx-server.h   |    6 +
 camel/providers/pop3/camel-pop3-folder.c     |  150 +++++++++++++++++++++++++-
 camel/providers/pop3/camel-pop3-folder.h     |    5 +
 camel/providers/pop3/camel-pop3-provider.c   |    2 +-
 12 files changed, 430 insertions(+), 20 deletions(-)
---
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 5667e11..d320c3e 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -1855,6 +1855,22 @@ camel_folder_summary_load_from_db (CamelFolderSummary *s,
 	return ret == 0 ? 0 : -1;
 }
 
+/**
+ * camel_folder_summary_sort_uids
+ *
+ * Sort the summary UIDS as per the folder requirements. This is mostly for backends use. 
+ * They client would hardly have a need to call this function.
+ **/
+void
+camel_folder_summary_sort_uids (CamelFolderSummary *s)
+{
+	struct _CamelFolderSummaryPrivate *p = CAMEL_FOLDER_SUMMARY_GET_PRIVATE(s);
+
+	camel_folder_summary_lock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+	camel_folder_sort_uids (s->folder, s->uids);
+	camel_folder_summary_unlock (s, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+}
+
 static void
 mir_from_cols (CamelMIRecord *mir, CamelFolderSummary *s, gint ncol, gchar ** cols, gchar ** name)
 {
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index 991a8ff..d93708d 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -362,6 +362,9 @@ void camel_folder_summary_touch(CamelFolderSummary *summary);
 /* add a new raw summary item */
 void camel_folder_summary_add (CamelFolderSummary *summary, CamelMessageInfo *info);
 
+/* Sort the uids within the summary to meet the backend's need. */
+void camel_folder_summary_sort_uids (CamelFolderSummary *s);
+
 /* Peek from mem only */
 CamelMessageInfo * camel_folder_summary_peek_info (CamelFolderSummary *s, const gchar *uid);
 
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index d27f658..67b2248 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -1721,6 +1721,85 @@ camel_folder_has_summary_capability (CamelFolder *folder)
 	return folder->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
 }
 
+/**
+ * camel_folder_fetch_old_messages:
+ * @folder: a #CamelFolder
+ * @count: Number of messages to fetch
+ * @error: return location for a #GError, or %NULL
+ *
+ * Fetches more (old) messages if the Folder is operating in mobile mode.
+ *
+ * Returns: #gboolean TRUE if there are more messages to fetch, FALSE otherwise.
+ **/
+gboolean
+camel_folder_fetch_old_messages (CamelFolder *folder,
+				 int count,
+                          	 GError **error)
+{
+	CamelFolderClass *class;
+	gboolean ret;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+	/* Backends that don't support mobile mode will always have all old messages. So lets return FALSE*/
+	if (class->fetch_old_messages == NULL)
+		return FALSE;
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	ret = class->fetch_old_messages (folder, count, error);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	if (ret && camel_debug_start (":folder")) {
+		printf ("CamelFolder:fetch_old_message ('%s') = %d\n",
+			camel_folder_get_full_name (folder), ret);
+		camel_debug_end ();
+	}
+
+	return ret;
+}
+
+/**
+ * camel_folder_purge_old_messages:
+ * @folder: a #CamelFolder
+ * @error: return location for a #GError, or %NULL
+ *
+ * Purge old messages that are downloaded the oldest to conserve space.
+ *
+ * Returns: #gboolean TRUE if messages are purged, FALSE otherwise.
+ **/
+gboolean
+camel_folder_purge_old_messages (CamelFolder *folder,
+                          	 GError **error)
+{
+	CamelFolderClass *class;
+	gboolean ret;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+	class = CAMEL_FOLDER_GET_CLASS (folder);
+
+	if (class->purge_old_messages == NULL)
+		return FALSE;
+
+	camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	ret = class->purge_old_messages (folder, error);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
+
+	if (ret && camel_debug_start (":folder")) {
+		printf ("CamelFolder:purge_old_message ('%s') = %d\n",
+			camel_folder_get_full_name (folder), ret);
+		camel_debug_end ();
+	}
+
+	return ret;
+}
+
+
 /* UIDs stuff */
 
 /**
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index d00fc76..94103c0 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -202,6 +202,11 @@ struct _CamelFolderClass {
 						 GError **error);
 	void		(*search_free)		(CamelFolder *folder,
 						 GPtrArray *result);
+	gboolean	(*fetch_old_messages)   (CamelFolder *folder,
+						 int count,
+						 GError **error);
+        gboolean	(*purge_old_messages)   (CamelFolder *folder,
+						 GError **error);
 	CamelMessageInfo *
 			(*get_message_info)	(CamelFolder *folder,
 						 const gchar *uid);
@@ -331,6 +336,11 @@ gint		camel_folder_get_deleted_message_count
 GPtrArray *	camel_folder_get_summary	(CamelFolder *folder);
 void		camel_folder_free_summary	(CamelFolder *folder,
 						 GPtrArray *array);
+gboolean	camel_folder_fetch_old_messages (CamelFolder *folder,
+						 int count,
+                          			 GError **error);
+gboolean	camel_folder_purge_old_messages (CamelFolder *folder,
+						 GError **error);
 
 /* uid based access operations */
 CamelMimeMessage *
diff --git a/camel/camel-provider.h b/camel/camel-provider.h
index 84b3ab0..1f4d1bb 100644
--- a/camel/camel-provider.h
+++ b/camel/camel-provider.h
@@ -83,6 +83,25 @@ extern gchar *camel_provider_type_name[CAMEL_NUM_PROVIDER_TYPES];
  **/
 #define CAMEL_PROVIDER_ALLOW_REAL_JUNK_FOLDER  (1 << 9)
 
+/** 
+ * CAMEL_PROVIDER_SUPPORTS_MOBILE_DEVICES
+ * Download limited set of emails instead of operating on full cache.
+ **/ 
+
+#define CAMEL_PROVIDER_SUPPORTS_MOBILE_DEVICES (1 << 10)
+/**
+ * CAMEL_PROVIDER_SUPPORTS_BATCH_FETCH
+ * Support to fetch messages in batch
+ **/ 
+
+#define CAMEL_PROVIDER_SUPPORTS_BATCH_FETCH (1 << 11)
+
+/**
+ * CAMEL_PROVIDER_SUPPORTS_PURGE_OLD_MESSAGES
+ * Support to remove oldest downloaded messages to conserve space.
+ **/
+#define CAMEL_PROVIDER_SUPPORTS_PURGE_OLD_MESSAGES (1 << 12)
+
 /* Flags for url_flags. "ALLOW" means the config dialog will let the
  * user configure it. "NEED" implies "ALLOW" but means the user must
  * configure it. Service code can assume that any url part for which
diff --git a/camel/providers/imapx/camel-imapx-folder.c b/camel/providers/imapx/camel-imapx-folder.c
index e4c8e68..dfb2ddd 100644
--- a/camel/providers/imapx/camel-imapx-folder.c
+++ b/camel/providers/imapx/camel-imapx-folder.c
@@ -530,6 +530,46 @@ imapx_search_by_expression (CamelFolder *folder, const gchar *expression, GError
 	return matches;
 }
 
+static gboolean
+imapx_fetch_old_messages (CamelFolder *folder, int count, GError **error)
+{
+	CamelStore *parent_store;
+	CamelIMAPXStore *istore;
+	CamelIMAPXServer *server;
+	gboolean ret = FALSE;
+
+	parent_store = camel_folder_get_parent_store (folder);
+	istore = CAMEL_IMAPX_STORE (parent_store);
+
+	if (CAMEL_OFFLINE_STORE (istore)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
+		g_set_error (
+			error, CAMEL_SERVICE_ERROR,
+			CAMEL_SERVICE_ERROR_UNAVAILABLE,
+			_("You must be working online to complete this operation"));
+		return FALSE;
+	}
+
+	if (!camel_service_connect((CamelService *)istore, error))
+		return FALSE;
+
+	server = camel_imapx_store_get_server(istore, camel_folder_get_full_name (folder), error);
+	if (server != NULL) {
+		ret = camel_imapx_server_fetch_old_messages (server, folder, count, error);
+		camel_imapx_store_op_done (istore, server, camel_folder_get_full_name (folder));
+		g_object_unref(server);
+	}
+
+	return ret;
+
+}
+
+static gboolean
+imapx_purge_old_messages (CamelFolder *folder, GError **error)
+{
+	/* Not implemented now */
+	return FALSE;
+}
+
 static void
 camel_imapx_folder_class_init (CamelIMAPXFolderClass *class)
 {
@@ -553,6 +593,8 @@ camel_imapx_folder_class_init (CamelIMAPXFolderClass *class)
 	folder_class->append_message = imapx_append_message;
 	folder_class->transfer_messages_to = imapx_transfer_messages_to;
 	folder_class->get_filename = imapx_get_filename;
+	folder_class->fetch_old_messages = imapx_fetch_old_messages;
+	folder_class->purge_old_messages = imapx_purge_old_messages;
 }
 
 static void
diff --git a/camel/providers/imapx/camel-imapx-provider.c b/camel/providers/imapx/camel-imapx-provider.c
index 6a92414..baab414 100644
--- a/camel/providers/imapx/camel-imapx-provider.c
+++ b/camel/providers/imapx/camel-imapx-provider.c
@@ -91,7 +91,10 @@ static CamelProvider imapx_provider = {
 	"mail",
 
 	CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE |
-	CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_SUPPORTS_SSL,
+	CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_SUPPORTS_SSL |
+	CAMEL_PROVIDER_SUPPORTS_MOBILE_DEVICES | 
+	CAMEL_PROVIDER_SUPPORTS_BATCH_FETCH |
+	CAMEL_PROVIDER_SUPPORTS_PURGE_OLD_MESSAGES,
 
 	CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH,
 
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 01c504e..b59ce5e 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -73,6 +73,7 @@
 #define BATCH_FETCH_COUNT 500
 
 #define MAX_COMMAND_LEN 1000
+#define FIRST_TIME_DOWNLOAD 100
 
 extern gint camel_application_is_exiting;
 
@@ -200,6 +201,7 @@ enum {
 	IMAPX_JOB_CREATE_FOLDER = 1<<11,
 	IMAPX_JOB_DELETE_FOLDER = 1<<12,
 	IMAPX_JOB_RENAME_FOLDER = 1<<13,
+	IMAPX_JOB_FETCH_OLD_MESSAGES = 1 << 14,
 };
 
 /* Operations on the store (folder_tree) will have highest priority as we know for sure they are sync
@@ -265,6 +267,7 @@ struct _CamelIMAPXJob {
 			/* used for biulding uidset stuff */
 			gint index;
 			gint last_index;
+			gint fetch_old_msg_count;
 			gboolean update_unseen;
 			struct _uidset_state uidset;
 			/* changes during refresh */
@@ -891,10 +894,10 @@ static gboolean duplicate_fetch_or_refresh(CamelIMAPXServer *is, CamelIMAPXComma
 	if (!ic->job)
 		return FALSE;
 
-	if (!(ic->job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO)))
+	if (!(ic->job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO|IMAPX_JOB_FETCH_OLD_MESSAGES)))
 		return FALSE;
 
-	if (imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL)) {
+	if (imapx_match_active_job (is, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_FETCH_OLD_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL)) {
 		c(printf("Not yet sending duplicate fetch/refresh %s command\n", ic->name));
 		return TRUE;
 	}
@@ -1146,6 +1149,7 @@ imapx_job_matches (CamelFolder *folder, CamelIMAPXJob *job, guint32 type, const
 				return TRUE;
 			break;
 		case IMAPX_JOB_FETCH_NEW_MESSAGES:
+		case IMAPX_JOB_FETCH_OLD_MESSAGES:
 		case IMAPX_JOB_REFRESH_INFO:
 		case IMAPX_JOB_SYNC_CHANGES:
 		case IMAPX_JOB_EXPUNGE:
@@ -1417,7 +1421,7 @@ imapx_untagged(CamelIMAPXServer *imap, GError **error)
 		}
 
 		if ((finfo->got & FETCH_FLAGS) && !(finfo->got & FETCH_HEADER)) {
-			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL);
+			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_FETCH_OLD_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL);
 			/* This is either a refresh_info job, check to see if it is and update
 			   if so, otherwise it must've been an unsolicited response, so update
 			   the summary to match */
@@ -1486,7 +1490,7 @@ imapx_untagged(CamelIMAPXServer *imap, GError **error)
 		}
 
 		if ((finfo->got & (FETCH_HEADER|FETCH_UID)) == (FETCH_HEADER|FETCH_UID)) {
-			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL);
+			CamelIMAPXJob *job = imapx_match_active_job (imap, IMAPX_JOB_FETCH_NEW_MESSAGES|IMAPX_JOB_FETCH_OLD_MESSAGES|IMAPX_JOB_REFRESH_INFO, NULL);
 
 			/* This must be a refresh info job as well, but it has asked for
 			   new messages to be added to the index */
@@ -1524,7 +1528,7 @@ imapx_untagged(CamelIMAPXServer *imap, GError **error)
 
 							mid = (min + max)/2;
 							r = &g_array_index(infos, struct _refresh_info, mid);
-							if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES)
+							if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES || job->type == IMAPX_JOB_FETCH_OLD_MESSAGES)
 								cmp = imapx_refresh_info_uid_cmp (finfo->uid, r->uid, !imap->descending);
 							else
 								cmp = imapx_refresh_info_uid_cmp (finfo->uid, r->uid, TRUE);
@@ -2237,6 +2241,7 @@ imapx_server_fetch_new_messages (CamelIMAPXServer *is,
 	job->noreply = async;
 	job->u.refresh_info.changes = camel_folder_change_info_new();
 	job->u.refresh_info.update_unseen = update_unseen;
+	job->u.refresh_info.fetch_old_msg_count = -1;
 	job->op = camel_operation_registered ();
 
 	success = imapx_submit_job (is, job, error);
@@ -3600,6 +3605,8 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 	}
 
 	if (camel_folder_change_info_changed(job->u.refresh_info.changes)) {
+		if (is->descending)
+			camel_folder_summary_sort_uids (ic->job->folder->summary);
 		imapx_update_store_summary (job->folder);
 		camel_folder_summary_save_to_db (job->folder->summary, NULL);
 		camel_folder_changed (job->folder, job->u.refresh_info.changes);
@@ -3608,6 +3615,7 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 	camel_folder_change_info_clear(job->u.refresh_info.changes);
 
 	if (i<infos->len) {
+		int total = camel_folder_summary_count (job->folder->summary);
 		camel_imapx_command_free (ic);
 
 		ic = camel_imapx_command_new(is, "FETCH", job->folder, "UID FETCH ");
@@ -3616,7 +3624,9 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 		ic->pri = job->pri - 1;
 		job->u.refresh_info.last_index = i;
 
-		for (;i<infos->len;i++) {
+		/* If its mobile client, when total=0 (new account setup) fetch only a limited mails,
+ 		 * on futher attempts download all new mails. */
+		for (;i<infos->len && (total || !is->mobile || i< FIRST_TIME_DOWNLOAD);i++) {
 			gint res;
 			struct _refresh_info *r = &g_array_index(infos, struct _refresh_info, i);
 
@@ -3630,8 +3640,8 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 				}
 			}
 		}
-
-		job->u.refresh_info.index = i;
+		printf("Existing : %d Gonna fetch in %s for %d/%d\n", total, camel_folder_get_full_name(job->folder), i, infos->len);
+		job->u.refresh_info.index = infos->len;
 		if (imapx_uidset_done(&job->u.refresh_info.uidset, ic)) {
 			camel_imapx_command_add(ic, " (RFC822.SIZE RFC822.HEADER)");
 			imapx_command_queue(is, ic);
@@ -3663,7 +3673,7 @@ imapx_command_step_fetch_done(CamelIMAPXServer *is, CamelIMAPXCommand *ic)
 		g_free(r->uid);
 	}
 	g_array_free(job->u.refresh_info.infos, TRUE);
-	if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES)
+	if (job->type == IMAPX_JOB_FETCH_NEW_MESSAGES || job->type == IMAPX_JOB_FETCH_OLD_MESSAGES)
 		camel_folder_change_info_free (job->u.refresh_info.changes);
 
 	imapx_job_done (is, job);
@@ -3866,13 +3876,14 @@ static void
 imapx_job_scan_changes_start(CamelIMAPXServer *is, CamelIMAPXJob *job)
 {
 	CamelIMAPXCommand *ic;
+	gchar *uid = camel_folder_summary_uid_from_index (job->folder->summary, 0);
 
 	camel_operation_start (
 		job->op, _("Scanning for changed messages in %s"),
 		camel_folder_get_name (job->folder));
 
 	ic = camel_imapx_command_new (is, "FETCH", job->folder,
-				     "UID FETCH 1:* (UID FLAGS)");
+				     "UID FETCH %s:* (UID FLAGS)", uid);
 	ic->job = job;
 	ic->complete = imapx_job_scan_changes_done;
 	ic->pri = job->pri;
@@ -3899,6 +3910,11 @@ imapx_command_fetch_new_messages_done (CamelIMAPXServer *is, CamelIMAPXCommand *
 	}
 
 	if (camel_folder_change_info_changed(ic->job->u.refresh_info.changes)) {
+		/* If we fetched old messages, the summary must be sorted internally from 
+ 		 * old to new. Otherwise it appends old uids to the end.
+ 		 **/
+		if (ic->job->type == IMAPX_JOB_FETCH_OLD_MESSAGES || is->descending)
+			camel_folder_summary_sort_uids (ic->job->folder->summary);
 		imapx_update_store_summary (ic->job->folder);
 		camel_folder_summary_save_to_db (ic->job->folder->summary, NULL);
 		camel_folder_changed (ic->job->folder, ic->job->u.refresh_info.changes);
@@ -3933,8 +3949,8 @@ exception:
 }
 
 static void
-imapx_command_fetch_new_uids_done	(CamelIMAPXServer *is,
-	                                 CamelIMAPXCommand *ic)
+imapx_command_fetch_uids_descending_done (CamelIMAPXServer *is,
+	                                  CamelIMAPXCommand *ic)
 {
 	CamelIMAPXJob *job = ic->job;
 	GArray *infos = job->u.refresh_info.infos;
@@ -3976,7 +3992,7 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
 		ic->pri = job->pri;
 		
 		if (is->descending)
-			ic->complete = imapx_command_fetch_new_uids_done;
+			ic->complete = imapx_command_fetch_uids_descending_done;
 		else 
 			ic->complete = imapx_command_step_fetch_done;
 
@@ -3993,6 +4009,44 @@ imapx_job_fetch_new_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
 }
 
 static void
+imapx_job_fetch_old_messages_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
+{
+	CamelIMAPXCommand *ic;
+	CamelFolder *folder = job->folder;
+	CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
+	guint32 total, diff;
+	gchar *start_uid = NULL, *end_uid = NULL;
+
+	total = camel_folder_summary_count (folder->summary);
+	diff = ifolder->exists_on_server - total;
+
+	if (total > 0) {
+		unsigned long long uidl;
+		start_uid = camel_folder_summary_uid_from_index (folder->summary, 0);
+		uidl = strtoull(start_uid, NULL, 10);
+		end_uid = g_strdup_printf("%lld", (uidl-job->u.refresh_info.fetch_old_msg_count > 0) ? (uidl-job->u.refresh_info.fetch_old_msg_count) : 1);
+	} else {
+		/* */
+		g_error("Shouldn't call fetch old messages without anything. ");
+	}
+
+	camel_operation_start (
+		job->op, _("Fetching summary information for old messages in %s"),
+		camel_folder_get_name (folder));
+
+	ic = camel_imapx_command_new (is, "FETCH", job->folder,
+				"UID FETCH %s:%s (RFC822.SIZE RFC822.HEADER FLAGS)", start_uid, end_uid);
+	ic->pri = job->pri;
+	ic->complete = imapx_command_fetch_new_messages_done;
+
+	g_free (start_uid);
+	g_free (end_uid);
+
+	ic->job = job;
+	imapx_command_queue (is, ic);
+}
+
+static void
 imapx_job_refresh_info_start (CamelIMAPXServer *is, CamelIMAPXJob *job)
 {
 	guint32 total;
@@ -5002,6 +5056,13 @@ camel_imapx_server_new(CamelStore *store, CamelURL *url)
 	else
 		is->descending = FALSE;
 
+	if (camel_url_get_param (url, "mobile"))
+		is->mobile = TRUE;
+	else
+		is->mobile = FALSE;
+
+	printf("Enabled for Mobile devices? :%d Descending? :%d\n", is->mobile, is->descending);
+
 	return is;
 }
 
@@ -5357,6 +5418,32 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is, CamelFolder *folder, GErr
 	return success;
 }
 
+gboolean
+camel_imapx_server_fetch_old_messages (CamelIMAPXServer *is,
+                                       CamelFolder *folder,
+				       int count,
+                                       GError **error)
+{
+	CamelIMAPXJob *job;
+	gboolean success;
+
+	job = g_malloc0(sizeof(*job));
+	job->type = IMAPX_JOB_FETCH_OLD_MESSAGES;
+	job->start = imapx_job_fetch_old_messages_start;
+	job->folder = folder;
+	job->noreply = FALSE;
+	job->u.refresh_info.changes = camel_folder_change_info_new();
+	job->u.refresh_info.update_unseen = TRUE;
+	job->u.refresh_info.fetch_old_msg_count = count;
+	job->op = camel_operation_registered ();
+
+	success = imapx_submit_job (is, job, error);
+
+	g_free (job);
+
+	return success;
+}
+
 static void
 imapx_sync_free_user(GArray *user_set)
 {
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index c951eec..ca69876 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -121,6 +121,7 @@ struct _CamelIMAPXServer {
 
 	/* order in which new messages would be fetched */
 	gboolean descending;
+	gboolean mobile;
 
 	/* used to synchronize duplicate get_message requests */
 	GCond *fetch_cond;
@@ -155,6 +156,11 @@ GPtrArray *	camel_imapx_server_list		(CamelIMAPXServer *is,
 gboolean	camel_imapx_server_refresh_info	(CamelIMAPXServer *is,
 						 CamelFolder *folder,
 						 GError **error);
+gboolean	camel_imapx_server_fetch_old_messages 		
+						(CamelIMAPXServer *is,
+                                       		 CamelFolder *folder,
+				       		 int count,
+                                       		 GError **error);
 gboolean	camel_imapx_server_sync_changes	(CamelIMAPXServer *is,
 						 CamelFolder *folder,
 						 GError **error);
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index 652cbcb..4ea10ab 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -36,7 +36,8 @@
 #include "camel-pop3-folder.h"
 #include "camel-pop3-store.h"
 
-#define d(x)
+#define d(x) if (camel_debug("pop")) x;
+#define FIRST_TIME_DOWNLOAD 40
 
 static gboolean pop3_refresh_info (CamelFolder *folder, GError **error);
 static gboolean pop3_sync (CamelFolder *folder, gboolean expunge, GError **error);
@@ -45,6 +46,7 @@ static GPtrArray *pop3_get_uids (CamelFolder *folder);
 static CamelMimeMessage *pop3_get_message (CamelFolder *folder, const gchar *uid, GError **error);
 static gboolean pop3_set_message_flags (CamelFolder *folder, const gchar *uid, guint32 flags, guint32 set);
 static gchar * pop3_get_filename (CamelFolder *folder, const gchar *uid, GError **error);
+static gboolean pop3_fetch_old_messages (CamelFolder *folder, int count, GError **error);
 
 G_DEFINE_TYPE (CamelPOP3Folder, camel_pop3_folder, CAMEL_TYPE_FOLDER)
 
@@ -99,6 +101,7 @@ camel_pop3_folder_class_init (CamelPOP3FolderClass *class)
 	folder_class->free_uids = camel_folder_free_shallow;
 	folder_class->get_filename = pop3_get_filename;
 	folder_class->get_message = pop3_get_message;
+	folder_class->fetch_old_messages = pop3_fetch_old_messages;
 	folder_class->set_message_flags = pop3_set_message_flags;
 }
 
@@ -111,6 +114,9 @@ CamelFolder *
 camel_pop3_folder_new (CamelStore *parent, GError **error)
 {
 	CamelFolder *folder;
+	CamelURL *url;
+	CamelPOP3Folder *pop3_folder;
+	CamelService *service;
 
 	d(printf("opening pop3 INBOX folder\n"));
 
@@ -119,6 +125,30 @@ camel_pop3_folder_new (CamelStore *parent, GError **error)
 		"full-name", "inbox", "name", "inbox",
 		"parent-store", parent, NULL);
 
+	pop3_folder = (CamelPOP3Folder *)folder;
+	service = (CamelService *) parent;
+
+	/* This decides if the POP3 downloads entire content or a limited content. */
+	url = service->url;
+	if (camel_url_get_param(url, "mobile"))
+		pop3_folder->mobile = TRUE;
+	else
+		pop3_folder->mobile = FALSE;
+	pop3_folder->fetch_more = 0;
+
+	if (pop3_folder->mobile) {
+		/* Setup Keyfile */
+		char *path, *root;
+
+		pop3_folder->key_file = g_key_file_new();
+		root = camel_session_get_storage_path (camel_service_get_session(service), service, NULL);
+		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);
+		g_free(root);
+		
+	}
 	/* mt-ok, since we dont have the folder-lock for new() */
 	if (!camel_folder_refresh_info (folder, error)) { /* mt-ok */
 		g_object_unref (folder);
@@ -184,9 +214,14 @@ cmd_list(CamelPOP3Engine *pe, CamelPOP3Stream *stream, gpointer data)
 	CamelStore *parent_store;
 	CamelPOP3Store *pop3_store;
 	CamelPOP3FolderInfo *fi;
+	int i=0, total, last_uid=-1;
+	CamelPOP3Folder *pop3_folder;
+	CamelService *service;
 
 	parent_store = camel_folder_get_parent_store (folder);
 	pop3_store = CAMEL_POP3_STORE (parent_store);
+	pop3_folder = (CamelPOP3Folder *)folder;
+	service = (CamelService *) parent_store;
 
 	do {
 		ret = camel_pop3_stream_line(stream, &line, &len);
@@ -198,12 +233,94 @@ cmd_list(CamelPOP3Engine *pe, CamelPOP3Stream *stream, gpointer data)
 				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, "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) {
+		gboolean save_uid = FALSE;
+		
+		d(printf("*********** Mobile mode *************\n"));
+		d(printf("Total Count: %s: %d\n", service->url->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-FIRST_TIME_DOWNLOAD)) {
+				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_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));
+				
+		}
+		
+		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];
+				g_hash_table_remove (pop3_folder->uids_id, GINT_TO_POINTER(fi->id));
+			}
+			g_ptr_array_remove_range (pop3_folder->uids, 0, i);
+			d(printf("Removing %d uids that are old\n", i));
+			
+		} 
+
+		if (save_uid) {
+			char *contents;
+			gsize len;
+			char *root, *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_session_get_storage_path (camel_service_get_session(service), service, NULL);
+			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);
+			g_free(root);
+			d(printf("Saving last uid %d\n", fi->id));
+			
+		}
+
+	}
+
+}	
 
 static void
 cmd_uidl(CamelPOP3Engine *pe, CamelPOP3Stream *stream, gpointer data)
@@ -228,7 +345,7 @@ cmd_uidl(CamelPOP3Engine *pe, CamelPOP3Stream *stream, gpointer data)
 					fi->uid = g_strdup(uid);
 					g_hash_table_insert(folder->uids_uid, fi->uid, fi);
 				} else {
-					g_warning("ID %u (uid: %s) not in previous LIST output", id, uid);
+					//g_warning("ID %u (uid: %s) not in previous LIST output", id, uid);
 				}
 			}
 		}
@@ -303,6 +420,29 @@ pop3_refresh_info (CamelFolder *folder, GError **error)
 }
 
 static gboolean
+pop3_fetch_old_messages (CamelFolder *folder, int count, GError **error)
+{
+	CamelPOP3FolderInfo *fi;
+	CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *)folder;
+
+	/* If we have the first message already, then return FALSE */
+	fi = pop3_folder->uids->pdata[0];
+	if (fi->id == pop3_folder->first_id)
+		return FALSE;
+	
+	pop3_folder->fetch_more = count;
+	pop3_refresh_info (folder, 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 (fi->id == pop3_folder->first_id)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
 pop3_sync (CamelFolder *folder,
            gboolean expunge,
            GError **error)
diff --git a/camel/providers/pop3/camel-pop3-folder.h b/camel/providers/pop3/camel-pop3-folder.h
index aba32a6..2e6d939 100644
--- a/camel/providers/pop3/camel-pop3-folder.h
+++ b/camel/providers/pop3/camel-pop3-folder.h
@@ -70,6 +70,11 @@ struct _CamelPOP3Folder {
 	GPtrArray *uids;
 	GHashTable *uids_uid;	/* messageinfo by uid */
 	GHashTable *uids_id;	/* messageinfo by id */
+	GKeyFile *key_file;
+	gboolean mobile;
+	int fetch_more;
+	int first_id;	
+
 };
 
 struct _CamelPOP3FolderClass {
diff --git a/camel/providers/pop3/camel-pop3-provider.c b/camel/providers/pop3/camel-pop3-provider.c
index 777c3a9..d1e3dfa 100644
--- a/camel/providers/pop3/camel-pop3-provider.c
+++ b/camel/providers/pop3/camel-pop3-provider.c
@@ -57,7 +57,7 @@ static CamelProvider pop3_provider = {
 	"mail",
 
 	CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE |
-	CAMEL_PROVIDER_SUPPORTS_SSL,
+	CAMEL_PROVIDER_SUPPORTS_SSL | CAMEL_PROVIDER_SUPPORTS_MOBILE_DEVICES,
 
 	CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH,
 



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