aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-06-24 19:00:51 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-06-24 19:00:51 +0000
commitcf227f48438b78f4cd72451c9b501b21b36fcf7c (patch)
tree18596fdaf30cad2d870ce8dac8ae2e1de4ad2192
parent6124abb8368c51b6d568fd362078509c464a617c (diff)
downloadfetchmail-cf227f48438b78f4cd72451c9b501b21b36fcf7c.tar.gz
fetchmail-cf227f48438b78f4cd72451c9b501b21b36fcf7c.tar.bz2
fetchmail-cf227f48438b78f4cd72451c9b501b21b36fcf7c.zip
Initial revision
svn path=/trunk/; revision=3
-rw-r--r--pop2.c611
-rw-r--r--pop3.c781
2 files changed, 1392 insertions, 0 deletions
diff --git a/pop2.c b/pop2.c
new file mode 100644
index 00000000..3323fda1
--- /dev/null
+++ b/pop2.c
@@ -0,0 +1,611 @@
+/* Copyright 1993-95 by Carl Harris, Jr.
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Carl Harris <ceharris@mal.com>
+ */
+
+
+/***********************************************************************
+ module: pop2.c
+ project: popclient
+ programmer: Carl Harris, ceharris@mal.com
+ description: POP2 client code.
+
+ $Log: pop2.c,v $
+ Revision 1.1 1996/06/24 19:00:51 esr
+ Initial revision
+
+ Revision 1.6 1995/08/14 18:36:40 ceharris
+ Patches to support POP3's LAST command.
+ Final revisions for beta3 release.
+
+ Revision 1.5 1995/08/10 00:32:36 ceharris
+ Preparation for 3.0b3 beta release:
+ - added code for --kill/--keep, --limit, --protocol, --flush
+ options; --pop2 and --pop3 options now obsoleted by --protocol.
+ - added support for APOP authentication, including --with-APOP
+ argument for configure.
+ - provisional and broken support for RPOP
+ - added buffering to SockGets and SockRead functions.
+ - fixed problem of command-line options not being correctly
+ carried into the merged options record.
+
+ Revision 1.4 1995/08/09 01:32:53 ceharris
+ Version 3.0 beta 2 release.
+ Added
+ - .poprc functionality
+ - GNU long options
+ - multiple servers on the command line.
+ Fixed
+ - Passwords showing up in ps output.
+
+ Revision 1.3 1995/08/08 01:01:22 ceharris
+ Added GNU-style long options processing.
+ Fixed password in 'ps' output problem.
+ Fixed various RCS tag blunders.
+ Integrated .poprc parser, lexer, etc into Makefile processing.
+
+ ***********************************************************************/
+
+#include <config.h>
+
+#include <stdio.h>
+#if defined(STDC_HEADERS)
+#include <string.h>
+#endif
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/time.h>
+#include <errno.h>
+
+#include "socket.h"
+#include "popclient.h"
+
+
+/* TCP port number for POP2 as defined by RFC 937 */
+#define POP2_PORT 109
+
+#if HAVE_PROTOTYPES
+/* prototypes for internal functions */
+int POP2_sendcmd (char *cmd, int socket);
+int POP2_sendHELO (char *userid, char *password, int socket);
+int POP2_sendFOLD (char *folder, int socket);
+int POP2_quit (int socket);
+int POP2_stateGREET (int socket);
+int POP2_stateNMBR (int socket);
+int POP2_stateSIZE (int socket);
+int POP2_stateXFER (int msgsize, int socket, int mboxfd, int topipe);
+#endif
+
+
+/*********************************************************************
+ function: doPOP2
+ description: retrieve messages from the specified mail server
+ using Post Office Protocol 2.
+
+ arguments:
+ servername name of the server to which we'll connect.
+ options fully-specified options (i.e. parsed, defaults invoked,
+ etc).
+
+ return value: exit code from the set of PS_.* constants defined in
+ popclient.h
+ calls: POP2_stateGREET, POP2_stateNMBR, POP2_stateSIZE,
+ POP2_stateXFER, POP2_sendcmd, POP2_sendHELO,
+ POP2_sendFOLD, POP2_quit, Socket, openuserfolder,
+ closeuserfolder, openmailpipe, closemailpipe.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int doPOP2 (servername,options)
+char *servername;
+struct optrec *options;
+{
+ int mboxfd;
+ int socket;
+ int number,msgsize,actsize;
+ int status = PS_UNDEFINED;
+
+ /* check for unsupported options */
+ if (options->limit) {
+ fprintf(stderr,"Option --limit is not supported in POP2\n");
+ return(PS_SYNTAX);
+ }
+ else if (options->flush) {
+ fprintf(stderr,"Option --flush is not supported in POP2\n");
+ return(PS_SYNTAX);
+ }
+ else if (options->fetchall) {
+ fprintf(stderr,"Option --all is not supported in POP2\n");
+ return(PS_SYNTAX);
+ }
+ else
+ ;
+
+ /* open the socket to the POP server */
+ if ((socket = Socket(servername,POP2_PORT)) < 0) {
+ perror("doPOP2: socket");
+ return(PS_SOCKET);
+ }
+
+ /* open/lock the folder if it is a user folder or stdout */
+ if (options->foldertype != OF_SYSMBOX)
+ if ((mboxfd = openuserfolder(options)) < 0)
+ return(PS_IOERR);
+
+ /* wait for the POP2 greeting */
+ if (POP2_stateGREET(socket) != 0) {
+ POP2_quit(socket);
+ return(PS_PROTOCOL);
+ }
+
+ /* log the user onto the server */
+ POP2_sendHELO(options->userid,options->password,socket);
+ if ((number = POP2_stateNMBR(socket)) < 0) {
+ POP2_quit(socket);
+ return(PS_AUTHFAIL);
+ }
+
+ /* set the remote folder if selected */
+ if (*options->remotefolder != 0) {
+ POP2_sendFOLD(options->remotefolder,socket);
+ if ((number = POP2_stateNMBR(socket)) < 0) {
+ POP2_quit(socket);
+ return(PS_PROTOCOL);
+ }
+ }
+
+ /* tell 'em how many messages are waiting */
+ if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%d messages in folder %s\n",number,options->remotefolder);
+ else
+ ;
+
+ /* fall into a retrieve/acknowledge loop */
+ if (number > 0) {
+
+ POP2_sendcmd("READ",socket);
+ msgsize = POP2_stateSIZE(socket);
+ while (msgsize > 0) {
+
+ /* open the pipe */
+ if (options->foldertype == OF_SYSMBOX)
+ if ((mboxfd = openmailpipe(options)) < 0) {
+ POP2_quit(socket);
+ return(PS_IOERR);
+ }
+
+ POP2_sendcmd("RETR",socket);
+ actsize = POP2_stateXFER(msgsize,socket,mboxfd,
+ options->foldertype == OF_SYSMBOX);
+ if (actsize == msgsize)
+ if (options->keep)
+ POP2_sendcmd("ACKS",socket);
+ else
+ POP2_sendcmd("ACKD",socket);
+ else if (actsize >= 0)
+ POP2_sendcmd("NACK",socket);
+ else {
+ POP2_quit(socket);
+ return(PS_SOCKET);
+ }
+
+ /* close the pipe */
+ if (options->foldertype == OF_SYSMBOX)
+ if (closemailpipe(mboxfd) < 0) {
+ POP2_quit(socket);
+ return(PS_IOERR);
+ }
+
+ msgsize = POP2_stateSIZE(socket);
+ }
+ POP2_quit(socket);
+ status = msgsize == 0 ? PS_SUCCESS : PS_PROTOCOL;
+ }
+ else {
+ POP2_quit(socket);
+ status = PS_NOMAIL;
+ }
+
+ if (options->foldertype != OF_SYSMBOX)
+ closeuserfolder(mboxfd);
+
+ return(status);
+}
+
+
+
+/*********************************************************************
+ function: POP2_sendcmd
+ description: send a command string (with no arguments) a server.
+ arguments:
+ cmd command string to send.
+ socket socket to which the server is connected.
+
+ return value: none.
+ calls: SockPuts.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_sendcmd (cmd,socket)
+char *cmd;
+int socket;
+{
+ SockPuts(socket,cmd);
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> %s\n",cmd);
+ else
+ ;
+}
+
+
+/*********************************************************************
+ function: POP2_sendHELO
+ description: send the HELO command to the server.
+ arguments:
+ userid user's mailserver id.
+ password user's mailserver password.
+ socket socket to which the server is connected.
+
+ return value: none.
+ calls: SockPrintf.
+ globals: read outlevel.
+ *********************************************************************/
+
+int POP2_sendHELO (userid,password,socket)
+char *userid, *password;
+int socket;
+{
+ SockPrintf(socket,"HELO %s %s\r\n",userid,password);
+
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> HELO %s password\n",userid);
+ else
+ ;
+}
+
+
+/*********************************************************************
+ function: POP2_sendFOLD
+ description: send the FOLD command to the server.
+ arguments:
+ folder name of the folder to open on the server.
+ socket socket to which the server is connected.
+
+ return value: none.
+ calls: SockPrintf.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_sendFOLD (folder,socket)
+char *folder;
+int socket;
+{
+ SockPrintf(socket,"FOLD %s\r\n",folder);
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> FOLD %s\n",folder);
+ else
+ ;
+}
+
+
+/*********************************************************************
+ function: POP2_quit
+ description: send the QUIT command to the server and close
+ the socket.
+
+ arguments:
+ socket socket to which the server is connected.
+
+ return value: none.
+ calls: SockPuts.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_quit (socket)
+int socket;
+{
+ SockPuts(socket,"QUIT");
+ close(socket);
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> QUIT\n");
+ else
+ ;
+}
+
+
+/*********************************************************************
+ function: POP2_stateGREET
+ description: process the GREET state as described in RFC 937.
+ arguments:
+ socket ...to which server is connected.
+
+ return value: zero if server's handling of the GREET state was
+ correct, else non-zero (may indicate difficulty
+ at the socket).
+ calls: SockGets.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_stateGREET (socket)
+int socket;
+{
+ char buf [POPBUFSIZE];
+
+ /* read the greeting from the server */
+ if (SockGets(socket, buf, sizeof(buf)) == 0) {
+
+ /* echo the server's greeting to the user */
+ if (outlevel > O_SILENT)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+ /* is the greeting in the correct format? */
+ if (*buf == '+')
+ return(0);
+ else
+ return(-1);
+ }
+ else {
+ /* an error at the socket */
+ if (outlevel > O_SILENT)
+ perror("error reading socket\n");
+ else
+ ;
+ return(-1);
+ }
+}
+
+
+/*********************************************************************
+ function: POP2_stateNMBR
+ description: process the NMBR state as described in RFC 937.
+ arguments:
+ socket ...to which the server is connected.
+
+ return value: zero if the expected NMBR state action occured, else
+ non-zero. Following HELO, a non-zero return value
+ usually here means the user authorization at the server
+ failed.
+ calls: SockGets.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_stateNMBR (socket)
+int socket;
+{
+ int number;
+ char buf [POPBUFSIZE];
+
+ /* read the NMBR (#ccc) message from the server */
+ if (SockGets(socket, buf, sizeof(buf)) == 0) {
+
+ /* is the message in the proper format? */
+ if (*buf == '#') {
+ number = atoi(buf + 1);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+ }
+ else {
+ number = -1;
+ if (outlevel > O_SILENT)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+ }
+ }
+ else {
+ /* socket problem */
+ number = -1;
+ if (outlevel == O_VERBOSE)
+ perror("socket read error\n");
+ else
+ ;
+ }
+ return(number);
+}
+
+
+/*********************************************************************
+ function: POP2_stateSIZE
+ description: process the SIZE state as described in RFC 937.
+ arguments:
+ socket ...to which the server is connected.
+
+ return value: zero if the expected SIZE state action occured, else
+ non-zero (usually indicates a protocol violation).
+ calls: SockGets.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_stateSIZE (socket)
+int socket;
+{
+ int msgsize;
+ char buf [POPBUFSIZE];
+
+ /* read the SIZE message (=ccc) from the server */
+ if (SockGets(socket, buf, sizeof(buf)) == 0)
+ /* is the message in the correct format? */
+ if (*buf == '=') {
+ msgsize = atoi(buf + 1);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+ }
+ else {
+ msgsize = -1;
+ if (outlevel > O_SILENT)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+ }
+ else {
+ /* socket problem */
+ msgsize = -1;
+ if (outlevel == O_VERBOSE)
+ perror("socket read error\n");
+ else
+ ;
+ }
+
+ return(msgsize);
+}
+
+
+/*********************************************************************
+ function: POP2_stateXFER
+ description: process the XFER state as described in RFC 937.
+ arguments:
+ msgsize content length of the message as reported in the
+ SIZE state.
+ socket ... to which the server is connected.
+ mboxfd open file descriptor to which the retrieved message will
+ be written.
+ topipe true if we're writing to a the /bin/mail pipe.
+
+ return value:
+ >= 0 actual length of the message received.
+ < 0 socket I/O problem.
+
+ calls: SockRead.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP2_stateXFER (msgsize,socket,mboxfd,topipe)
+int msgsize;
+int socket;
+int mboxfd;
+int topipe;
+{
+ int i,buflen,actsize;
+ char buf [MSGBUFSIZE];
+ char frombuf [MSGBUFSIZE];
+ char savec;
+ int msgTop;
+ int needFrom;
+
+ 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) /* we're writing to stdout */
+ fputs(".\n",stderr);
+ else
+ ;
+ }
+ else
+ ;
+
+
+ /* read the specified message content length from the server */
+ actsize = 0;
+ msgTop = !0;
+ while (msgsize > 0) {
+ buflen = msgsize <= MSGBUFSIZE ? msgsize : MSGBUFSIZE;
+ /* read a bufferful */
+ if (SockRead(socket, buf, buflen) == 0) {
+
+ /* Check for Unix 'From' header, and add 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 && msgTop) {
+ msgTop = 0;
+ if (strlen(buf) >= strlen("From ")) {
+ savec = *(buf + 5);
+ *(buf + 5) = 0;
+ needFrom = strcmp(buf,"From ") != 0;
+ *(buf + 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("POP2_stateXFER: write");
+ return(-1);
+ }
+ }
+ }
+
+ /* write to folder, stripping CR chars in the process */
+ for (i = 0; i < buflen; i++)
+ if (*(buf + i) != '\r')
+ if (write(mboxfd,buf + i,1) < 0) {
+ perror("POP2_stateXFER: write");
+ return(-1);
+ }
+ else
+ ; /* it was written */
+ else
+ ; /* ignore CR character */
+ }
+ else
+ return(-1); /* socket problem */
+
+ /* write another . for every bufferful received */
+ if (outlevel > O_SILENT && outlevel < O_VERBOSE && mboxfd != 1)
+ fputc('.',stderr);
+ else
+ ;
+ msgsize -= buflen;
+ actsize += buflen;
+ }
+
+ 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) < 1) {
+ perror("POP2_stateXFER: write");
+ return(-1);
+ }
+ }
+ else {
+ /* the mailer might require some sort of termination string, send
+ it if it is defined */
+#ifdef BINMAIL_TERM
+ if (write(mboxfd,BINMAIL_TERM,strlen(BINMAIL_TERM)) < 0) {
+ perror("POP2_stateXFER: write");
+ return(-1);
+ }
+#endif
+ }
+
+ /* finish up display output */
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"(%d characters of message content)\n",actsize);
+ else if (outlevel > O_SILENT && mboxfd != 0)
+ fputc('\n',stderr);
+ else
+ ;
+
+ return(actsize);
+}
diff --git a/pop3.c b/pop3.c
new file mode 100644
index 00000000..514edab8
--- /dev/null
+++ b/pop3.c
@@ -0,0 +1,781 @@
+/* Copyright 1993-95 by Carl Harris, Jr.
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice. May be sold if buildable source is provided to buyer. No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
+ * I'll try to keep a version up to date. I can be reached as follows:
+ * Carl Harris <ceharris@mal.com>
+ */
+
+
+/***********************************************************************
+ module: pop3.c
+ project: popclient
+ programmer: Carl Harris, ceharris@mal.com
+ description: POP3 client code.
+
+ $Log: pop3.c,v $
+ Revision 1.1 1996/06/24 18:56:35 esr
+ Initial revision
+
+ Revision 1.6 1995/08/14 18:36:42 ceharris
+ Patches to support POP3's LAST command.
+ Final revisions for beta3 release.
+
+ Revision 1.5 1995/08/10 00:32:38 ceharris
+ Preparation for 3.0b3 beta release:
+ - added code for --kill/--keep, --limit, --protocol, --flush
+ options; --pop2 and --pop3 options now obsoleted by --protocol.
+ - added support for APOP authentication, including --with-APOP
+ argument for configure.
+ - provisional and broken support for RPOP
+ - added buffering to SockGets and SockRead functions.
+ - fixed problem of command-line options not being correctly
+ carried into the merged options record.
+
+ Revision 1.4 1995/08/09 01:32:54 ceharris
+ Version 3.0 beta 2 release.
+ Added
+ - .poprc functionality
+ - GNU long options
+ - multiple servers on the command line.
+ Fixed
+ - Passwords showing up in ps output.
+
+ Revision 1.3 1995/08/08 01:01:24 ceharris
+ Added GNU-style long options processing.
+ Fixed password in 'ps' output problem.
+ Fixed various RCS tag blunders.
+ Integrated .poprc parser, lexer, etc into Makefile processing.
+
+ ***********************************************************************/
+
+#include <config.h>
+
+#include <stdio.h>
+#if defined(STDC_HEADERS)
+#include <string.h>
+#endif
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <sys/time.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "socket.h"
+#include "popclient.h"
+
+#define POP3_PORT 110
+
+#ifdef HAVE_PROTOTYPES
+/* prototypes for internal functions */
+int POP3_OK (char *buf, int socket);
+int POP3_auth (struct optrec *options, int socket);
+int POP3_sendQUIT (int socket);
+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_readmsg (int socket, int mboxfd, int topipe);
+int POP3_BuildDigest (char *buf, struct optrec *options);
+#endif
+
+
+/*********************************************************************
+ function: doPOP3
+ description: retrieve messages from the specified mail server
+ using Post Office Protocol 3.
+
+ arguments:
+ servername name of server to which we'll connect.
+ options fully-specified options (i.e. parsed, defaults invoked,
+ etc).
+
+ return value: exit code from the set of PS_.* constants defined in
+ popclient.h
+ calls:
+ globals: reads outlevel.
+ *********************************************************************/
+
+int doPOP3 (servername,options)
+char *servername;
+struct optrec *options;
+{
+ int ok;
+ int mboxfd;
+ char buf [POPBUFSIZE];
+ int socket;
+ int first,number,count;
+
+
+ /* open the folder if we're not using the system mailbox */
+ if (options->foldertype != OF_SYSMBOX)
+ if ((mboxfd = openuserfolder(options)) < 0)
+ return(PS_IOERR);
+
+ /* open the socket and get the greeting */
+ if ((socket = Socket(servername,POP3_PORT)) < 0) {
+ perror("doPOP3: socket");
+ return(PS_SOCKET);
+ }
+
+ ok = POP3_OK(buf,socket);
+ if (ok != 0) {
+ if (ok != PS_SOCKET)
+ POP3_sendQUIT(socket);
+ close(socket);
+ return(ok);
+ }
+
+ /* print the greeting */
+ if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+ else
+ ;
+
+#if defined(HAVE_APOP_SUPPORT)
+ /* build MD5 digest from greeting timestamp + password */
+ if (options->whichpop == P_APOP)
+ if (POP3_BuildDigest(buf,options) != 0)
+ return(PS_AUTHFAIL);
+ else
+ ;
+ else
+ ; /* not using APOP protocol this time */
+#endif
+
+ /* try to get authorized */
+ ok = POP3_auth(options,socket);
+ if (ok == PS_ERROR)
+ ok = PS_AUTHFAIL;
+ if (ok != 0)
+ goto cleanUp;
+
+ /* find out how many messages are waiting */
+ ok = POP3_sendSTAT(&count,socket);
+ if (ok != 0) {
+ goto cleanUp;
+ }
+
+ /* Ask for number of last message retrieved */
+ if (options->fetchall)
+ first = 1;
+ else {
+ ok = POP3_sendLAST(&first, socket);
+ if (ok != 0)
+ goto cleanUp;
+
+ first++;
+ }
+
+ /* 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 new messages in folder.\n", count);
+ else
+ ;
+
+ if (count > 0) {
+ for (number = (options->flush || options->fetchall)? 1 : first;
+ number <= count;
+ number++) {
+
+ /* open the mail pipe if we're using the system mailbox */
+ if (options->foldertype == OF_SYSMBOX
+ && (options->fetchall || number >= first)) {
+ ok = (mboxfd = openmailpipe(options)) < 0 ? -1 : 0;
+ if (ok != 0)
+ goto cleanUp;
+ }
+
+ if (options->flush && number < first && !options->fetchall)
+ ok = 0; /* no command to send here, will delete message below */
+ else if (options->limit)
+ ok = POP3_sendTOP(number,options->limit,socket);
+ else
+ ok = POP3_sendRETR(number,socket);
+ if (ok != 0)
+ goto cleanUp;
+
+ if (number >= first || options->fetchall)
+ ok = POP3_readmsg(socket,mboxfd,options->foldertype == OF_SYSMBOX);
+ else
+ ok = 0;
+ if (ok != 0)
+ goto cleanUp;
+
+ if ((number < first && options->flush) || !options->keep) {
+ if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"flushing message %d\n", number);
+ else
+ ;
+ ok = POP3_sendDELE(number,socket);
+ if (ok != 0)
+ goto cleanUp;
+ }
+ else
+ ; /* message is kept */
+
+ /* close the mail pipe if we're using the system mailbox */
+ if (options->foldertype == OF_SYSMBOX
+ && (options->fetchall || number >= first)) {
+ ok = closemailpipe(mboxfd);
+ if (ok != 0)
+ goto cleanUp;
+ }
+ }
+
+ ok = POP3_sendQUIT(socket);
+ if (ok == 0)
+ ok = PS_SUCCESS;
+ close(socket);
+ return(ok);
+ }
+ else {
+ ok = POP3_sendQUIT(socket);
+ if (ok == 0)
+ ok = PS_NOMAIL;
+ close(socket);
+ return(ok);
+ }
+
+cleanUp:
+ if (ok != 0 && ok != PS_SOCKET)
+ POP3_sendQUIT(socket);
+
+ if (options->foldertype != OF_SYSMBOX)
+ if (closeuserfolder(mboxfd) < 0 && ok == 0)
+ ok = PS_IOERR;
+
+ if (ok == PS_IOERR || ok == PS_SOCKET)
+ perror("doPOP3: cleanUp");
+
+ return(ok);
+}
+
+
+
+/*********************************************************************
+ function: POP3_OK
+ description: get the server's response to a command, and return
+ the extra arguments sent with the response.
+ arguments:
+ argbuf buffer to receive the argument string.
+ socket socket to which the server is connected.
+
+ return value: zero if okay, else return code.
+ calls: SockGets
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_OK (argbuf,socket)
+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);
+}
+
+
+
+/*********************************************************************
+ function: POP3_auth
+ description: send the USER and PASS commands to the server, and
+ get the server's response.
+ arguments:
+ options merged options record.
+ socket socket to which the server is connected.
+
+ return value: zero if success, else status code.
+ calls: SockPrintf, POP3_OK.
+ globals: read outlevel.
+ *********************************************************************/
+
+int POP3_auth (options,socket)
+struct optrec *options;
+int socket;
+{
+ char buf [POPBUFSIZE];
+
+ switch (options->whichpop) {
+ case P_POP3:
+ SockPrintf(socket,"USER %s\r\n",options->userid);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> USER %s\n",options->userid);
+ if (POP3_OK(buf,socket) != 0)
+ goto badAuth;
+
+ SockPrintf(socket,"PASS %s\r\n",options->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",
+ options->userid, options->digest);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> APOP %s %s\n",options->userid, options->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", options->userid);
+ if (POP3_OK(buf,socket) != 0)
+ goto badAuth;
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> RPOP %s %s\n",options->userid);
+ 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);
+}
+
+
+
+
+/*********************************************************************
+ function: POP3_sendQUIT
+ description: send the QUIT command to the server and close
+ the socket.
+
+ arguments:
+ socket socket to which the server is connected.
+
+ return value: none.
+ calls: SockPuts, POP3_OK.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_sendQUIT (socket)
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+
+ SockPuts(socket,"QUIT");
+
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> QUIT\n");
+ else
+ ;
+
+ ok = POP3_OK(buf,socket);
+ if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+
+ return(ok);
+}
+
+
+
+/*********************************************************************
+ function: POP3_sendSTAT
+ description: send the STAT command to the POP3 server to find
+ out how many messages are waiting.
+ arguments:
+ count pointer to an integer to receive the message count.
+ socket socket to which the POP3 server is connected.
+
+ return value: return code from POP3_OK.
+ calls: POP3_OK, SockPrintf
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_sendSTAT (msgcount,socket)
+int *msgcount;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+ int totalsize;
+
+ SockPrintf(socket,"STAT\r\n");
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> STAT\n");
+
+ ok = POP3_OK(buf,socket);
+ if (ok == 0)
+ sscanf(buf,"%d %d",msgcount,&totalsize);
+ else if (outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+
+ return(ok);
+}
+
+
+
+
+/*********************************************************************
+ function: POP3_sendRETR
+ description: send the RETR command to the POP3 server.
+ arguments:
+ msgnum message ID number
+ socket socket to which the POP3 server is connected.
+
+ return value: return code from POP3_OK.
+ calls: POP3_OK, SockPrintf
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_sendRETR (msgnum,socket)
+int msgnum;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+
+ SockPrintf(socket,"RETR %d\r\n",msgnum);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> RETR %d\n",msgnum);
+
+ ok = POP3_OK(buf,socket);
+ if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+
+ return(ok);
+}
+
+
+/*********************************************************************
+ function: POP3_sendTOP
+ description: send the TOP command to the POP3 server.
+ arguments:
+ msgnum message ID number
+ limit maximum number of message body lines to retrieve.
+ socket socket to which the POP3 server is connected.
+
+ return value: return code from POP3_OK.
+ calls: POP3_OK, SockPrintf
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_sendTOP (msgnum,limit,socket)
+int msgnum;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+
+ SockPrintf(socket,"TOP %d %d\r\n",msgnum,limit);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> TOP %d %d\n",msgnum,limit);
+
+ ok = POP3_OK(buf,socket);
+ if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"option --limit failed; server says '%s'\n",buf);
+
+ return(ok);
+}
+
+
+
+
+/*********************************************************************
+ function: POP3_sendDELE
+ description: send the DELE command to the POP3 server.
+ arguments:
+ msgnum message ID number
+ socket socket to which the POP3 server is connected.
+
+ return value: return code from POP3_OK.
+ calls: POP3_OK, SockPrintF.
+ globals: reads outlevel.
+ *********************************************************************/
+
+int POP3_sendDELE (msgnum,socket)
+int msgnum;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+
+ SockPrintf(socket,"DELE %d\r\n",msgnum);
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> DELE %d\n",msgnum);
+
+ ok = POP3_OK(buf,socket);
+ if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
+ fprintf(stderr,"%s\n",buf);
+
+ return(ok);
+}
+
+
+
+/*********************************************************************
+ function: POP3_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.
+ 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 POP3_readmsg (socket,mboxfd,topipe)
+int socket;
+int mboxfd;
+int topipe;
+{
+ char buf [MSGBUFSIZE];
+ char *bufp;
+ char savec;
+ char fromBuf[MSGBUFSIZE];
+ int needFrom;
+ 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 */
+ lines = 0;
+ sizeticker = MSGBUFSIZE;
+ while (1) {
+ if (SockGets(socket,buf,sizeof(buf)) < 0)
+ return(PS_SOCKET);
+ bufp = buf;
+ if (*bufp == '.') {
+ bufp++;
+ if (*bufp == 0)
+ break; /* end of message */
+ }
+ strcat(bufp,"\n");
+
+ /* Check for Unix 'From' header, and 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("POP3_readmsg: write");
+ return(PS_IOERR);
+ }
+ }
+ }
+
+ /* write this line to the file */
+ if (write(mboxfd,bufp,strlen(bufp)) < 0) {
+ perror("POP3_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("POP3_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("POP3_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);
+}
+
+
+
+
+/******************************************************************
+ function: POP3_sendLAST
+ description: send the LAST command to the server, which should
+ return the number of the last message number retrieved
+ from the server.
+ arguments:
+ last integer buffer to receive last message#
+
+ ret. value: non-zero on success, else zero.
+ globals: SockPrintf, POP3_OK.
+ calls: reads outlevel.
+ *****************************************************************/
+
+int POP3_sendLAST (last, socket)
+int *last;
+int socket;
+{
+ int ok;
+ char buf [POPBUFSIZE];
+
+ SockPrintf(socket,"LAST\r\n");
+ if (outlevel == O_VERBOSE)
+ fprintf(stderr,"> LAST\n");
+
+ ok = POP3_OK(buf,socket);
+ if (ok == 0 && sscanf(buf,"%d",last) == 0)
+ ok = PS_ERROR;
+
+ if (ok != 0 && outlevel > O_SILENT)
+ fprintf(stderr,"Server says '%s' to LAST command.\n",buf);
+
+ return(ok);
+}
+
+
+/******************************************************************
+ function: POP3_BuildDigest
+ description: Construct the MD5 digest for the current session,
+ using the user-specified password, and the time
+ stamp in the POP3 greeting.
+ arguments:
+ buf greeting string
+ options merged options record.
+
+ ret. value: zero on success, nonzero if no timestamp found in
+ greeting.
+ globals: none.
+ calls: MD5Digest.
+ *****************************************************************/
+
+#if defined(HAVE_APOP_SUPPORT)
+POP3_BuildDigest (buf,options)
+char *buf;
+struct optrec *options;
+{
+ char *start,*end;
+ char *msg;
+
+ /* find start of timestamp */
+ for (start = buf; *start != 0 && *start != '<'; start++)
+ ;
+ if (*start == 0) {
+ fprintf(stderr,"Required APOP timestamp not found in greeting\n");
+ return(-1);
+ }
+
+ /* find end of timestamp */
+ for (end = start; *end != 0 && *end != '>'; end++)
+ ;
+ if (*end == 0 || (end - start - 1) == 1) {
+ fprintf(stderr,"Timestamp syntax error in greeting\n");
+ return(-1);
+ }
+
+ /* copy timestamp and password into digestion buffer */
+ msg = (char *) malloc((end-start-1) + strlen(options->password) + 1);
+ *(++end) = 0;
+ strcpy(msg,start);
+ strcat(msg,options->password);
+
+ strcpy(options->digest, MD5Digest(msg));
+ free(msg);
+ return(0);
+}
+#endif /* HAVE_APOP_SUPPORT */
+