diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2000-04-07 10:07:06 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2000-04-07 10:07:06 +0000 |
commit | 32cf48a357ed372b9135aff60ea794b3db61bae6 (patch) | |
tree | 472bed7187335dc566f224b74ff8d9a157fb2025 /imap.c | |
parent | 27fda363d5f0398360b6aaf9bbbf4dbb6bf7d6ec (diff) | |
download | fetchmail-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.c | 225 |
1 files changed, 70 insertions, 155 deletions
@@ -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")); |