aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap/camel-imap-folder.c')
-rw-r--r--camel/providers/imap/camel-imap-folder.c360
1 files changed, 142 insertions, 218 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index e3888ec06f..45dad9f6b0 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -64,9 +64,6 @@
#include "camel-stream.h"
#include "string-utils.h"
-#define UID_SET_LIMIT (-1)
-
-
#define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o)))
static CamelDiscoFolderClass *disco_folder_class = NULL;
@@ -229,8 +226,6 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
!g_strcasecmp (folder_name, "INBOX"))
folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
- imap_folder->search = camel_imap_search_new(folder_dir);
-
return folder;
}
@@ -570,14 +565,11 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
g_array_free (removed, TRUE);
}
-/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */
-#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE)
-
/* Find all messages in @folder with flags matching @flags and @mask.
* If no messages match, returns %NULL. Otherwise, returns an array of
* CamelMessageInfo and sets *@set to a message set corresponding the
- * UIDs of the matched messages (up to @UID_SET_LIMIT bytes). The
- * caller must free the infos, the array, and the set string.
+ * UIDs of the matched messages. The caller must free the infos, the
+ * array, and the set string.
*/
static GPtrArray *
get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
@@ -586,12 +578,12 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
CamelMessageInfo *info;
int i, max, range;
GString *gset;
-
+
matches = g_ptr_array_new ();
gset = g_string_new ("");
max = camel_folder_summary_count (folder->summary);
range = -1;
- for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) {
+ for (i = 0; i < max; i++) {
info = camel_folder_summary_index (folder->summary, i);
if (!info)
continue;
@@ -606,7 +598,7 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
}
continue;
}
-
+
g_ptr_array_add (matches, info);
if (range != -1)
continue;
@@ -615,12 +607,11 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
g_string_append_c (gset, ',');
g_string_sprintfa (gset, "%s", camel_message_info_uid (info));
}
-
if (range != -1 && range != max - 1) {
info = matches->pdata[matches->len - 1];
g_string_sprintfa (gset, ":%s", camel_message_info_uid (info));
}
-
+
if (matches->len) {
*set = gset->str;
g_string_free (gset, FALSE);
@@ -666,19 +657,14 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
}
/* Note: Cyrus is broken and will not accept an
- empty-set of flags so... if this is true then we
- want to unset the previously set flags.*/
+ empty-set of flags so... if this is true then we
+ want to unset the previously set flags.*/
unset = !(info->flags & CAMEL_IMAP_SERVER_FLAGS);
/* FIXME: since we don't know the previously set
- flags, if unset is TRUE then just unset all the flags? */
+ flags, if unset is TRUE then just unset all the flags? */
flaglist = imap_create_flag_list (unset ? CAMEL_IMAP_SERVER_FLAGS : info->flags);
- /* Note: get_matching() uses UID_SET_LIMIT to limit
- the size of the uid-set string. We don't have to
- loop here to flush all the matching uids because
- they will be scooped up later by our parent loop (I
- think?). -- Jeff */
matches = get_matching (folder, info->flags & (CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED),
CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED, &set);
camel_folder_summary_info_free (folder->summary, info);
@@ -743,34 +729,28 @@ imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException *
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapResponse *response;
- int uid = 0;
char *set;
+ set = imap_uid_array_to_set (folder->summary, uids);
CAMEL_IMAP_STORE_LOCK (store, command_lock);
-
- while (uid < uids->len) {
- set = imap_uid_array_to_set (folder->summary, uids, uid, UID_SET_LIMIT, &uid);
- response = camel_imap_command (store, folder, ex,
- "UID STORE %s +FLAGS.SILENT \\Deleted",
- set);
- if (response)
- camel_imap_response_free (store, response);
- if (camel_exception_is_set (ex)) {
- CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
- g_free (set);
- return;
- }
-
- if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
- response = camel_imap_command (store, folder, ex,
- "UID EXPUNGE %s", set);
- } else
- response = camel_imap_command (store, folder, ex, "EXPUNGE");
-
- if (response)
- camel_imap_response_free (store, response);
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s +FLAGS.SILENT \\Deleted",
+ set);
+ if (response)
+ camel_imap_response_free (store, response);
+ if (camel_exception_is_set (ex)) {
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ g_free (set);
+ return;
}
+ if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
+ response = camel_imap_command (store, folder, ex,
+ "UID EXPUNGE %s", set);
+ } else
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ if (response)
+ camel_imap_response_free (store, response);
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
}
@@ -794,21 +774,20 @@ static void
imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- GPtrArray *keep_uids, *mark_uids;
CamelImapResponse *response;
- char *result;
+ char *result, *keep_uidset, *mark_uidset;
if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) {
imap_expunge_uids_online (folder, uids, ex);
return;
}
-
+
/* If we don't have UID EXPUNGE we need to avoid expunging any
* of the wrong messages. So we search for deleted messages,
* and any that aren't in our to-expunge list get temporarily
* marked un-deleted.
*/
-
+
CAMEL_IMAP_STORE_LOCK (store, command_lock);
response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED");
if (!response) {
@@ -820,125 +799,100 @@ imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelExceptio
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
return;
}
-
+
+ keep_uidset = mark_uidset = NULL;
if (result[8] == ' ') {
+ GPtrArray *keep_uids, *mark_uids;
char *uid, *lasts = NULL;
unsigned long euid, kuid;
int ei, ki;
-
+
keep_uids = g_ptr_array_new ();
mark_uids = g_ptr_array_new ();
-
+
/* Parse SEARCH response */
for (uid = strtok_r (result + 9, " ", &lasts); uid; uid = strtok_r (NULL, " ", &lasts))
g_ptr_array_add (keep_uids, uid);
qsort (keep_uids->pdata, keep_uids->len,
sizeof (void *), uid_compar);
-
+
/* Fill in "mark_uids", empty out "keep_uids" as needed */
for (ei = ki = 0; ei < uids->len; ei++) {
euid = strtoul (uids->pdata[ei], NULL, 10);
-
+
for (kuid = 0; ki < keep_uids->len; ki++) {
kuid = strtoul (keep_uids->pdata[ki], NULL, 10);
-
+
if (kuid >= euid)
break;
}
-
+
if (euid == kuid)
g_ptr_array_remove_index (keep_uids, ki);
else
g_ptr_array_add (mark_uids, uids->pdata[ei]);
}
+
+ if (keep_uids->len)
+ keep_uidset = imap_uid_array_to_set (folder->summary, keep_uids);
+ g_ptr_array_free (keep_uids, TRUE);
+
+ if (mark_uids->len)
+ mark_uidset = imap_uid_array_to_set (folder->summary, mark_uids);
+ g_ptr_array_free (mark_uids, TRUE);
} else {
/* Empty SEARCH result, meaning nothing is marked deleted
* on server.
*/
-
- keep_uids = NULL;
- mark_uids = NULL;
+ mark_uidset = imap_uid_array_to_set (folder->summary, uids);
}
-
g_free (result);
-
+
/* Unmark messages to be kept */
- if (keep_uids) {
- char *uidset;
- int uid = 0;
-
- while (uid < keep_uids->len) {
- uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid);
-
- response = camel_imap_command (store, folder, ex,
- "UID STORE %s -FLAGS.SILENT \\Deleted",
- uidset);
-
- g_free (uidset);
-
- if (!response) {
- g_ptr_array_free (keep_uids, TRUE);
- g_ptr_array_free (mark_uids, TRUE);
- CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
- return;
- }
- camel_imap_response_free (store, response);
+ if (keep_uidset) {
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s -FLAGS.SILENT \\Deleted",
+ keep_uidset);
+ if (!response) {
+ g_free (keep_uidset);
+ g_free (mark_uidset);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
}
+ camel_imap_response_free (store, response);
}
-
+
/* Mark any messages that still need to be marked */
- if (mark_uids) {
- char *uidset;
- int uid = 0;
-
- while (uid < mark_uids->len) {
- uidset = imap_uid_array_to_set (folder->summary, mark_uids, uid, UID_SET_LIMIT, &uid);
-
- response = camel_imap_command (store, folder, ex,
- "UID STORE %s +FLAGS.SILENT \\Deleted",
- uidset);
-
- g_free (uidset);
-
- if (!response) {
- g_ptr_array_free (keep_uids, TRUE);
- g_ptr_array_free (mark_uids, TRUE);
- CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
- return;
- }
- camel_imap_response_free (store, response);
+ if (mark_uidset) {
+ response = camel_imap_command (store, folder, ex,
+ "UID STORE %s +FLAGS.SILENT \\Deleted",
+ mark_uidset);
+ g_free (mark_uidset);
+ if (!response) {
+ g_free (keep_uidset);
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ return;
}
-
- g_ptr_array_free (mark_uids, TRUE);
+ camel_imap_response_free (store, response);
}
-
+
/* Do the actual expunging */
response = camel_imap_command (store, folder, ex, "EXPUNGE");
if (response)
camel_imap_response_free (store, response);
-
+
/* And fix the remaining messages if we mangled them */
- if (keep_uids) {
- char *uidset;
- int uid = 0;
-
- while (uid < keep_uids->len) {
- uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid);
-
- /* Don't pass ex if it's already been set */
- response = camel_imap_command (store, folder,
- camel_exception_is_set (ex) ? NULL : ex,
- "UID STORE %s +FLAGS.SILENT \\Deleted",
- uidset);
-
- g_free (uidset);
- if (response)
- camel_imap_response_free (store, response);
- }
-
- g_ptr_array_free (keep_uids, TRUE);
+ if (keep_uidset) {
+ /* Don't pass ex if it's already been set */
+ response = camel_imap_command (store, folder,
+ camel_exception_is_set (ex) ? NULL : ex,
+ "UID STORE %s +FLAGS.SILENT \\Deleted",
+ keep_uidset);
+ g_free (keep_uidset);
+ if (response)
+ camel_imap_response_free (store, response);
}
-
+
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
}
@@ -1232,22 +1186,16 @@ do_copy (CamelFolder *source, GPtrArray *uids,
{
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
- char *uidset;
- int uid = 0;
-
- while (uid < uids->len && !camel_exception_is_set (ex)) {
- uidset = imap_uid_array_to_set (source->summary, uids, uid, UID_SET_LIMIT, &uid);
-
- response = camel_imap_command (store, source, ex, "UID COPY %s %F",
- uidset, destination->full_name);
-
- g_free (uidset);
-
- if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS))
- handle_copyuid (response, source, destination);
-
- camel_imap_response_free (store, response);
- }
+ char *set;
+
+ set = imap_uid_array_to_set (source->summary, uids);
+ response = camel_imap_command (store, source, ex, "UID COPY %s %F",
+ set, destination->full_name);
+ if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS))
+ handle_copyuid (response, source, destination);
+
+ camel_imap_response_free (store, response);
+ g_free (set);
}
static void
@@ -1366,6 +1314,9 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc
command channel too */
CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+ if (!imap_folder->search)
+ imap_folder->search = camel_imap_search_new ();
+
camel_folder_search_set_folder (imap_folder->search, folder);
summary = camel_folder_get_summary(folder);
camel_folder_search_set_summary(imap_folder->search, summary);
@@ -1402,6 +1353,9 @@ imap_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids
CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
+ if (imap_folder->search == NULL)
+ imap_folder->search = camel_imap_search_new();
+
camel_folder_search_set_folder(imap_folder->search, folder);
camel_folder_search_set_summary(imap_folder->search, summary);
@@ -1457,7 +1411,6 @@ get_content (CamelImapFolder *imap_folder, const char *uid,
body_mp = camel_multipart_new ();
camel_data_wrapper_set_mime_type_field (
CAMEL_DATA_WRAPPER (body_mp), ci->type);
-
camel_multipart_set_boundary (body_mp, NULL);
speclen = strlen (part_spec);
@@ -1497,7 +1450,7 @@ get_content (CamelImapFolder *imap_folder, const char *uid,
camel_object_unref (CAMEL_OBJECT (content));
camel_multipart_add_part (body_mp, part);
camel_object_unref (CAMEL_OBJECT (part));
-
+
ci = ci->next;
}
g_free (child_spec);
@@ -1805,13 +1758,13 @@ imap_update_summary (CamelFolder *folder, int exists,
g_free (resp);
if (!data)
continue;
-
+
seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
if (seq < first) {
g_datalist_clear (&data);
continue;
}
-
+
if (g_datalist_get_data (&data, "FLAGS"))
got += IMAP_PRETEND_SIZEOF_FLAGS;
if (g_datalist_get_data (&data, "RFC822.SIZE"))
@@ -1819,22 +1772,22 @@ imap_update_summary (CamelFolder *folder, int exists,
stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
if (stream) {
got += IMAP_PRETEND_SIZEOF_HEADERS;
-
+
/* Use the stream now so we don't tie up many
* many fds if we're fetching many many messages.
*/
add_message_from_data (folder, messages, first, data);
g_datalist_set_data (&data, "BODY_PART_STREAM", NULL);
}
-
+
camel_operation_progress (NULL, got * 100 / size);
g_ptr_array_add (fetch_data, data);
}
camel_operation_end (NULL);
-
+
if (type == CAMEL_IMAP_RESPONSE_ERROR)
goto lose;
-
+
/* Figure out which headers we still need to fetch. */
needheaders = g_ptr_array_new ();
size = got = 0;
@@ -1842,67 +1795,55 @@ imap_update_summary (CamelFolder *folder, int exists,
data = fetch_data->pdata[i];
if (g_datalist_get_data (&data, "BODY_PART_LEN"))
continue;
-
+
uid = g_datalist_get_data (&data, "UID");
if (uid) {
g_ptr_array_add (needheaders, uid);
size += IMAP_PRETEND_SIZEOF_HEADERS;
}
}
-
+
/* And fetch them */
if (needheaders->len) {
- char *uidset;
- int uid = 0;
-
- qsort (needheaders->pdata, needheaders->len,
- sizeof (void *), uid_compar);
-
+ char *set;
+
+ /* FIXME: sort needheaders */
+ set = imap_uid_array_to_set (folder->summary, needheaders);
+ g_ptr_array_free (needheaders, TRUE);
+ if (!camel_imap_command_start (store, folder, ex,
+ "UID FETCH %s BODY.PEEK[%s]",
+ set, header_spec)) {
+ g_free (set);
+ goto lose;
+ }
+ g_free (set);
+
camel_operation_start (NULL, _("Fetching summary information for new messages"));
-
- while (uid < needheaders->len) {
- uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid);
- if (!camel_imap_command_start (store, folder, ex,
- "UID FETCH %s BODY.PEEK[%s]",
- uidset, header_spec)) {
- g_ptr_array_free (needheaders, TRUE);
- camel_operation_end (NULL);
- g_free (uidset);
- goto lose;
- }
- g_free (uidset);
-
- while ((type = camel_imap_command_response (store, &resp, ex))
- == CAMEL_IMAP_RESPONSE_UNTAGGED) {
- data = parse_fetch_response (imap_folder, resp);
- g_free (resp);
- if (!data)
- continue;
-
- stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
- if (stream) {
- add_message_from_data (folder, messages, first, data);
- got += IMAP_PRETEND_SIZEOF_HEADERS;
- camel_operation_progress (NULL, got * 100 / size);
- }
- g_datalist_clear (&data);
- }
-
- if (type == CAMEL_IMAP_RESPONSE_ERROR) {
- g_ptr_array_free (needheaders, TRUE);
- camel_operation_end (NULL);
- goto lose;
+ while ((type = camel_imap_command_response (store, &resp, ex))
+ == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+ data = parse_fetch_response (imap_folder, resp);
+ g_free (resp);
+ if (!data)
+ continue;
+
+ stream = g_datalist_get_data (&data, "BODY_PART_STREAM");
+ if (stream) {
+ add_message_from_data (folder, messages, first, data);
+ got += IMAP_PRETEND_SIZEOF_HEADERS;
+ camel_operation_progress (NULL, got * 100 / size);
}
+ g_datalist_clear (&data);
}
-
- g_ptr_array_free (needheaders, TRUE);
camel_operation_end (NULL);
+
+ if (type == CAMEL_IMAP_RESPONSE_ERROR)
+ goto lose;
}
-
+
/* Now finish up summary entries (fix UIDs, set flags and size) */
for (i = 0; i < fetch_data->len; i++) {
data = fetch_data->pdata[i];
-
+
seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE"));
if (seq >= first + messages->len) {
g_datalist_clear (&data);
@@ -1951,11 +1892,11 @@ imap_update_summary (CamelFolder *folder, int exists,
size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE"));
if (size)
mi->size = size;
-
+
g_datalist_clear (&data);
}
g_ptr_array_free (fetch_data, TRUE);
-
+
/* And add the entries to the summary, etc. */
for (i = 0; i < messages->len; i++) {
mi = messages->pdata[i];
@@ -1965,30 +1906,13 @@ imap_update_summary (CamelFolder *folder, int exists,
}
camel_folder_summary_add (folder->summary, mi);
camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
-
+
if ((mi->flags & CAMEL_IMAP_MESSAGE_RECENT))
camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi));
}
g_ptr_array_free (messages, TRUE);
-
- /* Kludge around Microsoft Exchange 5.5 IMAP - See bug #5348 for details */
- if (camel_folder_summary_count (folder->summary) != exists) {
- CamelImapStore *imap_store = (CamelImapStore *) folder->parent_store;
- CamelImapResponse *response;
-
- /* forget the currently selected folder */
- if (imap_store->current_folder) {
- camel_object_unref (CAMEL_OBJECT (imap_store->current_folder));
- imap_store->current_folder = NULL;
- }
-
- /* now re-select it and process the EXISTS response */
- response = camel_imap_command (imap_store, folder, ex, NULL);
- camel_imap_response_free (imap_store, response);
- }
-
return;
-
+
lose:
if (fetch_data) {
for (i = 0; i < fetch_data->len; i++) {
@@ -2097,7 +2021,7 @@ camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid,
CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock);
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
return stream;
- }
+ }
if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) {
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,