aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-08-22 22:59:05 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-08-22 22:59:05 +0000
commit3de1461231102f0b49264fa3346bdee334590fd2 (patch)
treede41cf8e0d3b17c82bf0479dcaf62fd50825d0eb
parent36159e7494bd14e0e19584cc5593c0bb5e902609 (diff)
downloadfetchmail-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--NEWS5
-rw-r--r--fetchmail.c52
-rw-r--r--fetchmail.h5
-rw-r--r--fetchmail.man15
-rw-r--r--options.c35
-rw-r--r--pop3.c82
6 files changed, 174 insertions, 20 deletions
diff --git a/NEWS b/NEWS
index 40e2ca1e..08aab328 100644
--- a/NEWS
+++ b/NEWS
@@ -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.
diff --git a/options.c b/options.c
index 97b00530..70c9ac71 100644
--- a/options.c
+++ b/options.c
@@ -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);
diff --git a/pop3.c b/pop3.c
index adb865cf..d699bd50 100644
--- a/pop3.c
+++ b/pop3.c
@@ -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