diff options
author | Srinivasa Ragavan <sragavan@gnome.org> | 2012-01-12 19:56:32 +0530 |
---|---|---|
committer | Srinivasa Ragavan <sragavan@gnome.org> | 2012-01-17 19:11:00 +0530 |
commit | 953c1fdc61453d40b93f4ad01037d75d9af7e542 (patch) | |
tree | c710200ed45937af523bd928926e9449d61245f0 | |
parent | 2283d6981be542e2b2bb4a3986539de9d300520b (diff) | |
download | evolution-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.c | 263 | ||||
-rw-r--r-- | 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 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 { |