diff options
author | Eric S. Raymond <esr@thyrsus.com> | 1996-08-22 22:59:05 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 1996-08-22 22:59:05 +0000 |
commit | 3de1461231102f0b49264fa3346bdee334590fd2 (patch) | |
tree | de41cf8e0d3b17c82bf0479dcaf62fd50825d0eb | |
parent | 36159e7494bd14e0e19584cc5593c0bb5e902609 (diff) | |
download | fetchmail-3de1461231102f0b49264fa3346bdee334590fd2.tar.gz fetchmail-3de1461231102f0b49264fa3346bdee334590fd2.tar.bz2 fetchmail-3de1461231102f0b49264fa3346bdee334590fd2.zip |
Added support for RFC-1725-compliant servers with UIDL and without LAST.
svn path=/trunk/; revision=56
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | fetchmail.c | 52 | ||||
-rw-r--r-- | fetchmail.h | 5 | ||||
-rw-r--r-- | fetchmail.man | 15 | ||||
-rw-r--r-- | options.c | 35 | ||||
-rw-r--r-- | pop3.c | 82 |
6 files changed, 174 insertions, 20 deletions
@@ -14,6 +14,11 @@ S/key for secure challenge-response. Implement IMAP support. +3.05: + +* Experimental support for RFC1725-compliant POP servers with the UIDL + command and without LAST. + 3.04: * Logfile option works. diff --git a/fetchmail.c b/fetchmail.c index 65e309a6..e2687bf2 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -39,7 +39,7 @@ #include "popclient.h" /* release info */ -#define RELEASE_TAG "3.04" +#define RELEASE_TAG "3.05" #ifdef HAVE_PROTOTYPES /* prototypes for internal functions */ @@ -61,6 +61,7 @@ int quitmode; /* if --quit was set */ /* miscellaneous global controls */ char *poprcfile; /* path name of rc file */ +char *idfile; /* path name of id file */ int linelimit; /* limit # lines retrieved per site */ int versioninfo; /* emit only version info */ @@ -83,16 +84,16 @@ char *mda_argv [32]; static void termhook(); static char *lockfile; static int popstatus; +static struct hostrec *hostp, *hostlist = (struct hostrec *)NULL; main (argc,argv) int argc; char **argv; { - int mboxfd; + int mboxfd, st; struct hostrec cmd_opts, def_opts; int parsestatus; char *servername; - struct hostrec *hostp, *hostlist = (struct hostrec *)NULL; FILE *tmpfp; pid_t pid; @@ -121,6 +122,7 @@ char **argv; prc_mergeoptions(servername, &cmd_opts, &def_opts, hostp); strcpy(hostp->servername, servername); parseMDAargs(hostp); + hostp->lastid[0] = '\0'; hostp->next = hostlist; hostlist = hostp; @@ -165,7 +167,7 @@ char **argv; fscanf(fp,"%d",&pid); fprintf(stderr,"popclient: killing popclient at PID %d\n",pid); - if ( kill(pid,SIGKILL) < 0 ) + if ( kill(pid,SIGTERM) < 0 ) fprintf(stderr,"popclient: error killing the process %d.\n",pid); else fprintf(stderr,"popclient: popclient at %d is dead.\n", pid); @@ -184,6 +186,23 @@ char **argv; return(PS_EXCLUDE); } + /* let's get stored message IDs from previous transactions */ + if ((st = prc_filecheck(idfile)) != 0) { + return (st); + } else if ((tmpfp = fopen(idfile, "r")) != (FILE *)NULL) { + char buf[POPBUFSIZE+1], host[HOSTLEN+1], id[IDLEN+1]; + + while (fgets(buf, POPBUFSIZE, tmpfp) != (char *)NULL) { + if ((st = sscanf(buf, "%s %s\n", host, id)) == 2) { + for (hostp = hostlist; hostp; hostp = hostp->next) { + if (strcmp(host, hostp->servername) == 0) + strcpy(hostp->lastid, id); + } + } + } + fclose(tmpfp); + } + /* * Maybe time to go to demon mode... */ @@ -231,8 +250,27 @@ char **argv; void termhook() { - unlink(lockfile); - exit(popstatus); + FILE *tmpfp; + int idcount = 0; + + for (hostp = hostlist; hostp; hostp = hostp->next) { + if (hostp->lastid[0]) + idcount++; + } + + /* write updated last-seen IDs */ + if (!idcount) + unlink(idfile); + else if ((tmpfp = fopen(idfile, "w")) != (FILE *)NULL) { + for (hostp = hostlist; hostp; hostp = hostp->next) { + if (hostp->lastid[0]) + fprintf(tmpfp, "%s %s\n", hostp->servername, hostp->lastid); + } + fclose(tmpfp); + } + + unlink(lockfile); + exit(popstatus); } int query_host(queryctl) @@ -339,6 +377,8 @@ struct hostrec *queryctl; else printf(" Text retrieved per message will be at most %d bytes.\n", linelimit); + if (queryctl->lastid[0]) + printf(" ID of last message retrieved %s\n", queryctl->lastid); } /********************************************************************* diff --git a/fetchmail.h b/fetchmail.h index 3eaa1df9..5d071bb2 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -22,6 +22,7 @@ #define FOLDERLEN 256 /* max folder name length */ #define DIGESTLEN 33 /* length of MD5 digest */ #define MDALEN 256 /* length of delivery agent command */ +#define IDLEN 128 /* length of UIDL message ID */ /* exit code values */ #define PS_SUCCESS 0 /* successful receipt of messages */ @@ -59,6 +60,9 @@ struct hostrec { int flush; int rewrite; + /* state used for tracking UIDL ids */ + char lastid [IDLEN]; + /* dependent on the above members */ int output; struct hostrec *next; @@ -80,6 +84,7 @@ extern int quitmode; /* if --quit was set */ /* miscellaneous global controls */ extern char *poprcfile; /* path name of rc file */ +extern char *idfile; /* path name of id file */ extern int linelimit; /* limit # lines retrieved per site */ extern int versioninfo; /* emit only version info */ diff --git a/fetchmail.man b/fetchmail.man index cb38b7d8..1fc19b30 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -71,6 +71,9 @@ before retrieving new messages. .B \-f pathname, --poprc pathname Specify an alternate name for the .poprc file. .TP +.B \-i pathname, --idfile pathname +Specify an alternate name for the .popids file. +.TP .B \-k, --keep Keep retrieved messages in folder on remote mailserver. Normally, messages are deleted from the folder on the mailserver after they have been retrieved @@ -530,6 +533,13 @@ was written by Carl Harris at Virginia Polytechnic Institute and State University (a.k.a. Virginia Tech). Version 3.0 was extensively improved by Eric S. Raymond <esr@snark.thyrsus.com> and is now maintained by esr.. .PP +.SH FILES +.TP 5 +~/.poprc +default configuration file +~/.popids +default location of file associating hosts with last message IDs seen +(used only with newer RFC1725-compliant servers supporting the UIDL command). .SH BUGS .PP The --version option doesn't display MDA arguments. @@ -542,6 +552,8 @@ dies after the first delivery. To cope with this, in daemon mode the delivery mode is automatically switched to append-and-lock if sendmail is the selected delivery agent. This needs to be fixed. .PP +The UIDL support for RFC1725-compliant servers is not yet well tested. +.PP No IMAP or RPOP support yet. .PP Send comments, bug reports, gripes, and the like to Eric S. Raymond @@ -553,4 +565,5 @@ must now be specified either manually or in your .I ~/.poprc file. .SH SEE ALSO -mail(1), binmail(1), sendmail(8), popd(8), RFC 937, RFC 1225. +mail(1), binmail(1), sendmail(8), popd(8), +RFC 937, RFC 1081, RFC 1082, RFC 1225, RFC 1460, RFC 1725. @@ -33,14 +33,15 @@ #define LA_PROTOCOL 10 #define LA_DAEMON 11 #define LA_POPRC 12 -#define LA_USERNAME 13 -#define LA_REMOTEFILE 14 -#define LA_LOCALFILE 15 -#define LA_MDA 16 -#define LA_LOGFILE 17 -#define LA_QUIT 18 -#define LA_NOREWRITE 19 -#define LA_YYDEBUG 20 +#define LA_IDFILE 13 +#define LA_USERNAME 14 +#define LA_REMOTEFILE 15 +#define LA_LOCALFILE 16 +#define LA_MDA 17 +#define LA_LOGFILE 18 +#define LA_QUIT 19 +#define LA_NOREWRITE 20 +#define LA_YYDEBUG 21 static char *shortoptions = "23VaKkvscl:Fd:f:u:r:o:m:L:qN"; static struct option longoptions[] = { @@ -63,6 +64,7 @@ static struct option longoptions[] = { {"local", required_argument, (int *) 0, LA_LOCALFILE }, {"mda", required_argument, (int *) 0, LA_MDA }, {"logfile", required_argument, (int *) 0, LA_LOGFILE }, + {"idfile", required_argument, (int *) 0, LA_IDFILE }, {"quit", no_argument, (int *) 0, LA_QUIT }, {"norewrite", no_argument, (int *) 0, LA_NOREWRITE }, {"yydebug", no_argument, (int *) 0, LA_YYDEBUG }, @@ -87,7 +89,7 @@ static struct option longoptions[] = { syntax errors. calls: none. globals: writes outlevel, versioninfo, yydebug, logfile, - poll_interval, quitmode, poprcfile, linelimit. + poll_interval, quitmode, poprcfile, idfile, linelimit. *********************************************************************/ int parsecmdline (argc,argv,queryctl) @@ -190,6 +192,11 @@ struct hostrec *queryctl; poprcfile = (char *) xmalloc(strlen(optarg)+1); strcpy(poprcfile,optarg); break; + case 'i': + case LA_IDFILE: + idfile = (char *) xmalloc(strlen(optarg)+1); + strcpy(idfile,optarg); + break; case 'u': case LA_USERNAME: strncpy(queryctl->remotename,optarg,sizeof(queryctl->remotename)-1); @@ -252,6 +259,7 @@ struct hostrec *queryctl; fputs(" -v, --verbose work noisily (diagnostic output)\n", stderr); fputs(" -d, --daemon run as a daemon once per n seconds\n", stderr); fputs(" -f, --poprc specify alternate config file\n", stderr); + fputs(" -i, --idfile specify alternate ID database\n", stderr); fputs(" -u, --username specify server user ID\n", stderr); fputs(" -c, --stdout write received mail to stdout\n", stderr); fputs(" -o, --local specify filename for received mail\n", stderr); @@ -279,7 +287,7 @@ struct hostrec *queryctl; return value: zero if defaults were successfully set, else non-zero (indicates a problem reading /etc/passwd). calls: none. - globals: writes outlevel, poprcfile. + globals: writes outlevel, poprcfile, idfile. *********************************************************************/ int setdefaults (queryctl) @@ -318,6 +326,13 @@ struct hostrec *queryctl; strcat(poprcfile, "/"); strcat(poprcfile, POPRC_NAME); + idfile = + (char *) xmalloc(strlen(pw->pw_dir)+strlen(IDFILE_NAME)+2); + + strcpy(idfile, pw->pw_dir); + strcat(idfile, "/"); + strcat(idfile, IDFILE_NAME); + outlevel = O_NORMAL; return(0); @@ -40,6 +40,7 @@ int POP3_sendSTAT (int *msgcount, int socket); int POP3_sendRETR (int msgnum, int socket); int POP3_sendDELE (int msgnum, int socket); int POP3_sendLAST (int *last, int socket); +int POP3_sendUIDL (int num, int socket, char **cp); int POP3_readmsg (int socket, int mboxfd, char *host, int topipe, int rewrite); int POP3_BuildDigest (char *buf, struct hostrec *options); #endif @@ -63,7 +64,7 @@ int POP3_BuildDigest (char *buf, struct hostrec *options); int doPOP3 (queryctl) struct hostrec *queryctl; { - int ok; + int ok, use_uidl; int mboxfd; char buf [POPBUFSIZE]; int socket; @@ -124,11 +125,39 @@ struct hostrec *queryctl; /* * Ask for number of last message retrieved. * Newer, RFC-1760-conformant POP servers may not have the LAST command. - * Therefore we don't croak if we get a nonzero return. + * Therefore we don't croak if we get a nonzero return. Instead, send + * UIDL and try to find the last received ID stored for this host in + * the list we get back. */ first = 1; + use_uidl = 0; if (!queryctl->fetchall) { + char buf [POPBUFSIZE]; + char id [IDLEN]; + int num; + + /* try LAST first */ ok = POP3_sendLAST(&first, socket); + use_uidl = (ok != 0); + + /* otherwise, if we have a stored last ID for this host, + * send UIDL and search the returned list for it + */ + if (use_uidl && queryctl->lastid[0]) { + if ((ok = POP3_sendUIDL(-1, socket, 0)) == 0) { + while (SockGets(socket, buf, sizeof(buf)) == 0) { + if (outlevel == O_VERBOSE) + fprintf(stderr,"%s\n",buf); + if (strcmp(buf, ".\n") == 0) { + break; + } + if (sscanf(buf, "%d %s\n", &num, id) == 2) + if (strcmp(id, queryctl->lastid) == 0) + first = num; + } + } + } + if (ok == 0) first++; } @@ -146,6 +175,8 @@ struct hostrec *queryctl; if (count > 0) { for (number = queryctl->flush ? 1 : first; number <= count; number++) { + char *cp; + /* open the mail pipe if we're using an MDA */ if (queryctl->output == TO_MDA && (queryctl->fetchall || number >= first)) { @@ -173,6 +204,11 @@ struct hostrec *queryctl; if (ok != 0) goto cleanUp; + /* update the last-seen field for this host */ + if (use_uidl && (ok = POP3_sendUIDL(number, socket, &cp)) == 0) + (void) strcpy(queryctl->lastid, cp); + + /* maybe we delete this message now? */ if ((number < first && queryctl->flush) || !queryctl->keep) { if (outlevel > O_SILENT && outlevel < O_VERBOSE) fprintf(stderr,"flushing message %d\n", number); @@ -671,7 +707,7 @@ int rewrite; arguments: last integer buffer to receive last message# - ret. value: non-zero on success, else zero. + ret. value: zero if success, else status code. globals: SockPrintf, POP3_OK. calls: reads outlevel. *****************************************************************/ @@ -697,6 +733,46 @@ int socket; return(ok); } +/****************************************************************** + function: POP3_sendUIDL + description: send the UIDL command to the server, + + arguments: + num number of message to query (may be -1) + + ret. value: zero if success, else status code. + globals: SockPrintf, POP3_OK. + calls: reads outlevel. + *****************************************************************/ + +int POP3_sendUIDL (num, socket, cp) +int num; +int socket; +char **cp; +{ + int ok; + char buf [POPBUFSIZE]; + static char id[IDLEN]; + + (void) strcpy(buf, "UIDL\r\n"); + if (num > -1) + (void) sprintf(buf, "UIDL %d\r\n", num); + + SockPrintf(socket, buf); + if (outlevel == O_VERBOSE) + fprintf(stderr,"> %s", buf); + + ok = POP3_OK(buf,socket); + if (ok != 0 && outlevel > O_SILENT) + fprintf(stderr,"Server says '%s' to UIDL command.\n",buf); + + if (cp) { + sscanf(buf, "%*d %s\n", id); + *cp = id; + } + return(ok); +} + /****************************************************************** function: POP3_BuildDigest |