summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivasa Ragavan <sragavan@gnome.org>2012-01-12 19:56:32 +0530
committerSrinivasa Ragavan <sragavan@gnome.org>2012-01-17 19:11:00 +0530
commit953c1fdc61453d40b93f4ad01037d75d9af7e542 (patch)
treec710200ed45937af523bd928926e9449d61245f0
parent2283d6981be542e2b2bb4a3986539de9d300520b (diff)
downloadevolution-data-server-email-factory-3-4.tar.gz
Add mobile support to POP and fix a bug where uids are duplicated.email-factory-3-4
-rw-r--r--camel/providers/pop3/camel-pop3-folder.c263
-rw-r--r--camel/providers/pop3/camel-pop3-folder.h7
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 af86fdc17..1d6951aaf 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 f7ed542dd..aa3955161 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 {