aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers')
-rw-r--r--camel/providers/imap/camel-imap-folder.c245
-rw-r--r--camel/providers/imap/camel-imap-utils.c34
-rw-r--r--camel/providers/imap/camel-imap-utils.h2
3 files changed, 171 insertions, 110 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index 714e245643..6da174fa00 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -64,6 +64,9 @@
#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;
@@ -567,11 +570,14 @@ 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. The caller must free the infos, the
- * array, and the set string.
+ * UIDs of the matched messages (up to @UID_SET_LIMIT bytes). The
+ * caller must free the infos, the array, and the set string.
*/
static GPtrArray *
get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
@@ -580,12 +586,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; i++) {
+ for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) {
info = camel_folder_summary_index (folder->summary, i);
if (!info)
continue;
@@ -600,7 +606,7 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set)
}
continue;
}
-
+
g_ptr_array_add (matches, info);
if (range != -1)
continue;
@@ -609,11 +615,12 @@ 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);
@@ -659,14 +666,19 @@ 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);
@@ -731,29 +743,32 @@ 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);
- 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)) {
+ while (uid < uids->len) {
+ set = imap_uid_array_to_set (folder->summary, uids, uid, UID_SET_LIMIT, &uid);
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ 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);
- 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);
}
static int
@@ -776,20 +791,21 @@ 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, *keep_uidset, *mark_uidset;
+ char *result;
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) {
@@ -801,100 +817,125 @@ 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.
*/
- mark_uidset = imap_uid_array_to_set (folder->summary, uids);
+
+ keep_uids = NULL;
+ mark_uids = NULL;
}
+
g_free (result);
-
+
/* Unmark messages to be kept */
- 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;
+ 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);
}
- camel_imap_response_free (store, response);
}
-
+
/* Mark any messages that still need to be marked */
- 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;
+ 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);
}
- camel_imap_response_free (store, response);
+
+ g_ptr_array_free (mark_uids, TRUE);
}
-
+
/* 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_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);
+ 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);
}
-
+
CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
}
@@ -1188,16 +1229,22 @@ do_copy (CamelFolder *source, GPtrArray *uids,
{
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *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);
+ 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);
+ }
}
static void
@@ -1802,18 +1849,20 @@ imap_update_summary (CamelFolder *folder, int exists,
/* And fetch them */
if (needheaders->len) {
- char *set;
+ char *uidset;
+ int uid = 0;
/* FIXME: sort needheaders */
- set = imap_uid_array_to_set (folder->summary, needheaders);
+ /* FIXME: modify code to allow for uidset limit */
+ uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, -1, &uid);
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);
+ uidset, header_spec)) {
+ g_free (uidset);
goto lose;
}
- g_free (set);
+ g_free (uidset);
camel_operation_start (NULL, _("Fetching summary information for new messages"));
while ((type = camel_imap_command_response (store, &resp, ex))
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index d5466bf9ac..7d2073142b 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -648,44 +648,54 @@ get_summary_uid_numeric (CamelFolderSummary *summary, int index)
return uid;
}
+/* 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)
+
/**
* imap_uid_array_to_set:
* @summary: summary for the folder the UIDs come from
* @uids: a (sorted) array of UIDs
+ * @uid: uid index to start at
+ * @maxlen: max length of the set string (or -1 for infinite)
+ * @lastuid: index offset of the last uid used
+ *
+ * Creates an IMAP "set" up to @maxlen bytes long, covering the listed
+ * UIDs starting at index @uid and not covering any UIDs that are in
+ * @summary but not in @uids. It doesn't actually require that all (or
+ * any) of the UIDs be in @summary.
*
- * Creates an IMAP "set" covering the listed UIDs and not covering
- * any UIDs that are in @summary but not in @uids. It doesn't
- * actually require that all (or any) of the UIDs be in @summary.
+ * After calling, @lastuid will be set the index of the first uid
+ * *not* included in the returned set string.
*
* Return value: the set, which the caller must free with g_free()
**/
char *
-imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids)
+imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid)
{
- int ui, si, scount;
unsigned long last_uid, next_summary_uid, this_uid;
gboolean range = FALSE;
+ int si, scount;
GString *gset;
char *set;
- g_return_val_if_fail (uids->len > 0, NULL);
+ g_return_val_if_fail (uids->len > uid, NULL);
- gset = g_string_new (uids->pdata[0]);
- last_uid = strtoul (uids->pdata[0], NULL, 10);
+ gset = g_string_new (uids->pdata[uid]);
+ last_uid = strtoul (uids->pdata[uid], NULL, 10);
next_summary_uid = 0;
scount = camel_folder_summary_count (summary);
- for (ui = 1, si = 0; ui < uids->len; ui++) {
+ for (uid++, si = 0; uid < uids->len && !UID_SET_FULL (gset->len, maxlen); uid++) {
/* Find the next UID in the summary after the one we
* just wrote out.
*/
- for (; last_uid >= next_summary_uid && si < scount; si++)
+ for ( ; last_uid >= next_summary_uid && si < scount; si++)
next_summary_uid = get_summary_uid_numeric (summary, si);
if (last_uid >= next_summary_uid)
next_summary_uid = (unsigned long) -1;
/* Now get the next UID from @uids */
- this_uid = strtoul (uids->pdata[ui], NULL, 10);
+ this_uid = strtoul (uids->pdata[uid], NULL, 10);
if (this_uid == next_summary_uid || this_uid == last_uid + 1)
range = TRUE;
else {
@@ -702,6 +712,8 @@ imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids)
if (range)
g_string_sprintfa (gset, ":%lu", last_uid);
+ *lastuid = uid;
+
set = gset->str;
g_string_free (gset, FALSE);
diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h
index 8f61fb99d9..f64d56743a 100644
--- a/camel/providers/imap/camel-imap-utils.h
+++ b/camel/providers/imap/camel-imap-utils.h
@@ -65,7 +65,7 @@ char *imap_quote_string (const char *str);
void imap_skip_list (char **str_p);
-char *imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids);
+char *imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid);
GPtrArray *imap_uid_set_to_array (CamelFolderSummary *summary, const char *uids);
void imap_uid_array_free (GPtrArray *arr);