]> Pileus Git - ~andy/fetchmail/commitdiff
POP2 now goes through the generic driver.
authorEric S. Raymond <esr@thyrsus.com>
Wed, 25 Sep 1996 01:43:25 +0000 (01:43 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Wed, 25 Sep 1996 01:43:25 +0000 (01:43 -0000)
svn path=/trunk/; revision=128

NEWS
driver.c
fetchmail.man
pop2.c

diff --git a/NEWS b/NEWS
index 104e9c8b61db8f2bbb9f4f1c03478dac5cd7e69d..f70db50efca977b83df94dfd5d38d77a20296a18 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,9 +2,7 @@
 
 To-do list:
 
-Option to enable EMACS-like user folder versioning on each run.
-
-The IMAP support is naive.  Chris Newman, one of the IMAP maintainers,
+1. The IMAP support is naive.  Chris Newman, one of the IMAP maintainers,
 criticized it as follows:
 ------------------------------- CUT HERE -----------------------------------
 On Wed, 18 Sep 1996, Eric S. Raymond wrote:
@@ -42,17 +40,19 @@ The key thing to remember is that in IMAP the server holds the
 authoratative list of messages and the client just holds a cache.  This is
 a very different model from POP.
 ------------------------------- CUT HERE -----------------------------------
+If we ever decide that concurrent runs need to work safely, this will have
+to be fixed.
 
-IMAP extensions for secure challenge-response.
+2. Support IMAP4 extensions for secure challenge-response.
 
-Recode POP2 to use the same driver/method strategy as POP3/IMAP, so 
-all three protocols will be able to forward messages through the generic
-driver to SMTP.  (This requires that we find a POP2 server to test with.)
+3. Option to enable EMACS-like user folder versioning on each run.
 
 fetchmail-1.0 (Mon Sep 23 19:54:01 EDT 1996):
 
 * Name change (it ain't just for POP3 any more).
 
+* SMTP forwarding and header-rewrite features work with POP2 now.
+
 * Stricter RFC822 conformance, so SMTP to qmail works.  Thanks to
   Cameron MacPherson <unsound@oz.net> for these changes.
 
index 6bfd8bffe26b31918ec5a4ae8ec83fc9ee8f0aa3..a37ab8072ddbf9b9aeb5645c98cef080e98f19d3 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -114,10 +114,6 @@ struct method *proto;
        goto closeUp;
     }
 
-    /* print the greeting */
-    if (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)
@@ -180,14 +176,17 @@ struct method *proto;
            }
 
            /* 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;
+           if (protocol->delete_cmd)
+           {
+               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 */
index 339e0bf6345488bbc943fadbee35f4c19542f614..70a85220ab1f9e68b8e8e093c89df85f0b4f66aa 100644 (file)
@@ -579,11 +579,6 @@ Running more than one concurrent instance of
 .I fetchmail
 on the same mailbox may cause messages to be lost or remain unfetched.
 .PP
-When using POP2, the --smtphost option doesn't work, and mail headers
-are not rewritten to enable replies as described under --norewrite. 
-This isn't a protocol problem, it's because the developer couldn't
-find a POP2 server to test the necessary code reorganization with.
-.PP
 The --remotefolder option doesn't work with POP3, the protocol won't
 support it.
 .PP
diff --git a/pop2.c b/pop2.c
index 2d6d4fe2f79dc2c45d09ad8680109563a9c4c87d..16fbb73d5dd649c3161ff226b22ab39a8f3f46ad 100644 (file)
--- a/pop2.c
+++ b/pop2.c
 #include  "socket.h"
 #include  "fetchmail.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:     
-    queryctl     fully-specified options (i.e. parsed, defaults invoked,
-                 etc).
+ Method declarations for POP2
 
-  return value:  exit code from the set of PS_.* constants defined in 
-                 fetchmail.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 (queryctl)
-struct hostrec *queryctl;
-{
-  int mboxfd;
-  int socket;
-  int number,msgsize,actsize;
-  int status = PS_UNDEFINED;
-
-  /* check for unsupported options */
-  if (linelimit) {
-    fprintf(stderr,"Option --limit is not supported with POP2\n");
-    return(PS_SYNTAX);
-  }
-  else if (queryctl->flush) {
-    fprintf(stderr,"Option --flush is not supported with POP2\n");
-    return(PS_SYNTAX);
-  }
-  else if (queryctl->fetchall) {
-    fprintf(stderr,"Option --all is not supported with POP2\n");
-    return(PS_SYNTAX);
-  }
-  else if (queryctl->smtphost[0]) {
-    fprintf(stderr,"Option --smtphost is not supported with POP2\n");
-    return(PS_SYNTAX);
-  }
-  else
-    ;
-
-  /* open the socket to the POP server */
-  if ((socket = Socket(queryctl->servername,
-                    queryctl->port ? queryctl->port : POP2_PORT)) < 0)
-  {
-    perror("doPOP2: socket");
-    return(PS_SOCKET);
-  }
-    
-  /* open/lock the folder if it is a user folder or stdout */
-  if (queryctl->output == TO_FOLDER)
-    if ((mboxfd = openuserfolder(queryctl)) < 0) 
-      return(PS_IOERR);
-  /* wait for the POP2 greeting */
-  if (POP2_stateGREET(socket) != 0) {
-    POP2_quit(socket);
-    status = PS_PROTOCOL;
-    goto closeUp;
-  }
-
-  /* log the user onto the server */
-  POP2_sendHELO(queryctl->remotename,queryctl->password,socket);
-  if ((number = POP2_stateNMBR(socket)) < 0) {
-    POP2_quit(socket);
-    status = PS_AUTHFAIL;
-    goto closeUp;
-  }
-
-  /* set the remote folder if selected */
-  if (*queryctl->remotefolder != 0) {
-    POP2_sendFOLD(queryctl->remotefolder,socket);
-    if ((number = POP2_stateNMBR(socket)) < 0) {
-      POP2_quit(socket);
-      status = PS_PROTOCOL;
-      goto closeUp;
-    }
-  }
-
-  /* tell 'em how many messages are waiting */
-  if (outlevel > O_SILENT && outlevel < O_VERBOSE)
-    if (number == 0)
-      fprintf(stderr,"No mail from %s\n",number,queryctl->servername);
-    else
-      fprintf(stderr,"%d message%s from %s\n",
-             number, number > 1 ? "s" : "", queryctl->servername);
-
+static int pound_arg, equal_arg;
 
-  /* fall into a retrieve/acknowledge loop */
-  if (number > 0) { 
-
-    POP2_sendcmd("READ",socket);
-    msgsize = POP2_stateSIZE(socket);
-    while (msgsize > 0) {
-
-      /* open the pipe */
-      if (queryctl->output == TO_MDA)
-        if ((mboxfd = openmailpipe(queryctl)) < 0) {   
-          POP2_quit(socket);
-          return(PS_IOERR);
-        }
-
-      POP2_sendcmd("RETR",socket);
-      actsize = POP2_stateXFER(msgsize,socket,mboxfd,
-                               queryctl->output == TO_MDA);
-      if (actsize == msgsize) 
-        if (queryctl->keep)
-          POP2_sendcmd("ACKS",socket);
-        else
-          POP2_sendcmd("ACKD",socket);
-      else if (actsize >= 0) 
-        POP2_sendcmd("NACK",socket);
-      else {
-        POP2_quit(socket);
-       status = PS_SOCKET;
-       goto closeUp; 
-      }
-
-      /* close the pipe */
-      if (queryctl->output == TO_MDA)
-        if (closemailpipe(mboxfd) < 0) {
-          POP2_quit(socket);
-          status = PS_IOERR;
-         goto closeUp;
-        }
-    
-      msgsize = POP2_stateSIZE(socket);
-    }
-    POP2_quit(socket);
-    status = msgsize == 0 ? PS_SUCCESS : PS_PROTOCOL;
-  }
-  else {
-    POP2_quit(socket);
-    status = PS_NOMAIL;
-  }
-
-closeUp:
-  if (queryctl->output == TO_FOLDER)
-    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 pop2_ok (argbuf,socket)
+/* parse POP2 command response */
+char *argbuf;
 int socket;
 {
-  SockPuts(socket,cmd);
+    int ok;
+    char buf [POPBUFSIZE+1];
+
+    pound_arg = equal_arg = -1;
+    if (SockGets(socket, buf, sizeof(buf)) >= 0) {
+       if (outlevel == O_VERBOSE)
+           fprintf(stderr,"%s\n",buf);
+
+       if (buf[0] == '+')
+           ok = 0;
+       else if (buf[0] == '#')
+       {
+           pound_arg = atoi(buf+1);
+           ok = 0;
+       }
+       else if (buf[0] == '=')
+       {
+           equal_arg = atoi(buf+1);
+           ok = 0;
+       }
+       else if (buf[0] == '-')
+           ok = PS_ERROR;
+       else
+           ok = PS_PROTOCOL;
+
+       if (argbuf != NULL)
+           strcpy(argbuf,buf);
+    }
+    else 
+       ok = PS_SOCKET;
 
-  if (outlevel == O_VERBOSE)
-    fprintf(stderr,"> %s\n",cmd);
-  else
-    ;
+    return(ok);
 }
 
-
-/*********************************************************************
-  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 pop2_getauth(socket, queryctl, buf)
+/* apply for connection authorization */
 int socket;
+struct hostrec *queryctl;
+char *buf;
 {
-  SockPrintf(socket,"HELO %s %s\r\n",userid,password);
-    
-
-  if (outlevel == O_VERBOSE)
-    fprintf(stderr,"> HELO %s password\n",userid);
-  else
-    ;
+    return(gen_transact(socket,
+                 "HELO %s %s",
+                 queryctl->remotename, queryctl->password));
 }
 
-
-/*********************************************************************
-  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;
+static pop2_getrange(socket, queryctl, countp, firstp)
+/* get range of messages to be fetched */
 int socket;
+struct hostrec *queryctl;
+int *countp;
+int *firstp;
 {
-  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.
- *********************************************************************/
+    /*
+     * We should have picked up a count of messages in the user's
+     * default inbox from the pop2_getauth() response.
+     */
+    if (pound_arg == -1)
+       return(PS_ERROR);
+
+    /* maybe the user wanted a non-default folder */
+    if (queryctl->remotefolder[0])
+    {
+       int     ok = gen_transact(socket, "FOLD %s", queryctl->remotefolder);
+
+       if (ok != 0)
+           return(ok);
+       if (pound_arg == -1)
+           return(PS_ERROR);
+    }
 
-int POP2_quit (socket)
-int socket;
-{
-  SockPuts(socket,"QUIT");
-  close(socket);
+    *firstp = 1;
+    *countp = pound_arg;
 
-  if (outlevel == O_VERBOSE)
-    fprintf(stderr,"> QUIT\n");
-  else
-    ;
+    return(0);
 }
 
-
-/*********************************************************************
-  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)
+static int pop2_fetch(socket, number, limit, lenp)
+/* request nth message */
 int socket;
+int number;
+int limit;
+int *lenp; 
 {
-  char buf [POPBUFSIZE+1];
-  /* 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,"POP2 greeting: %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);
-  }
-}
+    int        ok;
 
+    *lenp = 0;
+    ok = gen_transact(socket, "READ %d", number);
+    if (ok)
+       return(0);
+    *lenp = equal_arg;
 
-/*********************************************************************
-  function:      POP2_stateNMBR
-  description:   process the NMBR state as described in RFC 937.
-  arguments:     
-    socket       ...to which the server is connected.
+    gen_send(socket, "RETR");
 
-  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+1];
-
-  /* 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);
+    return(ok);
 }
 
-
-/*********************************************************************
-  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)
+static pop2_trail(socket, queryctl, number)
+/* send acknowledgement for message data */
 int socket;
+struct hostrec *queryctl;
+int number;
 {
-  int msgsize;
-  char buf [POPBUFSIZE+1];
-
-  /* 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);
+    return(gen_transact(socket, queryctl->keep ? "ACKS" : "ACKD"));
 }
 
-
-/*********************************************************************
-  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;
+static struct method pop2 =
 {
-  int i,buflen,actsize;
-  char buf [MSGBUFSIZE+1]; 
-  char frombuf [MSGBUFSIZE+1];
-  char savec;
-  int msgTop;
-  int needFrom;
-  
-  time_t now;
+    "POP2",                            /* Post Office Protocol v2 */
+    109,                               /* standard POP2 port */
+    0,                                 /* this is not a tagged protocol */
+    0,                                 /* does not use message delimiter */
+    pop2_ok,                           /* parse command response */
+    pop2_getauth,                      /* get authorization */
+    pop2_getrange,                     /* query range of messages */
+    pop2_fetch,                                /* request given message */
+    pop2_trail,                                /* eat message trailer */
+    NULL,                              /* no POP2 delete command */
+    NULL,                              /* no POP2 expunge command */
+    "QUIT",                            /* the POP2 exit command */
+};
 
-  /* 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 */
+int doPOP2 (queryctl)
+struct hostrec *queryctl;
+{
+    /* check for unsupported options */
+    if (linelimit) {
+       fprintf(stderr,"Option --limit is not supported with POP2\n");
+       return(PS_SYNTAX);
     }
-    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 if (queryctl->flush) {
+       fprintf(stderr,"Option --flush is not supported with POP2\n");
+       return(PS_SYNTAX);
     }
-  }
-  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);
+    else if (queryctl->fetchall) {
+       fprintf(stderr,"Option --all is not supported with POP2\n");
+       return(PS_SYNTAX);
     }
-#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);
+    return(do_protocol(queryctl, &pop2));
 }