[evolution-data-server/meego-eds: 41/47] Adds mobile support to camel. Fetch limited mails on pop/imapx.
- From: Srinivasa Ragavan <sragavan src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/meego-eds: 41/47] Adds mobile support to camel. Fetch limited mails on pop/imapx.
- Date: Wed, 15 Jun 2011 10:56:44 +0000 (UTC)
commit 22cdaeb04dccd9e5c939f3b554361cd68c766b78
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]