diff -Naur fetchmail-6.2.4.orig/conf.c fetchmail-6.2.4.new/conf.c --- fetchmail-6.2.4.orig/conf.c 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/conf.c 2003-09-26 15:13:01.000000000 +0530 @@ -377,6 +377,7 @@ numdump("warnings", ctl->warnings); numdump("fetchlimit", ctl->fetchlimit); numdump("fetchsizelimit", ctl->fetchsizelimit); + numdump("fastuidl", ctl->fastuidl); numdump("batchlimit", ctl->batchlimit); #ifdef SSL_ENABLE booldump("ssl", ctl->use_ssl); diff -Naur fetchmail-6.2.4.orig/driver.c fetchmail-6.2.4.new/driver.c --- fetchmail-6.2.4.orig/driver.c 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/driver.c 2003-09-30 11:51:17.000000000 +0530 @@ -1617,7 +1617,8 @@ * If no expunge limit or we do expunges within the driver, * then just do one session, passing in any fetchlimit. */ - if (proto->retry || !NUM_SPECIFIED(ctl->expunge)) + if ((ctl->keep && !ctl->flush) || + proto->retry || !NUM_SPECIFIED(ctl->expunge)) return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit))); /* * There's an expunge limit, and it isn't handled in the driver itself. diff -Naur fetchmail-6.2.4.orig/fetchmail.c fetchmail-6.2.4.new/fetchmail.c --- fetchmail-6.2.4.orig/fetchmail.c 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/fetchmail.c 2003-09-30 11:28:14.000000000 +0530 @@ -641,13 +641,20 @@ continue; #endif /* (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) */ + dofastuidl = 0; /* this is reset in the driver if required */ + querystatus = query_host(ctl); + if (NUM_NONZERO(ctl->fastuidl)) + ctl->fastuidlcount = (ctl->fastuidlcount + 1) % ctl->fastuidl; #ifdef POP3_ENABLE /* leave the UIDL state alone if there have been any errors */ if (!check_only && ((querystatus==PS_SUCCESS) || (querystatus==PS_NOMAIL) || (querystatus==PS_MAXFETCH))) uid_swap_lists(ctl); + else + uid_discard_new_list(ctl); + uid_reset_num(ctl); #endif /* POP3_ENABLE */ if (querystatus == PS_SUCCESS) @@ -873,6 +880,7 @@ FLAG_MERGE(warnings); FLAG_MERGE(fetchlimit); FLAG_MERGE(fetchsizelimit); + FLAG_MERGE(fastuidl); FLAG_MERGE(batchlimit); #ifdef SSL_ENABLE FLAG_MERGE(use_ssl); @@ -912,6 +920,7 @@ def_opts.remotename = user; def_opts.listener = SMTP_MODE; def_opts.fetchsizelimit = 100; + def_opts.fastuidl = 10; /* get the location of rcfile */ rcfiledir[0] = 0; @@ -1637,6 +1646,15 @@ ctl->fetchsizelimit, ctl->fetchsizelimit); else if (outlevel >= O_VERBOSE) printf(GT_(" No fetch message size limit (--fetchsizelimit 0).\n")); + if (NUM_NONZERO(ctl->fastuidl) && MAILBOX_PROTOCOL(ctl)) + { + if (ctl->fastuidl == 1) + printf(GT_(" Do binary search of UIDs during each poll (--fastuidl 1).\n")); + else + printf(GT_(" Do binary search of UIDs during %d out of %d polls (--fastuidl %d).\n"), ctl->fastuidl - 1, ctl->fastuidl, ctl->fastuidl); + } + else if (outlevel >= O_VERBOSE) + printf(GT_(" Do linear search of UIDs during each poll (--fastuidl 0).\n")); if (NUM_NONZERO(ctl->batchlimit)) printf(GT_(" SMTP message batch limit is %d.\n"), ctl->batchlimit); else if (outlevel >= O_VERBOSE) diff -Naur fetchmail-6.2.4.orig/fetchmail.h fetchmail-6.2.4.new/fetchmail.h --- fetchmail-6.2.4.orig/fetchmail.h 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/fetchmail.h 2003-09-30 11:28:00.000000000 +0530 @@ -147,7 +147,7 @@ { struct { - short num; + int num; flag mark; /* UID-index information */ #define UID_UNSEEN 0 /* hasn't been seen */ #define UID_SEEN 1 /* seen, but not deleted */ @@ -292,6 +292,8 @@ int warnings; /* size warning interval */ int fetchlimit; /* max # msgs to get in single poll */ int fetchsizelimit; /* max # msg sizes to get in a request */ + int fastuidl; /* do binary search for new UIDLs? */ + int fastuidlcount; /* internal count for frequency of binary search */ int batchlimit; /* max # msgs to pass in single SMTP session */ int expunge; /* max # msgs to pass between expunges */ flag use_ssl; /* use SSL encrypted session */ @@ -515,6 +517,8 @@ unsigned char *nxtaddr(const unsigned char *); /* uid.c: UID support */ +extern int dofastuidl; + void initialize_saved_lists(struct query *, const char *); struct idlist *save_str(struct idlist **, const char *, flag); void free_str_list(struct idlist **); @@ -522,17 +526,20 @@ void save_str_pair(struct idlist **, const char *, const char *); void free_str_pair_list(struct idlist **); int delete_str(struct idlist **, long); -int str_in_list(struct idlist **, const char *, const flag); +struct idlist *str_in_list(struct idlist **, const char *, const flag); int str_nr_in_list(struct idlist **, const char *); int str_nr_last_in_list(struct idlist **, const char *); void str_set_mark( struct idlist **, const char *, const flag); int count_list( struct idlist **idl ); char *str_from_nr_list( struct idlist **idl, long number ); char *str_find(struct idlist **, long); +struct idlist *id_find(struct idlist **idl, long); char *idpair_find(struct idlist **, const char *); void append_str_list(struct idlist **, struct idlist **); void expunge_uids(struct query *); void uid_swap_lists(struct query *); +void uid_discard_new_list(struct query *ctl); +void uid_reset_num(struct query *ctl); void write_saved_lists(struct query *, const char *); /* rcfile_y.y */ diff -Naur fetchmail-6.2.4.orig/fetchmail.man fetchmail-6.2.4.new/fetchmail.man --- fetchmail-6.2.4.orig/fetchmail.man 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/fetchmail.man 2003-09-28 19:45:07.000000000 +0530 @@ -496,6 +496,19 @@ This option does not work with ETRN or ODMR. For POP3, the only valid non-zero value is 1. .TP +.B \-\-fastuidl +(Keyword: fastuidl) +Do a binary instead of linear search for the first unseen UID. Binary +search avoids downloading the UIDs of all mails. This saves time +(especially in daemon mode) where downloading the same set of UIDs in +each poll is a waste of bandwidth. The number `n' indicates how rarely +a linear search should be done. In daemon mode, linear search is used +once followed by binary searches in `n-1' polls if `n' is greater than +1; binary search is always used if `n' is 1; linear search is always +used if `n' is 0. In non-daemon mode, binary search is used if `n' is +1; otherwise linear search is used. +This option works with POP3 only. +.TP .B \-e | \-\-expunge (keyword: expunge) Arrange for deletions to be made final after a given number of @@ -1491,6 +1504,9 @@ fetchsizelimit \& T{ Max # message sizes to fetch in single transaction T} +fastuidl \& T{ +Use binary search for first unseen message (POP3 only) +T} expunge -e T{ Perform an expunge on every #th message (IMAP and POP3 only) T} diff -Naur fetchmail-6.2.4.orig/fetchmailconf fetchmail-6.2.4.new/fetchmailconf --- fetchmail-6.2.4.orig/fetchmailconf 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/fetchmailconf 2003-09-26 12:58:28.000000000 +0530 @@ -250,7 +250,8 @@ self.limit = 0 # Message size limit self.warnings = 3600 # Size warning interval (see tunable.h) self.fetchlimit = 0 # Max messages fetched per batch - self.fetchsizelimit = 0 # Max message sizes fetched per transaction + self.fetchsizelimit = 100 # Max message sizes fetched per transaction + self.fastuidl = 10 # Do fast uidl 9 out of 10 times self.batchlimit = 0 # Max message forwarded per batch self.expunge = 0 # Interval between expunges (IMAP) self.ssl = 0 # Enable Seccure Socket Layer @@ -289,6 +290,7 @@ ('warnings', 'Int'), ('fetchlimit', 'Int'), ('fetchsizelimit', 'Int'), + ('fastuidl', 'Int'), ('batchlimit', 'Int'), ('expunge', 'Int'), ('ssl', 'Boolean'), @@ -351,6 +353,8 @@ res = res + " fetchlimit " + `self.fetchlimit` if self.fetchsizelimit != UserDefaults.fetchsizelimit: res = res + " fetchsizelimit " + `self.fetchsizelimit` + if self.fastuidl != UserDefaults.fastuidl: + res = res + " fastuidl " + `self.fastuidl` if self.batchlimit != UserDefaults.batchlimit: res = res + " batchlimit " + `self.batchlimit` if self.ssl and self.ssl != UserDefaults.ssl: @@ -1707,6 +1711,9 @@ self.fetchlimit, '30').pack(side=TOP, fill=X) LabeledEntry(limwin, 'Max message sizes to fetch per transaction:', self.fetchsizelimit, '30').pack(side=TOP, fill=X) + if self.parent.server.protocol not in ('ETRN', 'ODMR'): + LabeledEntry(limwin, 'Use fast UIDL:', + self.fastuidl, '30').pack(side=TOP, fill=X) LabeledEntry(limwin, 'Max messages to forward per poll:', self.batchlimit, '30').pack(side=TOP, fill=X) if self.parent.server.protocol not in ('ETRN', 'ODMR'): diff -Naur fetchmail-6.2.4.orig/options.c fetchmail-6.2.4.new/options.c --- fetchmail-6.2.4.orig/options.c 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/options.c 2003-09-26 15:20:16.000000000 +0530 @@ -87,6 +87,7 @@ #endif #define LA_FETCHSIZELIMIT 61 +#define LA_FASTUIDL 62 /* options still left: CDgGhHjJoORwWxXYz */ static const char *shortoptions = @@ -142,6 +143,7 @@ {"batchlimit",required_argument, (int *) 0, LA_BATCHLIMIT }, {"fetchlimit",required_argument, (int *) 0, LA_FETCHLIMIT }, {"fetchsizelimit",required_argument, (int *) 0, LA_FETCHSIZELIMIT }, + {"fastuidl", required_argument, (int *) 0, LA_FASTUIDL }, {"expunge", required_argument, (int *) 0, LA_EXPUNGE }, {"mda", required_argument, (int *) 0, LA_MDA }, {"bsmtp", required_argument, (int *) 0, LA_BSMTP }, @@ -535,6 +537,10 @@ c = xatoi(optarg, &errflag); ctl->fetchsizelimit = NUM_VALUE_IN(c); break; + case LA_FASTUIDL: + c = xatoi(optarg, &errflag); + ctl->fastuidl = NUM_VALUE_IN(c); + break; case 'e': case LA_EXPUNGE: c = xatoi(optarg, &errflag); @@ -712,6 +718,7 @@ P(GT_(" -b, --batchlimit set batch limit for SMTP connections\n")); P(GT_(" -B, --fetchlimit set fetch limit for server connections\n")); P(GT_(" --fetchsizelimit set fetch message size limit\n")); + P(GT_(" --fastuidl do a binary search for UIDLs\n")); P(GT_(" -e, --expunge set max deletions between expunges\n")); P(GT_(" -m, --mda set MDA to use for forwarding\n")); P(GT_(" --bsmtp set output BSMTP file\n")); diff -Naur fetchmail-6.2.4.orig/pop3.c fetchmail-6.2.4.new/pop3.c --- fetchmail-6.2.4.orig/pop3.c 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/pop3.c 2003-09-30 15:46:54.000000000 +0530 @@ -613,6 +613,77 @@ return 0; } +static int pop3_getuidl( int sock, int num , char *id) +{ + int ok; + char buf [POPBUFSIZE+1]; + gen_send(sock, "UIDL %d", num); + if ((ok = pop3_ok(sock, buf)) != 0) + return(ok); + if (sscanf(buf, "%d %s", &num, id) != 2) + return(PS_PROTOCOL); + return(PS_SUCCESS); +} + +static int pop3_fastuidl( int sock, struct query *ctl, unsigned int count, int *newp) +{ + int ok; + unsigned int first_nr, last_nr, try_nr; + char id [IDLEN+1]; + + first_nr = 0; + last_nr = count + 1; + while (first_nr < last_nr - 1) + { + struct idlist *new; + + try_nr = (first_nr + last_nr) / 2; + if( (ok = pop3_getuidl( sock, try_nr, id )) != 0 ) + return ok; + if ((new = str_in_list(&ctl->oldsaved, id, FALSE))) + { + flag mark = new->val.status.mark; + if (mark == UID_DELETED || mark == UID_EXPUNGED) + { + if (outlevel >= O_VERBOSE) + report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, try_nr); + /* just mark it as seen now! */ + new->val.status.mark = mark = UID_SEEN; + } + + /* narrow the search region! */ + if (mark == UID_UNSEEN) + { + if (outlevel >= O_DEBUG) + report(stdout, GT_("%u is unseen\n"), try_nr); + last_nr = try_nr; + } + else + first_nr = try_nr; + + /* save the number */ + new->val.status.num = try_nr; + } + else + { + if (outlevel >= O_DEBUG) + report(stdout, GT_("%u is unseen\n"), try_nr); + last_nr = try_nr; + + /* save it */ + new = save_str(&ctl->oldsaved, id, UID_UNSEEN); + new->val.status.num = try_nr; + } + } + if (outlevel >= O_DEBUG && last_nr <= count) + report(stdout, GT_("%u is first unseen\n"), last_nr); + + /* update last! */ + *newp = count - first_nr; + last = first_nr; + return 0; +} + static int pop3_slowuidl( int sock, struct query *ctl, int *countp, int *newp) { /* This approach tries to get the message headers from the @@ -737,8 +808,23 @@ *newp = -1; if (*countp > 0 && !ctl->fetchall) { + int fastuidl; char id [IDLEN+1]; + /* should we do fast uidl this time? */ + fastuidl = ctl->fastuidl; + if (*countp > 7 && /* linear search is better if there are few mails! */ + !ctl->flush && /* with flush, it is safer to disable fastuidl */ + NUM_NONZERO (fastuidl)) + { + if (fastuidl == 1) + dofastuidl = 1; + else + dofastuidl = ctl->fastuidlcount != 0; + } + else + dofastuidl = 0; + if (!ctl->server.uidl) { gen_send(sock, "LAST"); ok = pop3_ok(sock, buf); @@ -755,6 +841,8 @@ } else { + if (dofastuidl) + return(pop3_fastuidl( sock, ctl, *countp, newp)); /* grab the mailbox's UID list */ if ((ok = gen_transact(sock, "UIDL")) != 0) { @@ -776,17 +864,41 @@ break; else if (sscanf(buf, "%d %s", &num, id) == 2) { - struct idlist *new; + struct idlist *old, *new; new = save_str(&ctl->newsaved, id, UID_UNSEEN); new->val.status.num = num; - if (str_in_list(&ctl->oldsaved, id, FALSE)) { - new->val.status.mark = UID_SEEN; - str_set_mark(&ctl->oldsaved, id, UID_SEEN); + if ((old = str_in_list(&ctl->oldsaved, id, FALSE))) + { + flag mark = old->val.status.mark; + if (mark == UID_DELETED || mark == UID_EXPUNGED) + { + if (outlevel >= O_VERBOSE) + report(stderr, GT_("id=%s (num=%d) was deleted, but is still present!\n"), id, num); + /* just mark it as seen now! */ + old->val.status.mark = mark = UID_SEEN; + } + new->val.status.mark = mark; + if (mark == UID_UNSEEN) + { + (*newp)++; + if (outlevel >= O_DEBUG) + report(stdout, GT_("%u is unseen\n"), num); + } } else + { (*newp)++; + if (outlevel >= O_DEBUG) + report(stdout, GT_("%u is unseen\n"), num); + /* add it to oldsaved also! In case, we do not + * swap the lists (say, due to socket error), + * the same mail will not be downloaded again. + */ + old = save_str(&ctl->oldsaved, id, UID_UNSEEN); + old->val.status.num = num; + } } } } @@ -855,11 +967,42 @@ static int pop3_is_old(int sock, struct query *ctl, int num) /* is the given message old? */ { + struct idlist *new; if (!ctl->oldsaved) return (num <= last); + else if (dofastuidl) + { + char id [IDLEN+1]; + + if (num <= last) + return(TRUE); + + /* in fast uidl, we manipulate the old list only! */ + + if ((new = id_find(&ctl->oldsaved, num))) + { + /* we already have the id! */ + return(new->val.status.mark != UID_UNSEEN); + } + + /* get the uidl first! */ + if (pop3_getuidl(sock, num, id) != PS_SUCCESS) + return(TRUE); + + if ((new = str_in_list(&ctl->oldsaved, id, FALSE))) { + /* we already have the id! */ + new->val.status.num = num; + return(new->val.status.mark != UID_UNSEEN); + } + + /* save it */ + new = save_str(&ctl->oldsaved, id, UID_UNSEEN); + new->val.status.num = num; + return(FALSE); + } else - return (str_in_list(&ctl->oldsaved, - str_find(&ctl->newsaved, num), FALSE)); + return ((new = id_find(&ctl->newsaved, num)) != NULL && + new->val.status.mark != UID_UNSEEN); } #ifdef UNUSED @@ -970,17 +1113,16 @@ static void mark_uid_seen(struct query *ctl, int number) /* Tell the UID code we've seen this. */ { - if (ctl->newsaved) - { - struct idlist *sdp; + struct idlist *sdp; - for (sdp = ctl->newsaved; sdp; sdp = sdp->next) - if (sdp->val.status.num == number) - { - sdp->val.status.mark = UID_SEEN; - save_str(&ctl->oldsaved, sdp->id,UID_SEEN); - } - } + if ((sdp = id_find(&ctl->newsaved, number))) + sdp->val.status.mark = UID_SEEN; + /* mark it as seen in oldsaved also! In case, we do not swap the lists + * (say, due to socket error), the same mail will not be downloaded + * again. + */ + if ((sdp = id_find(&ctl->oldsaved, number))) + sdp->val.status.mark = UID_SEEN; } static int pop3_delete(int sock, struct query *ctl, int number) @@ -992,7 +1134,7 @@ ok = gen_transact(sock, "DELE %d", number); if (ok != PS_SUCCESS) return(ok); - delete_str(&ctl->newsaved, number); + delete_str(dofastuidl ? &ctl->oldsaved : &ctl->newsaved, number); return(PS_SUCCESS); } diff -Naur fetchmail-6.2.4.orig/rcfile_l.l fetchmail-6.2.4.new/rcfile_l.l --- fetchmail-6.2.4.orig/rcfile_l.l 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/rcfile_l.l 2003-09-26 15:26:21.000000000 +0530 @@ -125,6 +125,7 @@ batchlimit { return BATCHLIMIT; } fetchlimit { return FETCHLIMIT; } fetchsizelimit { return FETCHSIZELIMIT; } +fastuidl { return FASTUIDL; } expunge { return EXPUNGE; } properties { return PROPERTIES; } diff -Naur fetchmail-6.2.4.orig/rcfile_y.y fetchmail-6.2.4.new/rcfile_y.y --- fetchmail-6.2.4.orig/rcfile_y.y 2003-09-22 11:50:55.000000000 +0530 +++ fetchmail-6.2.4.new/rcfile_y.y 2003-09-30 15:05:22.000000000 +0530 @@ -67,7 +67,7 @@ %token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS %token NETSEC INTERFACE MONITOR PLUGIN PLUGOUT %token IS HERE THERE TO MAP WILDCARD -%token BATCHLIMIT FETCHLIMIT FETCHSIZELIMIT EXPUNGE PROPERTIES +%token BATCHLIMIT FETCHLIMIT FETCHSIZELIMIT FASTUIDL EXPUNGE PROPERTIES %token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE POSTMASTER BOUNCEMAIL %token SPAMBOUNCE SHOWDOTS %token PROTO AUTHTYPE @@ -375,6 +375,7 @@ | WARNINGS NUMBER {current.warnings = NUM_VALUE_IN($2);} | FETCHLIMIT NUMBER {current.fetchlimit = NUM_VALUE_IN($2);} | FETCHSIZELIMIT NUMBER {current.fetchsizelimit = NUM_VALUE_IN($2);} + | FASTUIDL NUMBER {current.fastuidl = NUM_VALUE_IN($2);} | BATCHLIMIT NUMBER {current.batchlimit = NUM_VALUE_IN($2);} | EXPUNGE NUMBER {current.expunge = NUM_VALUE_IN($2);} diff -Naur fetchmail-6.2.4.orig/uid.c fetchmail-6.2.4.new/uid.c --- fetchmail-6.2.4.orig/uid.c 2003-08-06 09:00:19.000000000 +0530 +++ fetchmail-6.2.4.new/uid.c 2003-10-01 08:19:09.000000000 +0530 @@ -63,9 +63,45 @@ * be picked up by the next run. If there are no un-expunged * messages, the file is deleted. * + * One disadvantage of UIDL is that all the UIDs have to be downloaded + * before a search for new messages can be done. Typically, new messages + * are appended to mailboxes. Hence, downloading all UIDs just to download + * a few new mails is a waste of bandwidth. If new messages are always at + * the end of the mailbox, fast UIDL will decrease the time required to + * download new mails. + * + * During fast UIDL, the UIDs of all messages are not downloaded! The first + * unseen message is searched for by using a binary search on UIDs. UIDs + * after the first unseen message are downloaded as and when needed. + * + * The advantages of fast UIDL are (this is noticeable only when the + * mailbox has too many mails): + * + * - There is no need to download the UIDs of all mails right at the start. + * - There is no need to save all the UIDs in memory separately in + * `newsaved' list. + * - There is no need to download the UIDs of seen mail (except for the + * first binary search). + * - The first new mail is downloaded considerably faster. + * + * The disadvantages are: + * + * - Since all UIDs are not downloaded, it is not possible to swap old and + * new list. The current state of the mailbox is essentially a merged state + * of old and new mails. + * - If an intermediate mail has been temporarily refused (say, due to 4xx + * code from the smtp server), this mail may not get downloaded. + * - If 'flush' is used, such intermediate mails will also get deleted. + * + * The first two disadvantages can be overcome by doing a linear search + * once in a while (say, every 10th poll). Also, with flush, fast UIDL + * should be disabled. + * * Note: some comparisons (those used for DNS address lists) are caseblind! */ +int dofastuidl = 0; + /* UIDs associated with un-queried hosts */ static struct idlist *scratchlist; @@ -305,20 +341,20 @@ } #endif -int str_in_list(struct idlist **idl, const char *str, const flag caseblind) +struct idlist *str_in_list(struct idlist **idl, const char *str, const flag caseblind) /* is a given ID in the given list? (comparison may be caseblind) */ { struct idlist *walk; if (caseblind) { for( walk = *idl; walk; walk = walk->next ) if( strcasecmp( str, (char *)walk->id) == 0 ) - return 1; + return walk; } else { for( walk = *idl; walk; walk = walk->next ) if( strcmp( str, (char *)walk->id) == 0 ) - return 1; + return walk; } - return 0; + return NULL; } int str_nr_in_list( struct idlist **idl, const char *str ) @@ -389,6 +425,16 @@ return(str_find(&(*idl)->next, number)); } +struct idlist *id_find(struct idlist **idl, long number) +/* return the id of the given number in the given list. */ +{ + struct idlist *idp; + for (idp = *idl; idp; idp = idp->next) + if (idp->val.status.num == number) + return(idp); + return(0); +} + char *idpair_find(struct idlist **idl, const char *id) /* return the id of the given id in the given list (caseblind comparison) */ { @@ -449,7 +495,7 @@ { struct idlist *idl; - for (idl = ctl->newsaved; idl; idl = idl->next) + for (idl = dofastuidl ? ctl->oldsaved : ctl->newsaved; idl; idl = idl->next) if (idl->val.status.mark == UID_DELETED) idl->val.status.mark = UID_EXPUNGED; } @@ -462,8 +508,11 @@ { struct idlist *idp; - report_build(stdout, GT_("New UID list from %s:"), ctl->server.pollname); - for (idp = ctl->newsaved; idp; idp = idp->next) + if (dofastuidl) + report_build(stdout, GT_("Merged UID list from %s:"), ctl->server.pollname); + else + report_build(stdout, GT_("New UID list from %s:"), ctl->server.pollname); + for (idp = dofastuidl ? ctl->oldsaved : ctl->newsaved; idp; idp = idp->next) report_build(stdout, " %s = %d", idp->id, idp->val.status.mark); if (!idp) report_build(stdout, GT_(" ")); @@ -495,10 +544,48 @@ ctl->oldsaved = ctl->newsaved; ctl->newsaved = (struct idlist *) NULL; } - else if (outlevel >= O_DEBUG) + /* in fast uidl, there is no need to swap lists: the old state of + * mailbox cannot be discarded! */ + else if (outlevel >= O_DEBUG && !dofastuidl) report(stdout, GT_("not swapping UID lists, no UIDs seen this query\n")); } +void uid_discard_new_list(struct query *ctl) +/* finish a query which had errors */ +{ + /* debugging code */ + if (ctl->server.uidl && outlevel >= O_DEBUG) + { + struct idlist *idp; + + /* this is now a merged list! the mails which were seen in this + * poll are marked here. */ + report_build(stdout, GT_("Merged UID list from %s:"), ctl->server.pollname); + for (idp = ctl->oldsaved; idp; idp = idp->next) + report_build(stdout, " %s = %d", idp->id, idp->val.status.mark); + if (!idp) + report_build(stdout, GT_(" ")); + report_complete(stdout, "\n"); + } + + if (ctl->newsaved) + { + /* new state of mailbox is not reliable */ + if (outlevel >= O_DEBUG) + report(stdout, GT_("discarding new UID list\n")); + free_str_list(&ctl->newsaved); + ctl->newsaved = (struct idlist *) NULL; + } +} + +void uid_reset_num(struct query *ctl) +/* reset the number associated with each id */ +{ + struct idlist *idp; + for (idp = ctl->oldsaved; idp; idp = idp->next) + idp->val.status.num = 0; +} + void write_saved_lists(struct query *hostlist, const char *idfile) /* perform end-of-run write of seen-messages list */ {