aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap')
-rw-r--r--camel/providers/imap/camel-imap-command.c120
-rw-r--r--camel/providers/imap/camel-imap-command.h2
-rw-r--r--camel/providers/imap/camel-imap-folder.c78
-rw-r--r--camel/providers/imap/camel-imap-store.c1
4 files changed, 116 insertions, 85 deletions
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index 7215168dc7..ac929b044a 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -146,9 +146,7 @@ static CamelImapResponse *
imap_read_response (CamelImapStore *store, CamelException *ex)
{
CamelImapResponse *response;
- int number, exists = 0;
- GArray *expunged = NULL;
- char *respbuf, *retcode, *word, *p;
+ char *respbuf, *retcode;
/* Read first line */
if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store),
@@ -156,6 +154,9 @@ imap_read_response (CamelImapStore *store, CamelException *ex)
return NULL;
response = g_new0 (CamelImapResponse, 1);
+ response->folder = store->current_folder;
+ if (response->folder)
+ camel_object_ref (CAMEL_OBJECT (response->folder));
response->untagged = g_ptr_array_new ();
/* Check for untagged data */
@@ -165,51 +166,20 @@ imap_read_response (CamelImapStore *store, CamelException *ex)
if (camel_exception_is_set (ex))
break;
- /* If it starts with a number, we might deal with
- * it ourselves.
- */
- word = imap_next_word (respbuf);
- number = strtoul (word, &p, 10);
- if (p != word && store->current_folder) {
- word = imap_next_word (p);
- if (!g_strcasecmp (word, "EXISTS")) {
- exists = number;
- g_free (respbuf);
- goto next;
- } else if (!g_strcasecmp (word, "EXPUNGE")) {
- if (!expunged) {
- expunged = g_array_new (FALSE, FALSE,
- sizeof (int));
- }
- g_array_append_val (expunged, number);
- g_free (respbuf);
- goto next;
- }
- } else {
- if (!g_strncasecmp (word, "BYE", 3)) {
- /* connection was lost, no more data to fetch */
- store->connected = FALSE;
- g_free (respbuf);
- respbuf = NULL;
- break;
- }
+ if (!g_strncasecmp (respbuf, "* BYE", 5)) {
+ /* Connection was lost, no more data to fetch */
+ store->connected = FALSE;
+ g_free (respbuf);
+ respbuf = NULL;
+ break;
}
g_ptr_array_add (response->untagged, respbuf);
- next:
if (camel_remote_store_recv_line (
CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0)
break;
}
- /* Update the summary */
- if (store->current_folder && (exists > 0 || expunged)) {
- camel_imap_folder_changed (store->current_folder, exists,
- expunged, NULL);
- }
- if (expunged)
- g_array_free (expunged, TRUE);
-
if (!respbuf || camel_exception_is_set (ex)) {
camel_imap_response_free (response);
return NULL;
@@ -372,25 +342,76 @@ imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex)
/**
* camel_imap_response_free:
- * response: a CamelImapResponse:
+ * @response: a CamelImapResponse:
*
- * Frees all of the data in @response.
+ * Frees all of the data in @response and processes any untagged
+ * EXPUNGE and EXISTS responses in it.
**/
void
camel_imap_response_free (CamelImapResponse *response)
{
- int i;
+ int i, number, exists = 0;
+ GArray *expunged = NULL;
+ char *resp, *p;
if (!response)
return;
- for (i = 0; i < response->untagged->len; i++)
- g_free (response->untagged->pdata[i]);
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+
+ if (response->folder) {
+ /* Check if it's something we need to handle. */
+ number = strtoul (resp + 2, &p, 10);
+ if (!g_strcasecmp (p, " EXISTS")) {
+ exists = number;
+ } else if (!g_strcasecmp (p, " EXPUNGE")) {
+ if (!expunged) {
+ expunged = g_array_new (FALSE, FALSE,
+ sizeof (int));
+ }
+ g_array_append_val (expunged, number);
+ }
+ }
+ g_free (resp);
+ }
+
g_ptr_array_free (response->untagged, TRUE);
g_free (response->status);
+
+ if (response->folder) {
+ if (exists > 0 || expunged) {
+ /* Update the summary */
+ camel_imap_folder_changed (response->folder,
+ exists, expunged, NULL);
+ if (expunged)
+ g_array_free (expunged, TRUE);
+ }
+
+ camel_object_unref (CAMEL_OBJECT (response->folder));
+ }
+
g_free (response);
}
/**
+ * camel_imap_response_free:
+ * @response: a CamelImapResponse:
+ *
+ * Frees all of the data in @response without processing any untagged
+ * responses.
+ **/
+void
+camel_imap_response_free_without_processing (CamelImapResponse *response)
+{
+ if (response->folder) {
+ camel_object_unref (CAMEL_OBJECT (response->folder));
+ response->folder = NULL;
+ }
+ camel_imap_response_free (response);
+}
+
+/**
* camel_imap_response_extract:
* @response: the response data returned from camel_imap_command
* @type: the response type to extract
@@ -419,14 +440,11 @@ camel_imap_response_extract (CamelImapResponse *response, const char *type,
if (!g_strncasecmp (resp, type, len))
break;
-
- g_free (response->untagged->pdata[i]);
}
if (i < response->untagged->len) {
resp = response->untagged->pdata[i];
- for (i++; i < response->untagged->len; i++)
- g_free (response->untagged->pdata[i]);
+ g_ptr_array_remove_index (response->untagged, i);
} else {
resp = NULL;
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
@@ -434,9 +452,7 @@ camel_imap_response_extract (CamelImapResponse *response, const char *type,
"%s information"), type);
}
- g_ptr_array_free (response->untagged, TRUE);
- g_free (response->status);
- g_free (response);
+ camel_imap_response_free (response);
return resp;
}
diff --git a/camel/providers/imap/camel-imap-command.h b/camel/providers/imap/camel-imap-command.h
index a7d3c3eae9..9dd31b88d2 100644
--- a/camel/providers/imap/camel-imap-command.h
+++ b/camel/providers/imap/camel-imap-command.h
@@ -37,6 +37,7 @@ extern "C" {
#include <glib.h>
struct _CamelImapResponse {
+ CamelFolder *folder;
GPtrArray *untagged;
char *status;
};
@@ -50,6 +51,7 @@ CamelImapResponse *camel_imap_command_continuation (CamelImapStore *store,
const char *cmdbuf);
void camel_imap_response_free (CamelImapResponse *response);
+void camel_imap_response_free_without_processing(CamelImapResponse *response);
char *camel_imap_response_extract (CamelImapResponse *response,
const char *type,
CamelException *ex);
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 5181b19ed8..d458b1cfb5 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -84,11 +84,6 @@ static void imap_copy_message_to (CamelFolder *source, const char *uid,
static void imap_move_message_to (CamelFolder *source, const char *uid,
CamelFolder *destination, CamelException *ex);
-/* summary info */
-static void imap_update_summary (CamelFolder *folder, int first, int last,
- CamelFolderChangeInfo *changes,
- CamelException *ex);
-
/* searching */
static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex);
static void imap_search_free (CamelFolder *folder, GPtrArray *uids);
@@ -228,8 +223,14 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
} else if (isdigit ((unsigned char)*resp)) {
unsigned long num = strtoul (resp, &resp, 10);
- if (!g_strncasecmp (resp, " EXISTS", 7))
+ if (!g_strncasecmp (resp, " EXISTS", 7)) {
exists = num;
+ /* Remove from the response so nothing
+ * else tries to interpret it.
+ */
+ g_free (response->untagged->pdata[i]);
+ g_ptr_array_remove_index (response->untagged, i--);
+ }
}
}
@@ -266,17 +267,21 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
for (i = 0; i < response->untagged->len; i++) {
resp = response->untagged->pdata[i];
val = strtoul (resp + 2, &resp, 10);
- if (val == count && !g_strncasecmp (resp, " FETCH (", 8))
- break;
- }
+ if (val == 0)
+ continue;
+ if (!g_strcasecmp (resp, " EXISTS")) {
+ /* Another one?? */
+ exists = val;
+ continue;
+ }
+ if (uid != 0 || val != count || g_strncasecmp (resp, " FETCH (", 8) != 0)
+ continue;
- if (i < response->untagged->len) {
fetch_data = parse_fetch_response (imap_folder, resp + 7);
- uid = strtoul (g_datalist_get_data (&fetch_data, "UID"),
- NULL, 10);
+ uid = strtoul (g_datalist_get_data (&fetch_data, "UID"), NULL, 10);
g_datalist_clear (&fetch_data);
}
- camel_imap_response_free (response);
+ camel_imap_response_free_without_processing (response);
info = camel_folder_summary_index (folder->summary, count - 1);
val = strtoul (camel_message_info_uid (info), NULL, 10);
@@ -366,7 +371,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
g_datalist_clear (&fetch_data);
g_ptr_array_remove_index_fast (response->untagged, i--);
}
- camel_imap_response_free (response);
+ camel_imap_response_free_without_processing (response);
}
/* If we find a UID in the summary that doesn't correspond to
@@ -991,12 +996,13 @@ imap_protocol_get_summary_specifier (CamelImapStore *store)
if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
return "UID FLAGS RFC822.SIZE BODY.PEEK[HEADER]";
else
- return "UID FLAGS RFC822.SIZE RFC822.HEADER";
+ return "UID FLAGS RFC822.SIZE BODY.PEEK[0]";
}
static void
-imap_update_summary (CamelFolder *folder, int first, int last,
- CamelFolderChangeInfo *changes, CamelException *ex)
+imap_update_summary (CamelFolder *folder,
+ CamelFolderChangeInfo *changes,
+ CamelException *ex)
{
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
@@ -1004,41 +1010,39 @@ imap_update_summary (CamelFolder *folder, int first, int last,
GPtrArray *headers, *messages;
const char *summary_specifier;
char *p;
- int i, seq, count;
+ int i, seq, first, exists = 0;
CamelMimeMessage *msg;
CamelMessageInfo *mi;
GData *fetch_data;
+ first = camel_folder_summary_count (folder->summary) + 1;
summary_specifier = imap_protocol_get_summary_specifier (store);
- /* We already have the command lock */
- if (first == last) {
- response = camel_imap_command (store, folder, ex,
- "FETCH %d (%s)", first,
- summary_specifier);
- } else {
- response = camel_imap_command (store, folder, ex,
- "FETCH %d:%d (%s)", first,
- last, summary_specifier);
- }
+ /* We already have the command lock */
+ response = camel_imap_command (store, folder, ex, "FETCH %d:* (%s)",
+ first, summary_specifier);
if (!response)
return;
- count = camel_folder_summary_count (folder->summary);
messages = g_ptr_array_new ();
- g_ptr_array_set_size (messages, last - first + 1);
headers = response->untagged;
for (i = 0; i < headers->len; i++) {
p = headers->pdata[i];
if (*p++ != '*' || *p++ != ' ')
continue;
seq = strtoul (p, &p, 10);
- if (!seq || seq < first || seq > last)
+ if (!g_strcasecmp (p, " EXISTS")) {
+ exists = seq;
+ continue;
+ }
+ if (!seq || seq < first)
continue;
if (g_strncasecmp (p, " FETCH (", 8) != 0)
continue;
p += 7;
+ if (seq - first >= messages->len)
+ g_ptr_array_set_size (messages, seq - first + 1);
mi = messages->pdata[seq - first];
fetch_data = parse_fetch_response (imap_folder, p);
@@ -1071,14 +1075,22 @@ imap_update_summary (CamelFolder *folder, int first, int last,
g_datalist_clear (&fetch_data);
}
- camel_imap_response_free (response);
+ camel_imap_response_free_without_processing (response);
for (i = 0; i < messages->len; i++) {
mi = messages->pdata[i];
+ if (!mi) {
+ g_warning ("No information for message %d", i + first);
+ continue;
+ }
camel_folder_summary_add (folder->summary, mi);
camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
}
g_ptr_array_free (messages, TRUE);
+
+ /* Did more mail arrive while we were doing this? */
+ if (exists && exists > camel_folder_summary_count (folder->summary))
+ imap_update_summary (folder, changes, ex);
}
/* Called with the store's command_lock locked */
@@ -1108,7 +1120,7 @@ camel_imap_folder_changed (CamelFolder *folder, int exists,
len = camel_folder_summary_count (folder->summary);
if (exists > len)
- imap_update_summary (folder, len + 1, exists, changes, ex);
+ imap_update_summary (folder, changes, ex);
if (camel_folder_change_info_changed (changes)) {
camel_object_trigger_event (CAMEL_OBJECT (folder),
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index f5dd7ba089..fa7fac480a 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -1109,6 +1109,7 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
if (!subscribed_only || !recursive || top) {
if (!camel_imap_store_check_online (imap_store, ex))
return NULL;
+ online = TRUE;
} else
online = camel_imap_store_check_online (imap_store, NULL);