aboutsummaryrefslogtreecommitdiffstats
path: root/imap.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2000-04-07 10:07:06 +0000
committerEric S. Raymond <esr@thyrsus.com>2000-04-07 10:07:06 +0000
commit32cf48a357ed372b9135aff60ea794b3db61bae6 (patch)
tree472bed7187335dc566f224b74ff8d9a157fb2025 /imap.c
parent27fda363d5f0398360b6aaf9bbbf4dbb6bf7d6ec (diff)
downloadfetchmail-32cf48a357ed372b9135aff60ea794b3db61bae6.tar.gz
fetchmail-32cf48a357ed372b9135aff60ea794b3db61bae6.tar.bz2
fetchmail-32cf48a357ed372b9135aff60ea794b3db61bae6.zip
speed improvement by usingh SEARCH UNSEEN.
svn path=/trunk/; revision=2863
Diffstat (limited to 'imap.c')
-rw-r--r--imap.c225
1 files changed, 70 insertions, 155 deletions
diff --git a/imap.c b/imap.c
index 7f039f51..3e534cf3 100644
--- a/imap.c
+++ b/imap.c
@@ -62,31 +62,17 @@ extern char *strstr(); /* needed on sysV68 R3V7.1. */
#define IMAP4 0 /* IMAP4 rev 0, RFC1730 */
#define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
-static int count, seen, unseen, deletions, imap_version, preauth;
-#ifdef USE_SEARCH
-static int unseen_count;
-#endif /* USE_SEARCH */
+static int count, unseen, deletions, imap_version, preauth;
static int expunged, expunge_period, saved_timeout;
static flag do_idle;
static char capabilities[MSGBUFSIZE+1];
-
-#ifdef USE_SEARCH
-/*
- * unseen_count is a dynamic array that holds the sequence number
- * of unseen_messages. It is created whenever a SEARCH UNSEEN response
- * is returned and deleted at logout time.
- * Data are terminated by 0 in unseen_sequence since sequence numbers
- * are between 1 and 2^32.
- */
-static unsigned int* unseen_sequence;
-#endif /* USE_SEARCH */
+static unsigned int *unseen_messages;
int imap_ok(int sock, char *argbuf)
/* parse command response */
{
- char buf [MSGBUFSIZE+1];
+ char buf[MSGBUFSIZE+1];
- seen = 0;
do {
int ok;
char *cp;
@@ -102,7 +88,7 @@ int imap_ok(int sock, char *argbuf)
/* interpret untagged status responses */
if (strstr(buf, "* CAPABILITY"))
strncpy(capabilities, buf + 12, sizeof(capabilities));
- if (strstr(buf, "EXISTS"))
+ else if (strstr(buf, "EXISTS"))
{
count = atoi(buf+2);
/*
@@ -123,78 +109,8 @@ int imap_ok(int sock, char *argbuf)
stage = STAGE_FETCH;
}
}
- if (strstr(buf, "UNSEEN"))
- {
- char *cp;
-
- /*
- * Handle both "* 42 UNSEEN" (if that ever happens) and
- * "* OK [UNSEEN 42] 42". Note that what this gets us is
- * a minimum index, not a count.
- */
- unseen = 0;
- for (cp = buf; *cp && !isdigit(*cp); cp++)
- continue;
- unseen = atoi(cp);
- }
- if (strstr(buf, "FLAGS"))
- seen = (strstr(buf, "SEEN") != (char *)NULL);
- if (strstr(buf, "PREAUTH"))
+ else if (strstr(buf, "PREAUTH"))
preauth = TRUE;
-#ifdef USE_SEARCH
- /*
- * The response to SEARCH UNSEEN looks like:
- * * SEARCH list of sequence numbers
- * It means stuffing unseen_sequence and eating white space in between.
- */
- if (strstr(buf, "* SEARCH"))
- {
- char *cp = strstr(buf, "SEARCH") + 6; /* Start after SEARCH */
- char *endofnumber = NULL;
-
- /* unseen_sequence already exists. Discard it for a new use */
- if (unseen_sequence)
- free(unseen_sequence);
-
- /*
- * We do unseen_sequence memory allocation here. Chances
- * are it will be grossly oversized, but there is no way
- * to size it correctly in one pass without relying on
- * the flaky RECENT response. Which is exactly why
- * we're using SEARCH UNSEEN. Fill unseen_sequence with
- * zero because 0 means end of data.
- */
- unseen_sequence = xmalloc(count * sizeof(unsigned int));
- memset(unseen_sequence, 0, count * sizeof(unsigned int));
- unseen_count = 0;
-
- while (*cp)
- {
- /* White space */
- while (*cp && isspace(*cp)) cp++;
- /* Number is between 1 and 2^32 included so unsigned int is enough. */
- if (*cp)
- {
- /*
- * To avoid a buffer overflow. That count would
- * be less than unseen_count is not supposed to
- * happen, but you never know.
- */
- if (unseen_count >= count)
- break;
- unseen_sequence[unseen_count++] = (unsigned int)strtol(cp, &endofnumber, 10);
-
- if (outlevel >= O_DEBUG)
- report(stdout, _("%u is unseen\n"), unseen_sequence[unseen_count - 1]);
-
- cp = endofnumber;
- }
- }
-
- if (unseen_sequence[0] > 0 && unseen_count > 0)
- unseen = unseen_sequence[0];
- }
-#endif /* USE_SEARCH */
} while
(tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
@@ -1118,6 +1034,7 @@ static int internal_expunge(int sock)
return(ok);
expunged += deletions;
+ unseen -= deletions;
deletions = 0;
#ifdef IMAP_UID /* not used */
@@ -1134,9 +1051,10 @@ static int imap_getrange(int sock,
/* get range of messages to be fetched */
{
int ok;
+ char buf[MSGBUFSIZE+1], *cp;
/* find out how many messages are waiting */
- *bytes = unseen = -1;
+ *bytes = -1;
if (pass > 1)
{
@@ -1164,28 +1082,13 @@ static int imap_getrange(int sock,
else if (count == -1) /* no EXISTS response to NOOP/IDLE */
{
count = 0;
- unseen = -1;
}
}
else
{
-#ifdef USE_SEARCH
ok = gen_transact(sock,
check_only ? "EXAMINE \"%s\"" : "SELECT \"%s\"",
folder ? folder : "INBOX");
-#else
- if (check_only) {
- ok = gen_transact(sock, "EXAMINE \"%s\"", folder? folder: "INBOX");
- } else {
- ok = gen_transact(sock, "SELECT \"%s\"", folder? folder: "INBOX");
- /*
- * SEARCH UNSEEN will modify the static unseen variable.
- * It is a much better way than RECENT to determine UNSEEN
- * messages.
- */
- ok = gen_transact(sock, "SEARCH UNSEEN");
- }
-#endif /* USE_SEARCH */
if (ok != 0)
{
report(stderr, _("mailbox selection failed\n"));
@@ -1195,30 +1098,55 @@ static int imap_getrange(int sock,
*countp = count;
- /*
- * Note: because IMAP has an is_old method, this number is used
- * only for the "X messages (Y unseen)" notification. Accordingly
- * it doesn't matter much that it can be wrong (e.g. if we see an
- * UNSEEN response but not all messages above the first UNSEEN one
- * are likewise).
- *
- * We used to fall back to using the value from the last RECENT
- * response here. But RECENT is not really a good indication of
- * recent messages, because it is ill-defined, e.g. if several
- * connections are made to the folder, messages might appear as
- * recent to some and not to others. Using SEARCH UNSEEN provides
- * us with the exact number of unseen messages.
- */
-#ifndef USE_SEARCH
- if (unseen >= 0)
- *newp = count - unseen + 1;
-#else
- if (unseen >= 0 && unseen_count > 0)
- *newp = unseen_count;
-#endif /* USE_SEARCH */
- else
- *newp = -1; /* should never happen */
+ /* OK, now get a count of unseen messages and their indices */
+ if (unseen_messages)
+ free(unseen_messages);
+ unseen_messages = xmalloc(count * sizeof(unsigned int));
+ memset(unseen_messages, 0, count * sizeof(unsigned int));
+ unseen = 0;
+
+ gen_send(sock, "SEARCH UNSEEN");
+ do {
+ ok = gen_recv(sock, buf, sizeof(buf));
+ if (ok != 0)
+ {
+ report(stderr, _("search for unseen messages failed\n"));
+ return(PS_PROTOCOL);
+ }
+ else if ((cp = strstr(buf, "* SEARCH")))
+ {
+ char *ep;
+
+ cp += 8; /* skip "* SEARCH" */
+
+ while (*cp && unseen < count)
+ {
+ /* skip whitespace */
+ while (*cp && isspace(*cp))
+ cp++;
+ if (*cp)
+ {
+ /*
+ * Message numbers are between 1 and 2^32 inclusive,
+ * so unsigned int is large enough.
+ */
+ unseen_messages[unseen]=(unsigned int)strtol(cp,&ep,10);
+
+ if (outlevel >= O_DEBUG)
+ report(stdout,
+ _("%u is unseen\n"),
+ unseen_messages[unseen]);
+
+ unseen++;
+ cp = ep;
+ }
+ }
+ }
+ } while
+ (tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
+
+ *newp = unseen;
expunged = 0;
return(PS_SUCCESS);
@@ -1285,35 +1213,22 @@ static int imap_getsizes(int sock, int count, int *sizes)
static int imap_is_old(int sock, struct query *ctl, int number)
/* is the given message old? */
{
-#ifdef USE_SEARCH
- int ok;
-#else
- int ok, i;
-#endif /* USE_SEARCH */
+ flag seen = TRUE;
+ int i;
- /* expunges change the fetch numbers */
- number -= expunged;
+ /*
+ * Expunges change the fetch numbers, but unseen_messages contains
+ * indices from before any expungees were done. So neither the
+ * argument nor the values in message_sequence need to be decremented.
+ */
-#ifdef USE_SEARCH
- if (unseen_count > 0)
- {
- /* !unseen_count[i] means end of data - redundant with unseen_count */
- for (i = 0; i < unseen_count && 0 < unseen_sequence[i]; i++)
+ seen = TRUE;
+ for (i = 0; i < unseen; i++)
+ if (unseen_messages[i] == number)
{
- unseen_sequence[i] -= expunged; /* expunge adjustment */
- if (unseen_sequence[i] == number) {
- seen = FALSE; /* message in unseen_sequence */
- break;
- }
- else
- seen = TRUE;
+ seen = FALSE;
+ break;
}
- }
- else
- /* Fall back to FETCH FLAGS */
-#endif /* USE_SEARCH */
- if ((ok = gen_transact(sock, "FETCH %d FLAGS", number)) != 0)
- return(PS_ERROR);
return(seen);
}
@@ -1518,8 +1433,8 @@ static int imap_logout(int sock, struct query *ctl)
#ifdef USE_SEARCH
/* Memory clean-up */
- if (unseen_sequence)
- free(unseen_sequence);
+ if (unseen_messages)
+ free(unseen_messages);
#endif /* USE_SEARCH */
return(gen_transact(sock, "LOGOUT"));