diff options
Diffstat (limited to 'camel/providers/imap')
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 120 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-command.h | 2 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 78 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 1 |
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); |