aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-08-27 15:26:48 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-08-27 15:26:48 +0000
commit096baf62311247c313fc818c061b9382becf6458 (patch)
treed453bacd1f56876d6866b19359e8602ff09e23c5
parent4e41d2758a5f46700876197ce659ba28bae90e07 (diff)
downloadfetchmail-096baf62311247c313fc818c061b9382becf6458.tar.gz
fetchmail-096baf62311247c313fc818c061b9382becf6458.tar.bz2
fetchmail-096baf62311247c313fc818c061b9382becf6458.zip
Successfully genericized POP3 and IMAP.
svn path=/trunk/; revision=73
-rw-r--r--Makefile.in4
-rw-r--r--fetchmail.c2
-rw-r--r--fetchmail.h28
-rw-r--r--imap.c653
-rw-r--r--pop3.c226
5 files changed, 256 insertions, 657 deletions
diff --git a/Makefile.in b/Makefile.in
index 4c9c710c..ed9efb98 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -63,14 +63,14 @@ ETAGS = etags -tw
CTAGS = ctags -tw
popobjs = socket.o getpass.o pop2.o pop3.o imap.o popclient.o options.o \
- poprc_l.o poprc_y.o poprc.o daemon.o xmalloc.o
+ poprc_l.o poprc_y.o poprc.o daemon.o driver.o xmalloc.o
objs = $(popobjs) $(EXTRAOBJ) $(extras)
srcs = $(srcdir)/socket.c $(srcdir)/getpass.c $(srcdir)/pop2.c \
$(srcdir)/pop3.c $(srcdir)/imap.c $(srcdir)/popclient.c \
$(srcdir)/options.c $(srcdir)/poprc.c $(srcdir)/daemon.c \
- $(srcdir)/xmalloc.c $(EXTRASRC)
+ $(srcdir)/driver.c $(srcdir)/xmalloc.c $(EXTRASRC)
.SUFFIXES:
.SUFFIXES: .o .c .h .y .l .ps .dvi .info .texi
diff --git a/fetchmail.c b/fetchmail.c
index bee75d16..a9ed8fc6 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -331,7 +331,7 @@ struct hostrec *queryctl;
break;
case P_POP3:
case P_APOP:
- return(doPOP3(queryctl));
+ return(doPOP3bis(queryctl));
break;
case P_IMAP:
return(doIMAP(queryctl));
diff --git a/fetchmail.h b/fetchmail.h
index a65e3773..571a39d8 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -46,7 +46,8 @@
#define TO_STDOUT 2 /* use stdout */
#define TO_MDA 3 /* use agent */
-struct hostrec {
+struct hostrec
+{
char servername [HOSTLEN];
char localname [USERNAMELEN];
char remotename [USERNAMELEN];
@@ -73,6 +74,25 @@ struct hostrec {
#endif
};
+struct method
+{
+ char *name; /* protocol name */
+ int port; /* service port */
+ int tagged; /* if true, generate & expect command tags */
+ int delimited; /* if true, accept "." message delimiter */
+ int (*parse_response)(); /* response_parsing function */
+ int (*getauth)(); /* authorization fetcher */
+ int (*getrange)(); /* get message range to fetch */
+ int (*fetch)(); /* fetch a given message */
+ int (*trail)(); /* eat trailer of a message */
+ char *delete_cmd; /* delete command */
+ char *expunge_cmd; /* expunge command */
+ char *exit_cmd; /* exit command */
+};
+
+#define TAGLEN 5
+extern char tag[TAGLEN];
+
/* controls the detail level of status/progress messages written to stderr */
extern int outlevel; /* see the O_.* constants above */
extern int yydebug; /* enable parse debugging */
@@ -90,6 +110,12 @@ extern int versioninfo; /* emit only version info */
#ifdef HAVE_PROTOTYPES
+int gen_ok (char *buf, int socket);
+void gen_send ();
+int gen_transact ();
+int gen_readmsg (int socket, int mboxfd, long len, int delimited,
+ char *host, int topipe, int rewrite);
+
/* prototypes for globally callable functions */
int doPOP2 (struct hostrec *);
int doPOP3 (struct hostrec *);
diff --git a/imap.c b/imap.c
index 5e4688f3..29df58f2 100644
--- a/imap.c
+++ b/imap.c
@@ -29,266 +29,8 @@
#include "socket.h"
#include "popclient.h"
-#ifdef HAVE_PROTOTYPES
-/* prototypes for internal functions */
-int gen_ok (char *buf, int socket);
-void gen_send ();
-int gen_transact ();
-int gen_readmsg (int socket, int mboxfd, long len, int delimited,
- char *host, int topipe, int rewrite);
-#endif
-
-#define DELIMITED 99999L
-
-#define TAGLEN 5
-static char tag[TAGLEN];
-static int tagnum;
-#define GENSYM (sprintf(tag, "a%04d", ++tagnum), tag)
-
static int count, first;
-struct method
-{
- char *name; /* protocol name */
- int port; /* service port */
- int tagged; /* if true, generate & expect command tags */
- int delimited; /* if true, accept "." message delimiter */
- int (*parse_response)(); /* response_parsing function */
- int (*getauth)(); /* authorization fetcher */
- int (*getrange)(); /* get message range to fetch */
- int (*fetch)(); /* fetch a given message */
- int (*trail)(); /* eat trailer of a message */
- char *delete_cmd; /* delete command */
- char *expunge_cmd; /* expunge command */
- char *exit_cmd; /* exit command */
-};
-
-/*********************************************************************
-
- Method declarations for POP3
-
- *********************************************************************/
-
-int pop3_ok (argbuf,socket)
-/* parse command response */
-char *argbuf;
-int socket;
-{
- int ok;
- char buf [POPBUFSIZE];
- char *bufp;
-
- if (SockGets(socket, buf, sizeof(buf)) >= 0) {
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"%s\n",buf);
-
- bufp = buf;
- if (*bufp == '+' || *bufp == '-')
- bufp++;
- else
- return(PS_PROTOCOL);
-
- while (isalpha(*bufp))
- bufp++;
- *(bufp++) = '\0';
-
- if (strcmp(buf,"+OK") == 0)
- ok = 0;
- else if (strcmp(buf,"-ERR") == 0)
- ok = PS_ERROR;
- else
- ok = PS_PROTOCOL;
-
- if (argbuf != NULL)
- strcpy(argbuf,bufp);
- }
- else
- ok = PS_SOCKET;
-
- return(ok);
-}
-
-int pop3_getauth(socket, queryctl, greeting)
-/* apply for connection authorization */
-int socket;
-struct hostrec *queryctl;
-char *greeting;
-{
- char buf [POPBUFSIZE];
-
-#if defined(HAVE_APOP_SUPPORT)
- /* build MD5 digest from greeting timestamp + password */
- if (queryctl->whichpop == P_APOP)
- if (POP3_BuildDigest(greeting,queryctl) != 0) {
- return(PS_AUTHFAIL);
- }
-#endif
-
- switch (queryctl->protocol) {
- case P_POP3:
- SockPrintf(socket,"USER %s\r\n",queryctl->remotename);
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> USER %s\n",queryctl->remotename);
- if (POP3_OK(buf,socket) != 0)
- goto badAuth;
-
- SockPrintf(socket,"PASS %s\r\n",queryctl->password);
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> PASS password\n");
- if (POP3_OK(buf,socket) != 0)
- goto badAuth;
-
- break;
-
-#if defined(HAVE_APOP_SUPPORT)
- case P_APOP:
- SockPrintf(socket,"APOP %s %s\r\n",
- queryctl->remotename, queryctl->digest);
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> APOP %s %s\n",queryctl->remotename, queryctl->digest);
- if (POP3_OK(buf,socket) != 0)
- goto badAuth;
- break;
-#endif /* HAVE_APOP_SUPPORT */
-
-#if defined(HAVE_RPOP_SUPPORT)
- case P_RPOP:
- SockPrintf(socket, "RPOP %s\r\n", queryctl->remotename);
- if (POP3_OK(buf,socket) != 0)
- goto badAuth;
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> RPOP %s %s\n",queryctl->remotename);
- break;
-#endif /* HAVE_RPOP_SUPPORT */
-
- default:
- fprintf(stderr,"Undefined protocol request in POP3_auth\n");
- }
-
- /* we're approved */
- return(0);
-
- /*NOTREACHED*/
-
-badAuth:
- if (outlevel > O_SILENT && outlevel < O_VERBOSE)
- fprintf(stderr,"%s\n",buf);
- else
- ; /* say nothing */
-
- return(PS_ERROR);
-}
-
-static int use_uidl;
-
-static pop3_getrange(socket, queryctl, countp, firstp)
-/* get range of messages to be fetched */
-int socket;
-struct hostrec *queryctl;
-int *countp;
-int *firstp;
-{
- int ok;
-
- ok = POP3_sendSTAT(countp,socket);
- if (ok != 0) {
- return(ok);
- }
-
- /*
- * 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. Instead, send
- * UIDL and try to find the last received ID stored for this host in
- * the list we get back.
- */
- *firstp = 1;
- use_uidl = 0;
- if (!queryctl->fetchall) {
- char buf [POPBUFSIZE];
- char id [IDLEN];
- int num;
-
- /* try LAST first */
- ok = POP3_sendLAST(firstp, 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)
- *firstp = num;
- }
- }
- }
-
- if (ok == 0)
- (*firstp)++;
- }
-
- return(0);
-}
-
-static int pop3_fetch(socket, number, limit, lenp)
-/* request nth message */
-int socket;
-int number;
-int limit;
-int *lenp;
-{
- *lenp = DELIMITED;
- if (limit)
- return(POP3_sendTOP(number, limit, socket));
- else
- return(POP3_sendRETR(number, socket));
-}
-
-static pop3_trail(socket, queryctl, number)
-/* update the last-seen field for this host */
-int socket;
-struct hostrec *queryctl;
-int number;
-{
- char *cp;
- int ok = 0;
-
- if (use_uidl && (ok = POP3_sendUIDL(number, socket, &cp)) == 0)
- (void) strcpy(queryctl->lastid, cp);
- return(ok);
-}
-
-static struct method pop3 =
-{
- "POP3", /* Post Office Protocol v3 */
- 110, /* standard POP3 port */
- 0, /* this is not a tagged protocol */
- 1, /* this uses a message delimiter */
- pop3_ok, /* parse command response */
- pop3_getauth, /* get authorization */
- pop3_getrange, /* query range of messages */
- pop3_fetch, /* request given message */
- pop3_trail, /* eat message trailer */
- "DELE %d", /* set POP3 delete flag */
- NULL, /* the POP3 expunge command */
- "QUIT", /* the POP3 exit command */
-};
-
-int doPOP3bis (queryctl)
-/* retrieve messages using POP3 */
-struct hostrec *queryctl;
-{
- return(do_protocol(queryctl, &pop3));
-}
-
/*********************************************************************
Method declarations for IMAP
@@ -455,398 +197,3 @@ struct hostrec *queryctl;
return(do_protocol(queryctl, &imap));
}
-/*********************************************************************
-
- Everything below here is generic to all protocols.
-
- *********************************************************************/
-
-static struct method *protocol;
-
-/*********************************************************************
- function: do_protocol
- description: retrieve messages from the specified mail server
- using a given set of mrthods
-
- arguments:
- queryctl fully-specified options (i.e. parsed, defaults invoked,
- etc).
- proto protocol method pointer
-
- return value: exit code from the set of PS_.* constants defined in
- popclient.h
- calls:
- globals: reads outlevel.
- *********************************************************************/
-
-int do_protocol(queryctl, proto)
-struct hostrec *queryctl;
-struct method *proto;
-{
- int ok, len;
- int mboxfd;
- char buf [POPBUFSIZE];
- int socket;
- int first,number,count;
-
- tagnum = 0;
- protocol = proto;
-
- /* open stdout or the mailbox, locking it if it is a folder */
- if (queryctl->output == TO_FOLDER || queryctl->output == TO_STDOUT)
- if ((mboxfd = openuserfolder(queryctl)) < 0)
- return(PS_IOERR);
-
- /* open the socket */
- if ((socket = Socket(queryctl->servername,protocol->port)) < 0) {
- perror("do_protocol: socket");
- ok = PS_SOCKET;
- goto closeUp;
- }
-
- /* accept greeting message from IMAP server */
- ok = imap_ok(buf,socket);
- if (ok != 0) {
- if (ok != PS_SOCKET)
- gen_transact(socket, protocol->exit_cmd);
- close(socket);
- goto closeUp;
- }
-
- /* print the greeting */
- if (outlevel > O_SILENT && outlevel < O_VERBOSE)
- fprintf(stderr,"%s greeting: %s\n", protocol->name, buf);
-
- /* try to get authorized to fetch mail */
- ok = (protocol->getauth)(socket, queryctl, buf);
- if (ok == PS_ERROR)
- ok = PS_AUTHFAIL;
- if (ok != 0)
- goto cleanUp;
-
- /* compute count and first */
- if ((*protocol->getrange)(socket, queryctl, &count, &first) != 0)
- goto cleanUp;
-
- /* show them how many messages we'll be downloading */
- if (outlevel > O_SILENT && outlevel < O_VERBOSE)
- if (first > 1)
- fprintf(stderr,"%d messages in folder, %d new messages.\n",
- count, count - first + 1);
- else
- fprintf(stderr,"%d %smessages in folder.\n", count, ok ? "" : "new ");
-
- 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)) {
- ok = (mboxfd = openmailpipe(queryctl)) < 0 ? -1 : 0;
- if (ok != 0)
- goto cleanUp;
- }
-
- if (queryctl->flush && number < first && !queryctl->fetchall)
- ok = 0; /* no command to send here, will delete message below */
- else
- {
- (*protocol->fetch)(socket, number, linelimit, &len);
- if (outlevel == O_VERBOSE)
- if (protocol->delimited)
- fprintf(stderr,"fetching message %d (delimited)\n",number);
- else
- fprintf(stderr,"fetching message %d (%d bytes)\n",number,len);
- ok = gen_readmsg(socket,mboxfd,len,protocol->delimited,
- queryctl->servername,
- queryctl->output == TO_MDA,
- queryctl->rewrite);
- if (protocol->trail)
- (*protocol->trail)(socket, queryctl, number);
- if (ok != 0)
- goto cleanUp;
- }
-
- /* 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);
- else
- ;
- ok = gen_transact(socket, protocol->delete_cmd, number);
- if (ok != 0)
- goto cleanUp;
- }
-
- /* close the mail pipe, we'll reopen before next message */
- if (queryctl->output == TO_MDA
- && (queryctl->fetchall || number >= first)) {
- ok = closemailpipe(mboxfd);
- if (ok != 0)
- goto cleanUp;
- }
- }
-
- /* remove all messages flagged for deletion */
- if (!queryctl->keep && protocol->expunge_cmd)
- {
- ok = gen_transact(socket, protocol->expunge_cmd);
- if (ok != 0)
- goto cleanUp;
- }
-
- ok = gen_transact(socket, protocol->exit_cmd);
- if (ok == 0)
- ok = PS_SUCCESS;
- close(socket);
- goto closeUp;
- }
- else {
- ok = gen_transact(socket, protocol->exit_cmd);
- if (ok == 0)
- ok = PS_NOMAIL;
- close(socket);
- goto closeUp;
- }
-
-cleanUp:
- if (ok != 0 && ok != PS_SOCKET)
- gen_transact(socket, protocol->exit_cmd);
-
-closeUp:
- if (queryctl->output == TO_FOLDER)
- if (closeuserfolder(mboxfd) < 0 && ok == 0)
- ok = PS_IOERR;
-
- if (ok == PS_IOERR || ok == PS_SOCKET)
- perror("do_protocol: cleanUp");
-
- return(ok);
-}
-
-/*********************************************************************
- function: gen_send
- description: Assemble command in print style and send to the server
-
- arguments:
- socket socket to which the server is connected.
- fmt printf-style format
-
- return value: none.
- calls: SockPuts.
- globals: reads outlevel.
- *********************************************************************/
-
-void gen_send(socket, fmt, va_alist)
-int socket;
-const char *fmt;
-va_dcl {
-
- char buf [POPBUFSIZE];
- va_list ap;
-
- if (protocol->tagged)
- (void) sprintf(buf, "%s ", GENSYM);
- else
- buf[0] = '\0';
-
- va_start(ap);
- vsprintf(buf + strlen(buf), fmt, ap);
- va_end(ap);
-
- SockPuts(socket, buf);
-
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> %s\n", buf);
-}
-
-/*********************************************************************
- function: gen_transact
- description: Assemble command in print style and send to the server.
- then accept a protocol-dependent response.
-
- arguments:
- socket socket to which the server is connected.
- fmt printf-style format
-
- return value: none.
- calls: SockPuts, imap_ok.
- globals: reads outlevel.
- *********************************************************************/
-
-int gen_transact(socket, fmt, va_alist)
-int socket;
-const char *fmt;
-va_dcl {
-
- int ok;
- char buf [POPBUFSIZE];
- va_list ap;
-
- if (protocol->tagged)
- (void) sprintf(buf, "%s ", GENSYM);
- else
- buf[0] = '\0';
-
- va_start(ap);
- vsprintf(buf + strlen(buf), fmt, ap);
- va_end(ap);
-
- SockPuts(socket, buf);
-
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"> %s\n", buf);
-
- ok = (protocol->parse_response)(buf,socket);
- if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
- fprintf(stderr,"%s\n",buf);
-
- return(ok);
-}
-
-/*********************************************************************
- function: gen_readmsg
- description: Read the message content
-
- as described in RFC 1225.
- arguments:
- socket ... to which the server is connected.
- mboxfd open file descriptor to which the retrieved message will
- be written.
- len length of text
- pophost name of the POP host
- topipe true if we're writing to the system mailbox pipe.
-
- return value: zero if success else PS_* return code.
- calls: SockGets.
- globals: reads outlevel.
- *********************************************************************/
-
-int gen_readmsg (socket,mboxfd,len,delimited,pophost,topipe,rewrite)
-int socket;
-int mboxfd;
-long len;
-int delimited;
-char *pophost;
-int topipe;
-int rewrite;
-{
- char buf [MSGBUFSIZE];
- char *bufp;
- char savec;
- char fromBuf[MSGBUFSIZE];
- int n;
- int needFrom;
- int inheaders;
- int lines,sizeticker;
- time_t now;
- /* This keeps the retrieved message count for display purposes */
- static int msgnum = 0;
-
- /* set up for status message if outlevel allows it */
- if (outlevel > O_SILENT && outlevel < O_VERBOSE) {
- fprintf(stderr,"reading message %d",++msgnum);
- /* won't do the '...' if retrieved messages are being sent to stdout */
- if (mboxfd == 1)
- fputs(".\n",stderr);
- else
- ;
- }
- else
- ;
-
- /* read the message content from the server */
- inheaders = 1;
- lines = 0;
- sizeticker = MSGBUFSIZE;
- while (delimited || len > 0) {
- if ((n = SockGets(socket,buf,sizeof(buf))) < 0)
- return(PS_SOCKET);
- len -= n;
- if (outlevel == O_VERBOSE)
- (void) fprintf(stderr, "%s\n", buf);
- bufp = buf;
- if (buf[0] == '\r' || buf[0] == '\n')
- inheaders = 0;
- if (*bufp == '.') {
- bufp++;
- if (delimited && *bufp == 0)
- break; /* end of message */
- }
- strcat(bufp,"\n");
-
- /* Check for Unix 'From' header, and add a bogus one if it's not
- present -- only if not using an MDA.
- XXX -- should probably parse real From: header and use its
- address field instead of bogus 'POPmail' string.
- */
- if (!topipe && lines == 0) {
- if (strlen(bufp) >= strlen("From ")) {
- savec = *(bufp + 5);
- *(bufp + 5) = 0;
- needFrom = strcmp(bufp,"From ") != 0;
- *(bufp + 5) = savec;
- }
- else
- needFrom = 1;
- if (needFrom) {
- now = time(NULL);
- sprintf(fromBuf,"From POPmail %s",ctime(&now));
- if (write(mboxfd,fromBuf,strlen(fromBuf)) < 0) {
- perror("gen_readmsg: write");
- return(PS_IOERR);
- }
- }
- }
-
- /*
- * Edit some headers so that replies will work properly.
- */
- if (inheaders && rewrite)
- reply_hack(bufp, pophost);
-
- /* write this line to the file */
- if (write(mboxfd,bufp,strlen(bufp)) < 0) {
- perror("gen_readmsg: write");
- return(PS_IOERR);
- }
-
- sizeticker -= strlen(bufp);
- if (sizeticker <= 0) {
- if (outlevel > O_SILENT && outlevel < O_VERBOSE && mboxfd != 1)
- fputc('.',stderr);
- sizeticker = MSGBUFSIZE;
- }
- lines++;
- }
-
- if (!topipe) {
- /* The server may not write the extra newline required by the Unix
- mail folder format, so we write one here just in case */
- if (write(mboxfd,"\n",1) < 0) {
- perror("gen_readmsg: write");
- return(PS_IOERR);
- }
- }
- else {
- /* The mail delivery agent may require a terminator. Write it if
- it has been defined */
-#ifdef BINMAIL_TERM
- if (write(mboxfd,BINMAIL_TERM,strlen(BINMAIL_TERM)) < 0) {
- perror("gen_readmsg: write");
- return(PS_IOERR);
- }
-#endif
- }
-
- /* finish up display output */
- if (outlevel == O_VERBOSE)
- fprintf(stderr,"(%d lines of message content)\n",lines);
- else if (outlevel > O_SILENT && mboxfd != 1)
- fputs(".\n",stderr);
- else
- ;
- return(0);
-}
diff --git a/pop3.c b/pop3.c
index a8a96cbe..0965b47b 100644
--- a/pop3.c
+++ b/pop3.c
@@ -41,6 +41,232 @@ int POP3_BuildDigest (char *buf, struct hostrec *options);
/*********************************************************************
+
+ Method declarations for POP3
+
+ *********************************************************************/
+
+int pop3_ok (argbuf,socket)
+/* parse command response */
+char *argbuf;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+ char *bufp;
+
+ if (SockGets(socket, buf, sizeof(buf)) >= 0) {
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+
+ bufp = buf;
+ if (*bufp == '+' || *bufp == '-')
+ bufp++;
+ else
+ return(PS_PROTOCOL);
+
+ while (isalpha(*bufp))
+ bufp++;
+ *(bufp++) = '\0';
+
+ if (strcmp(buf,"+OK") == 0)
+ ok = 0;
+ else if (strcmp(buf,"-ERR") == 0)
+ ok = PS_ERROR;
+ else
+ ok = PS_PROTOCOL;
+
+ if (argbuf != NULL)
+ strcpy(argbuf,bufp);
+ }
+ else
+ ok = PS_SOCKET;
+
+ return(ok);
+}
+
+int pop3_getauth(socket, queryctl, greeting)
+/* apply for connection authorization */
+int socket;
+struct hostrec *queryctl;
+char *greeting;
+{
+ char buf [POPBUFSIZE];
+
+#if defined(HAVE_APOP_SUPPORT)
+ /* build MD5 digest from greeting timestamp + password */
+ if (queryctl->whichpop == P_APOP)
+ if (POP3_BuildDigest(greeting,queryctl) != 0) {
+ return(PS_AUTHFAIL);
+ }
+#endif
+
+ switch (queryctl->protocol) {
+ case P_POP3:
+ SockPrintf(socket,"USER %s\r\n",queryctl->remotename);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> USER %s\n",queryctl->remotename);
+ if (pop3_ok(buf,socket) != 0)
+ goto badAuth;
+
+ SockPrintf(socket,"PASS %s\r\n",queryctl->password);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> PASS password\n");
+ if (pop3_ok(buf,socket) != 0)
+ goto badAuth;
+
+ break;
+
+#if defined(HAVE_APOP_SUPPORT)
+ case P_APOP:
+ SockPrintf(socket,"APOP %s %s\r\n",
+ queryctl->remotename, queryctl->digest);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> APOP %s %s\n",queryctl->remotename, queryctl->digest);
+ if (pop3_ok(buf,socket) != 0)
+ goto badAuth;
+ break;
+#endif /* HAVE_APOP_SUPPORT */
+
+#if defined(HAVE_RPOP_SUPPORT)
+ case P_RPOP:
+ SockPrintf(socket, "RPOP %s\r\n", queryctl->remotename);
+ if (pop3_ok(buf,socket) != 0)
+ goto badAuth;
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> RPOP %s %s\n",queryctl->remotename);
+ break;
+#endif /* HAVE_RPOP_SUPPORT */
+
+ default:
+ fprintf(stderr,"Undefined protocol request in POP3_auth\n");
+ }
+
+ /* we're approved */
+ return(0);
+
+ /*NOTREACHED*/
+
+badAuth:
+ if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ; /* say nothing */
+
+ return(PS_ERROR);
+}
+
+static int use_uidl;
+
+static pop3_getrange(socket, queryctl, countp, firstp)
+/* get range of messages to be fetched */
+int socket;
+struct hostrec *queryctl;
+int *countp;
+int *firstp;
+{
+ int ok;
+
+ ok = POP3_sendSTAT(countp,socket);
+ if (ok != 0) {
+ return(ok);
+ }
+
+ /*
+ * 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. Instead, send
+ * UIDL and try to find the last received ID stored for this host in
+ * the list we get back.
+ */
+ *firstp = 1;
+ use_uidl = 0;
+ if (!queryctl->fetchall) {
+ char buf [POPBUFSIZE];
+ char id [IDLEN];
+ int num;
+
+ /* try LAST first */
+ ok = POP3_sendLAST(firstp, 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)
+ *firstp = num;
+ }
+ }
+ }
+
+ if (ok == 0)
+ (*firstp)++;
+ }
+
+ return(0);
+}
+
+static int pop3_fetch(socket, number, limit, lenp)
+/* request nth message */
+int socket;
+int number;
+int limit;
+int *lenp;
+{
+ *lenp = 0;
+ if (limit)
+ return(gen_transact(socket, "TOP %d %d", number, limit));
+ else
+ return(gen_transact(socket, "RETR %d", number));
+}
+
+static pop3_trail(socket, queryctl, number)
+/* update the last-seen field for this host */
+int socket;
+struct hostrec *queryctl;
+int number;
+{
+ char *cp;
+ int ok = 0;
+
+ if (use_uidl && (ok = POP3_sendUIDL(number, socket, &cp)) == 0)
+ (void) strcpy(queryctl->lastid, cp);
+ return(ok);
+}
+
+static struct method pop3 =
+{
+ "POP3", /* Post Office Protocol v3 */
+ 110, /* standard POP3 port */
+ 0, /* this is not a tagged protocol */
+ 1, /* this uses a message delimiter */
+ pop3_ok, /* parse command response */
+ pop3_getauth, /* get authorization */
+ pop3_getrange, /* query range of messages */
+ pop3_fetch, /* request given message */
+ pop3_trail, /* eat message trailer */
+ "DELE %d", /* set POP3 delete flag */
+ NULL, /* the POP3 expunge command */
+ "QUIT", /* the POP3 exit command */
+};
+
+int doPOP3bis (queryctl)
+/* retrieve messages using POP3 */
+struct hostrec *queryctl;
+{
+ return(do_protocol(queryctl, &pop3));
+}
+
+/*********************************************************************
function: POP3_sendSTAT
description: send the STAT command to the POP3 server to find
out how many messages are waiting.