From 65b310a77efb75cd01d355df779cf4721156f89e Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Mon, 6 Mar 2000 06:34:46 +0000 Subject: Implemented support for RFC2177 IDLE command. svn path=/trunk/; revision=2790 --- NEWS | 3 +++ conf.c | 1 + design-notes.html | 8 ++++++-- fetchmail-features.html | 10 +++++++--- fetchmail.c | 5 +++++ fetchmail.h | 1 + fetchmail.man | 23 ++++++++++++++++++++--- fetchmailconf | 12 +++++++++--- imap.c | 34 +++++++++++++++++++++++++++++++--- rcfile_l.l | 4 +++- rcfile_y.y | 5 ++++- sample.rcfile | 2 ++ 12 files changed, 92 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 3db8e8d0..7b1a4510 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ (The `lines' figures total .c, .h, .l, and .y files under version control.) +* Added support for RFC2177 IDLE command extension of IMAP. +* Updated fr.po. + fetchmail-5.3.1 (Sun Mar 5 23:02:42 EST 2000), 18648 lines: * Use remotename@hostname for MAIL FROM if we have not been able to deduce diff --git a/conf.c b/conf.c index 1f1039e2..2f108f82 100644 --- a/conf.c +++ b/conf.c @@ -329,6 +329,7 @@ void dump_config(struct runctl *runp, struct query *querylist) booldump("pass8bits", ctl->pass8bits); booldump("dropstatus", ctl->dropstatus); booldump("mimedecode", ctl->mimedecode); + booldump("idle", ctl->idle); stringdump("mda", ctl->mda); stringdump("bsmtp", ctl->bsmtp); diff --git a/design-notes.html b/design-notes.html index 0707878a..4b1bbdce 100644 --- a/design-notes.html +++ b/design-notes.html @@ -10,7 +10,7 @@
Back to Fetchmail Home Page To Site Map -$Date: 2000/02/05 04:10:38 $ +$Date: 2000/03/06 06:34:43 $

Design Notes On Fetchmail

@@ -346,6 +346,8 @@ following minimum steps.
  • Hack conf.c to dump the option so we won't have a version-skew problem.
  • Add an entry to NEWS. + +
  • If the option implements a new feature, add a note to the feature list. There may be other things you have to do in the way of logic, of course.

    @@ -531,13 +533,15 @@ all shaped the design in one way or another.

    IMAP/POP AUTHorize Extension for Simple Challenge/Response
    RFC2449
    POP3 Extension Mechanism +
    RFC2449 +
    IMAP IDLE command
    Back to Fetchmail Home Page To Site Map -$Date: 2000/02/05 04:10:38 $ +$Date: 2000/03/06 06:34:43 $

    Eric S. Raymond <esr@snark.thyrsus.com>
    diff --git a/fetchmail-features.html b/fetchmail-features.html index 619e7971..33dd5950 100644 --- a/fetchmail-features.html +++ b/fetchmail-features.html @@ -10,7 +10,7 @@
    Back to Fetchmail Home Page To Site Map -$Date: 2000/02/05 04:10:38 $ +$Date: 2000/03/06 06:34:43 $

    @@ -19,7 +19,11 @@

    Since 5.0:

    • -Fetchail now recognizes the RFC 2449 extended responses [IN-USE] and +Fetcmail can optionally use the RFC 2177 IDLE extension on an IMAP +server that supports it. + +
    • +Fetchmail now recognizes the RFC 2449 extended responses [IN-USE] and [LOGIN-DELAY].
    • @@ -192,7 +196,7 @@ get-mail, gwpop, pimp-1.0, pop-perl5-1.2, popc, popmail-1.6 and upop.

      Back to Fetchmail Home Page To Site Map -$Date: 2000/02/05 04:10:38 $ +$Date: 2000/03/06 06:34:43 $

      Eric S. Raymond <esr@snark.thyrsus.com>
      diff --git a/fetchmail.c b/fetchmail.c index faaf52f4..ee2d4ee9 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -972,6 +972,7 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(pass8bits); FLAG_MERGE(dropstatus); FLAG_MERGE(mimedecode); + FLAG_MERGE(idle); FLAG_MERGE(limit); FLAG_MERGE(warnings); FLAG_MERGE(fetchlimit); @@ -1138,6 +1139,7 @@ static int load_params(int argc, char **argv, int optind) DEFAULT(ctl->pass8bits, FALSE); DEFAULT(ctl->dropstatus, FALSE); DEFAULT(ctl->mimedecode, FALSE); + DEFAULT(ctl->idle, FALSE); DEFAULT(ctl->server.dns, TRUE); DEFAULT(ctl->server.uidl, FALSE); #ifdef SSL_ENABLE @@ -1673,6 +1675,9 @@ static void dump_params (struct runctl *runp, printf(_(" MIME decoding is %s (mimedecode %s).\n"), ctl->mimedecode ? _("enabled") : _("disabled"), ctl->mimedecode ? "on" : "off"); + printf(_(" Idle after poll is %s (idle %s).\n"), + ctl->idle ? _("enabled") : _("disabled"), + ctl->idle ? "on" : "off"); printf(_(" Nonempty Status lines will be %s (dropstatus %s)\n"), ctl->dropstatus ? _("discarded") : _("kept"), ctl->dropstatus ? "on" : "off"); diff --git a/fetchmail.h b/fetchmail.h index ade31a5a..76ec4a79 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -260,6 +260,7 @@ struct query flag pass8bits; /* if TRUE, ignore Content-Transfer-Encoding */ flag dropstatus; /* if TRUE, drop Status lines in mail */ flag mimedecode; /* if TRUE, decode MIME-armored messages */ + flag idle; /* if TRUE, idle after each poll */ int limit; /* limit size of retrieved messages */ int warnings; /* size warning interval */ int fetchlimit; /* max # msgs to get in single poll */ diff --git a/fetchmail.man b/fetchmail.man index 0188a0de..ded662af 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -1248,6 +1248,9 @@ T} mimedecode \& T{ Convert quoted-printable to 8-bit in MIME messages T} +idle \& T{ +Idle waiting for new messages after each poll (IMAP only) +T} no keep -K T{ Delete seen messages from server (default) T} @@ -1275,6 +1278,9 @@ T} no mimedecode \& T{ Don't convert quoted-printable to 8-bit in MIME messages (default) T} +no idle \& T{ +Don't idle waiting for new messages after each poll (IMAP only) +T} limit -l T{ Set message size limit T} @@ -1314,7 +1320,7 @@ the following: `via', `interval', `aka', `is', `to', `dns'/`no dns', `checkalias'/`no checkalias', `password', `preconnect', `postconnect', `localdomains', `stripcr'/`no stripcr', `forcecr'/`no forcecr', `pass8bits'/`no pass8bits' `dropstatus/no dropstatus', `mimedecode/no -mimedecode', and `no envelope'. +mimedecode', `idle/no idle', and `no envelope'. .PP The `via' option is for use with ssh, or if you want to have more than one configuration pointing at the same site. If it is present, @@ -1471,6 +1477,17 @@ default, because doing RFC2047 conversion on headers throws away character-set information and can lead to bad results if the encoding of the headers differs from the body encoding. .PP +The `idle' option is usable only with IMAP servers supporting the +RFC2177 IDLE command extension. If it is enabled, and fetchmail +detects that IDLE is supported, an IDLE will be issued at the end +of each poll. This will tell the IMAP server to hold the connection +open and notify the client when new mail is available. If you need to +poll a link frequently, IDLE can save bandwidth by eliminating TCP/IP +connects and LOGIN/LOGOUT sequences. On the other hand, an IDLE +connection will eat almost akll of your fetchmail's time, because it +will never drop the connection and allow other pools to occur unless +the server times out the IDLE. +.PP The `properties' option is an extension mechanism. It takes a string argument, which is ignored by fetchmail itself. The string argument may be used to store configuration information for scripts which require it. @@ -1978,7 +1995,7 @@ SMTP/ESMTP: RFC 821, RFC 1869, RFC 1652, RFC 1870, RFC1983, RFC 1985 .TP 5 mail: -RFC 822, RFC 1892, RFC1894 +RFC 822, RFC 1892, RFC 1894 .TP 5 POP2: RFC 937 @@ -1996,7 +2013,7 @@ IMAP2/IMAP2BIS: RFC 1176, RFC 1732 .TP 5 IMAP4/IMAP4rev1: -RFC 1730, RFC 1731, RFC 1732, RFC 2060, RFC 2061, RFC 2195 +RFC 1730, RFC 1731, RFC 1732, RFC 2060, RFC 2061, RFC 2195, RFC 2177 .TP 5 ETRN: RFC 1985 diff --git a/fetchmailconf b/fetchmailconf index e4328a58..2358566d 100755 --- a/fetchmailconf +++ b/fetchmailconf @@ -4,7 +4,7 @@ # by Eric S. Raymond, . # Requires Python with Tkinter, and the following OS-dependent services: # posix, posixpath, socket -version = "1.22" +version = "1.23" from Tkinter import * from Dialog import * @@ -216,6 +216,7 @@ class User: self.pass8bits = FALSE # Force BODY=7BIT self.mimedecode = FALSE # Undo MIME armoring self.dropstatus = FALSE # Drop incoming Status lines + self.idle = FALSE # IDLE after poll self.limit = 0 # Message size limit self.warnings = 0 # Size warning interval self.fetchlimit = 0 # Max messages fetched per batch @@ -246,6 +247,7 @@ class User: ('pass8bits', 'Boolean'), ('mimedecode', 'Boolean'), ('dropstatus', 'Boolean'), + ('idle', 'Boolean'), ('limit', 'Int'), ('warnings', 'Int'), ('fetchlimit', 'Int'), @@ -274,7 +276,8 @@ class User: or self.stripcr != UserDefaults.stripcr or self.pass8bits != UserDefaults.pass8bits or self.mimedecode != UserDefaults.mimedecode - or self.dropstatus != UserDefaults.dropstatus): + or self.dropstatus != UserDefaults.dropstatus + or self.idle != UserDefaults.idle): res = res + " options" if self.keep != UserDefaults.keep: res = res + flag2str(self.keep, 'keep') @@ -294,6 +297,8 @@ class User: res = res + flag2str(self.mimedecode, 'mimedecode') if self.dropstatus != UserDefaults.dropstatus: res = res + flag2str(self.dropstatus, 'dropstatus') + if self.idle != UserDefaults.idle: + res = res + flag2str(self.idle, 'idle') if self.limit != UserDefaults.limit: res = res + " limit " + `self.limit` if self.warnings != UserDefaults.warnings: @@ -1491,6 +1496,8 @@ class UserEdit(Frame, MyWidget): if self.parent.server.protocol in ('IMAP', 'IMAP-K4', 'IMAP-GSS'): LabeledEntry(limwin, 'Interval between expunges (IMAP):', self.expunge, '30').pack(side=TOP, fill=X) + Checkbutton(limwin, text="Idle after each poll (IMAP only)", + variable=self.idle).pack(side=TOP, anchor=W) limwin.pack(fill=X) if self.parent.server.protocol in ('IMAP', 'IMAP-K4', 'IMAP-GSS'): @@ -1646,7 +1653,6 @@ Or you can just select `Quit' to exit the launcher now. Configurator(self.outfile, Toplevel(), lambda self=self: self.configbutton.configure(state=NORMAL), self) - def test(self): RunWindow("fetchmail -d0 -v --nosyslog", Toplevel(), self) diff --git a/imap.c b/imap.c index 9aee018d..948807d2 100644 --- a/imap.c +++ b/imap.c @@ -64,6 +64,7 @@ extern char *strstr(); /* needed on sysV68 R3V7.1. */ static int count, seen, recent, unseen, deletions, imap_version, preauth; static int expunged, expunge_period; +static flag do_idle, idling; static char capabilities[MSGBUFSIZE+1]; int imap_ok(int sock, char *argbuf) @@ -88,7 +89,21 @@ int imap_ok(int sock, char *argbuf) if (strstr(buf, "* CAPABILITY")) strncpy(capabilities, buf + 12, sizeof(capabilities)); if (strstr(buf, "EXISTS")) + { count = atoi(buf+2); + /* + * Nasty kluge to handle RFC2177 IDLE. If we know we're idling + * we can't wait for the tag matching the IDLE; we have to tell the + * server the IDLE is finished by shipping back a DONE when we + * see an EXISTS. Only after that will a tagged response be + * shipped. The idling flag also gets cleared on a timeout. + */ + if (idling) + { + gen_send(sock, "DONE"); + idling = FALSE; + } + } if (strstr(buf, "RECENT")) recent = atoi(buf+2); if (strstr(buf, "UNSEEN")) @@ -901,6 +916,18 @@ int imap_getauth(int sock, struct query *ctl, char *greeting) if (preauth || ctl->server.preauthenticate == A_SSH) return(PS_SUCCESS); + /* + * Handle idling. We depend on coming through here on startup + * and after each timeout (including timeouts during idles). + */ + idling = FALSE; + if (strstr(capabilities, "IDLE") && ctl->idle) + { + do_idle = TRUE; + if (outlevel >= O_VERBOSE) + report(stdout, "will idle after poll\n"); + } + #if OPIE_ENABLE if ((ctl->server.protocol == P_IMAP) && strstr(capabilities, "AUTH=X-OTP")) { @@ -1050,14 +1077,15 @@ static int imap_getrange(int sock, */ ok = 0; if (deletions && expunge_period != 1) - internal_expunge(sock); + ok = internal_expunge(sock); count = -1; - if (ok || gen_transact(sock, "NOOP")) + idling = do_idle; + if (ok || gen_transact(sock, do_idle ? "IDLE" : "NOOP")) { report(stderr, _("re-poll failed\n")); return(ok); } - else if (count == -1) /* no EXISTS response to NOOP */ + else if (count == -1) /* no EXISTS response to NOOP/IDLE */ { count = recent = 0; unseen = -1; diff --git a/rcfile_l.l b/rcfile_l.l index 32e274cc..559bd152 100644 --- a/rcfile_l.l +++ b/rcfile_l.l @@ -130,7 +130,8 @@ noforcecr | nostripcr | nopass8(bits)? | nodropstatus | -nomimedec(ode)? { +nomimedec(ode)? | +noidle { yyless(2); return NO; } @@ -146,6 +147,7 @@ stripcr { return STRIPCR; } pass8(bits)? { return PASS8BITS; } dropstatus { return DROPSTATUS; } mimedec(ode)? { return MIMEDECODE; } +idle { return IDLE; } dns { return DNS; } uidl { return UIDL; } ssl { return SSL; } diff --git a/rcfile_y.y b/rcfile_y.y index 2e99e62b..d5633584 100644 --- a/rcfile_y.y +++ b/rcfile_y.y @@ -69,7 +69,8 @@ extern char * yytext; %token STRING %token NUMBER %token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS DROPSTATUS -%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE CHECKALIAS SSL SSLKEY SSLCERT +%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS +%token SSL SSLKEY SSLCERT %% @@ -322,6 +323,7 @@ user_option : TO localnames HERE | PASS8BITS {current.pass8bits = FLAG_TRUE;} | DROPSTATUS {current.dropstatus = FLAG_TRUE;} | MIMEDECODE {current.mimedecode = FLAG_TRUE;} + | IDLE {current.idle = FLAG_TRUE;} | SSL {current.use_ssl = FLAG_TRUE;} | SSLKEY STRING {current.sslkey = xstrdup($2);} @@ -336,6 +338,7 @@ user_option : TO localnames HERE | NO PASS8BITS {current.pass8bits = FLAG_FALSE;} | NO DROPSTATUS {current.dropstatus = FLAG_FALSE;} | NO MIMEDECODE {current.mimedecode = FLAG_FALSE;} + | NO IDLE {current.idle = FLAG_FALSE;} | NO SSL {current.use_ssl = FLAG_FALSE;} diff --git a/sample.rcfile b/sample.rcfile index b08af78f..54308b4e 100644 --- a/sample.rcfile +++ b/sample.rcfile @@ -68,6 +68,7 @@ # pass8bits # dropstatus # mimedecode +# idle # no keep # no flush # no fetchall @@ -77,6 +78,7 @@ # no pass8bits # no dropstatus # no mimedecode +# no idle # limit -- must be followed by numeric size limit # warnings -- must be followed by numeric size limit # fetchlimit -- must be followed by numeric msg fetch limit -- cgit v1.2.3