aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog4
-rw-r--r--camel/providers/imap4/camel-imap4-folder.c206
2 files changed, 148 insertions, 62 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 6698923e6a..d49962db6c 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,9 @@
2004-06-17 Jeffrey Stedfast <fejj@ximian.com>
+ * providers/imap4/camel-imap4-folder.c (imap4_get_uid_set): Fixed
+ to work properly. It was getting ranges wrong before sometimes
+ which was making me lose mail! Ugh.
+
Thanks to Christian Kellner for pointing out these bugs (and
submitting the original patch for service_setv)
diff --git a/camel/providers/imap4/camel-imap4-folder.c b/camel/providers/imap4/camel-imap4-folder.c
index fb47d3f994..c5b94af89d 100644
--- a/camel/providers/imap4/camel-imap4-folder.c
+++ b/camel/providers/imap4/camel-imap4-folder.c
@@ -313,82 +313,164 @@ static struct {
{ "\\Seen", CAMEL_MESSAGE_SEEN },
};
-static int
-imap4_get_uid_set (CamelIMAP4Engine *engine, CamelFolderSummary *summary, GPtrArray *infos, int cur, size_t linelen, char **set)
+struct _uidset_range {
+ struct _uidset_range *next;
+ guint32 first, last;
+ uint8_t buflen;
+ char buf[24];
+};
+
+struct _uidset {
+ CamelFolderSummary *summary;
+ struct _uidset_range *ranges;
+ struct _uidset_range *tail;
+ size_t maxlen, setlen;
+};
+
+static void
+uidset_range_free (struct _uidset_range *range)
{
- CamelMessageInfo *info;
- guint32 this, prev, next;
- gboolean range = FALSE;
- GString *uidset;
- int scount, i;
- size_t len;
-
- if (engine->maxlentype == CAMEL_IMAP4_ENGINE_MAXLEN_LINE)
- len = engine->maxlen - linelen;
- else
- len = engine->maxlen;
-
- i = cur + 1;
- info = (CamelMessageInfo *) infos->pdata[cur];
- fflush (stdout);
- uidset = g_string_new ("");
- g_string_append (uidset, camel_message_info_uid (info));
-
- if (!(i < infos->len))
- goto done;
+ struct _uidset_range *next;
- scount = summary->messages->len;
-
- /* init this info */
- for (this = 0; this < scount; this++) {
- if (info == summary->messages->pdata[this])
- break;
+ while (range != NULL) {
+ next = range->next;
+ g_free (range);
+ range = next;
}
-
- /* init next info */
- info = (CamelMessageInfo *) infos->pdata[i];
- for (next = this; next < scount; next++) {
- if (info == summary->messages->pdata[next])
+}
+
+static void
+uidset_init (struct _uidset *uidset, CamelFolderSummary *summary, size_t maxlen)
+{
+ uidset->ranges = g_new (struct _uidset_range, 1);
+ uidset->ranges->next = NULL;
+ uidset->ranges->buflen = 0;
+ uidset->ranges->first = 0;
+ uidset->ranges->last = 0;
+
+ uidset->tail = uidset->ranges;
+ uidset->summary = summary;
+ uidset->maxlen = maxlen;
+ uidset->setlen = 0;
+}
+
+/* returns: -1 on full-and-not-added, 0 on added-and-not-full or 1 on added-and-full */
+static int
+uidset_add (struct _uidset *uidset, CamelMessageInfo *info)
+{
+ GPtrArray *messages = uidset->summary->messages;
+ struct _uidset_range *node, *tail = uidset->tail;
+ const char *iuid = camel_message_info_uid (info);
+ size_t uidlen, len;
+ guint32 index;
+ char *colon;
+
+ for (index = tail->last + 1; index < messages->len; index++) {
+ if (info == messages->pdata[index])
break;
}
- for ( ; i < infos->len && uidset->len < len; i++) {
- prev = this;
- this = next;
-
- if (i + 1 < infos->len) {
- info = infos->pdata[i + 1];
- for (next = this; next < scount; next++) {
- if (info == summary->messages->pdata[next])
- break;
- }
- } else {
- next = scount;
- }
-
- if (this == (next - 1) || this == (prev + 1)) {
- range = TRUE;
+ g_assert (index < messages->len);
+
+ uidlen = strlen (iuid);
+
+ if (tail->buflen == 0) {
+ /* first add */
+ tail->first = tail->last = index;
+ strcpy (tail->buf, iuid);
+ uidset->setlen = uidlen;
+ tail->buflen = uidlen;
+ } else if (index == (tail->last + 1)) {
+ /* add to last range */
+ if (tail->last == tail->first) {
+ /* make sure we've got enough room to add this one... */
+ if ((uidset->setlen + uidlen + 1) > uidset->maxlen)
+ return -1;
+
+ tail->buf[tail->buflen++] = ':';
+ uidset->setlen++;
} else {
- if (range) {
- info = (CamelMessageInfo *) summary->messages->pdata[prev];
- g_string_append_printf (uidset, ":%s", camel_message_info_uid (info));
- range = FALSE;
- }
+ colon = strchr (tail->buf, ':') + 1;
- info = infos->pdata[i];
- g_string_append_printf (uidset, ",%s", camel_message_info_uid (info));
+ len = strlen (colon);
+ uidset->setlen -= len;
+ tail->buflen -= len;
}
+
+ strcpy (tail->buf + tail->buflen, iuid);
+ uidset->setlen += uidlen;
+ tail->buflen += uidlen;
+
+ tail->last = index;
+ } else if ((uidset->setlen + uidlen + 1) < uidset->maxlen) {
+ /* the beginning of a new range */
+ tail->next = node = g_new (struct _uidset_range, 1);
+ node->first = node->last = index;
+ strcpy (node->buf, iuid);
+ uidset->setlen += uidlen + 1;
+ node->buflen = uidlen;
+ uidset->tail = node;
+ node->next = NULL;
+ } else {
+ /* can't add this one... */
+ return -1;
+ }
+
+ fprintf (stderr, "added uid %s to uidset (summary index = %u)\n", iuid, index);
+
+ if (uidset->setlen < uidset->maxlen)
+ return 0;
+
+ return 1;
+}
+
+static char *
+uidset_to_string (struct _uidset *uidset)
+{
+ struct _uidset_range *range;
+ GString *string;
+ char *str;
+
+ string = g_string_new ("");
+
+ range = uidset->ranges;
+ while (range != NULL) {
+ g_string_append (string, range->buf);
+ range = range->next;
+ if (range)
+ g_string_append_c (string, ',');
}
- if (range) {
- info = (CamelMessageInfo *) summary->messages->pdata[this];
- g_string_append_printf (uidset, ":%s", camel_message_info_uid (info));
+ str = string->str;
+ g_string_free (string, FALSE);
+
+ return str;
+}
+
+static int
+imap4_get_uid_set (CamelIMAP4Engine *engine, CamelFolderSummary *summary, GPtrArray *infos, int cur, size_t linelen, char **set)
+{
+ struct _uidset uidset;
+ size_t maxlen;
+ int rv = 0;
+ int i;
+
+ if (engine->maxlentype == CAMEL_IMAP4_ENGINE_MAXLEN_LINE)
+ maxlen = engine->maxlen - linelen;
+ else
+ maxlen = engine->maxlen;
+
+ uidset_init (&uidset, summary, maxlen);
+
+ for (i = cur; i < infos->len && rv != 1; i++) {
+ if ((rv = uidset_add (&uidset, infos->pdata[i])) == -1)
+ break;
}
- done:
+ if (i > cur)
+ *set = uidset_to_string (&uidset);
- *set = uidset->str;
- g_string_free (uidset, FALSE);
+ uidset_range_free (uidset.ranges);
return (i - cur);
}