]> Pileus Git - ~andy/fetchmail/blobdiff - driver.c
Eliminate some unnecessary headers.
[~andy/fetchmail] / driver.c
index 4718d35b7e476059dfd5925a69db9b5ff894a6b4..53b41e5acd49e371828984a93de075ceed7175ed 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -5,30 +5,20 @@
 
 /***********************************************************************
   module:       driver.c
-  project:      popclient
+  project:      fetchmail
   programmer:   Eric S. Raymond
   description:  Generic driver for mail fetch method protocols
 
  ***********************************************************************/
 
 #include  <config.h>
-#include  <varargs.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  <malloc.h>
+#include  <varargs.h>
+#include  <sys/time.h>
 
 #include  "socket.h"
-#include  "popclient.h"
+#include  "fetchmail.h"
 #include  "smtp.h"
 
 static struct method *protocol;
@@ -55,7 +45,7 @@ static int gen_readmsg (int socket, int mboxfd, long len, int delimited,
     proto        protocol method pointer
 
   return value:  exit code from the set of PS_.* constants defined in 
-                 popclient.h
+                 fetchmail.h
   calls:
   globals:       reads outlevel.
  *********************************************************************/
@@ -66,7 +56,7 @@ struct method *proto;
 {
     int ok, len;
     int mboxfd;
-    char buf [POPBUFSIZE], host[HOSTLEN];
+    char buf [POPBUFSIZE+1], host[HOSTLEN+1];
     int socket;
     int first,number,count;
 
@@ -114,10 +104,6 @@ struct method *proto;
        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)
@@ -131,11 +117,19 @@ struct method *proto;
 
     /* 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);
+       if (count == 0)
+           fprintf(stderr, "No mail from %s\n", queryctl->servername);
+       else if (first > 1) 
+           fprintf(stderr,
+                   "%d message%s from %s, %d new messages.\n", 
+                   count, count > 1 ? "s" : "", 
+                   queryctl->servername, count - first + 1);
        else
-           fprintf(stderr,"%d %smessages in folder.\n", count, ok ? "" : "new ");
+           fprintf(stderr,
+                   "%d %smessage%s from %s.\n",
+                   count, ok ? "" : "new ", 
+                   count > 1 ? "s" : "", 
+                   queryctl->servername);
 
     if (count > 0) { 
        for (number = queryctl->flush ? 1 : first;  number<=count; number++) {
@@ -172,14 +166,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 */
@@ -223,8 +220,10 @@ closeUp:
        if (closeuserfolder(mboxfd) < 0 && ok == 0)
            ok = PS_IOERR;
     }
-    else if (queryctl->output == TO_SMTP && mboxfd  > 0)
+    else if (queryctl->output == TO_SMTP && mboxfd > 0) {
+       SMTP_quit(mboxfd);
        close(mboxfd);
+    }
 
     if (ok == PS_IOERR || ok == PS_SOCKET) 
        perror("do_protocol: cleanUp");
@@ -250,7 +249,7 @@ int socket;
 const char *fmt;
 va_dcl {
 
-  char buf [POPBUFSIZE];
+  char buf [POPBUFSIZE+1];
   va_list ap;
 
   if (protocol->tagged)
@@ -288,7 +287,7 @@ const char *fmt;
 va_dcl {
 
   int ok;
-  char buf [POPBUFSIZE];
+  char buf [POPBUFSIZE+1];
   va_list ap;
 
   if (protocol->tagged)
@@ -306,7 +305,7 @@ va_dcl {
     fprintf(stderr,"> %s\n", buf);
 
   ok = (protocol->parse_response)(buf,socket);
-  if (ok != 0 && outlevel > O_SILENT && outlevel < O_VERBOSE)
+  if (ok != 0 && outlevel > O_SILENT && outlevel <= O_VERBOSE)
     fprintf(stderr,"%s\n",buf);
 
   return(ok);
@@ -332,7 +331,7 @@ const char *host;
 {
     const char *from;
     int state = 0;
-    char mycopy[POPBUFSIZE];
+    char mycopy[POPBUFSIZE+1];
 
     if (strncmp("From: ", buf, 6)
        && strncmp("To: ", buf, 4)
@@ -417,8 +416,9 @@ const char *host;
 /*********************************************************************
   function:      nxtaddr
   description:   Parse addresses in succession out of a specified RFC822
-                 header.  Note: RFC822 escaping with \ is *not* handled.
-
+                 header.  Note 1: RFC822 escaping with \ is *not* handled.
+                 Note 2: it is important that this routine not stop on \r,
+                 since we use \r as a marker for RFC822 continuations below.
   arguments:     
     hdr          header line to be parsed, NUL to continue in previous hdr
 
@@ -429,7 +429,7 @@ const char *host;
 static char *nxtaddr(hdr)
 char *hdr;
 {
-    static char        *hp, *tp, address[POPBUFSIZE];
+    static char        *hp, *tp, address[POPBUFSIZE+1];
     static     state;
 
     if (hdr)
@@ -446,37 +446,52 @@ char *hdr;
            if (*hp == '\n')
                return(NULL);
            else if (*hp == ':')
+           {
                state = 1;
+               tp = address;
+           }
            break;
 
-       case 1:   /* we've seen the colon, we're looking for addresses */
-           if (*hp == '\n')
-               return(NULL);
-           else if (*hp == '"')
-               state = 2;
-           else if (*hp == '(')
+       case 1:   /* we've seen the colon, now grab the address */
+           if ((*hp == '\n') || (*hp == ','))  /* end of address list */
+           {
+               *tp++ = '\0';
+               return(address);
+           }
+           else if (*hp == '"') /* quoted string */
+           {
+               state = 2;
+               *tp++ = *hp;
+           }
+           else if (*hp == '(') /* address comment -- ignore */
                state = 3;    
-           else if (*hp == '<')
+           else if (*hp == '<') /* begin <address> */
            {
                state = 4;
                tp = address;
            }
-           else if (isalnum(*hp))
+           else if (isspace(*hp)) /* ignore space */
+               state = 1;
+           else   /* just take it */
            {
-               state = 5;
-               tp = address;
+               state = 1;
                *tp++ = *hp;
            }
            break;
 
-       case 2:   /* we're in a quoted human name, copy and ignore */
+       case 2:   /* we're in a quoted string, copy verbatim */
            if (*hp == '\n')
                return(NULL);
+           if (*hp != '"')
+               *tp++ = *hp;
            else if (*hp == '"')
+           {
+               *tp++ = *hp;
                state = 1;
+           }
            break;
 
-       case 3:   /* we're in a parenthesized human name, copy and ignore */
+       case 3:   /* we're in a parenthesized comment, ignore */
            if (*hp == '\n')
                return(NULL);
            else if (*hp == ')')
@@ -484,25 +499,33 @@ char *hdr;
            break;
 
        case 4:   /* possible <>-enclosed address */
-           if (*hp == '>')
+           if (*hp == '>') /* end of address */
            {
                *tp++ = '\0';
                state = 1;
                return(address);
            }
-           else
+           else if (*hp == '<')  /* nested <> */
+               tp = address;
+           else if (*hp == '"') /* quoted address */
+           {
+               *tp++ = *hp;
+               state = 5;
+           }
+           else  /* just copy address */
                *tp++ = *hp;
            break;
 
-       case 5: /* address not <>-enclosed, terminate on any whitespace */
-           if (isspace(*hp))
+       case 5:   /* we're in a quoted address, copy verbatim */
+           if (*hp == '\n')  /* mismatched quotes */
+               return(NULL);
+           if (*hp != '"')  /* just copy it if it isn't a quote */
+               *tp++ = *hp;
+           else if (*hp == '"')  /* end of quoted string */
            {
-               *tp++ = '\0';
-               state = 1;
-               return(address);        /* prevents normal hp++ */
+               *tp++ = *hp;
+               state = 4;
            }
-           else
-               *tp++ = *hp;
            break;
        }
     }
@@ -539,8 +562,8 @@ char *pophost;
 int output;
 int rewrite;
 { 
-    char buf [MSGBUFSIZE]; 
-    char fromBuf[MSGBUFSIZE];
+    char buf [MSGBUFSIZE+1]; 
+    char fromBuf[MSGBUFSIZE+1];
     char *bufp, *headers, *unixfrom, *fromhdr, *tohdr, *cchdr, *bcchdr;
     int n, oldlen;
     int inheaders;
@@ -554,14 +577,14 @@ int rewrite;
        fprintf(stderr,"reading message %d",++msgnum);
        /* won't do the '...' if retrieved messages are being sent to stdout */
        if (mboxfd == 1)
-           fputs(".\n",stderr);
+           fputs("\n",stderr);
     }
 
     /* read the message content from the server */
     inheaders = 1;
     headers = unixfrom = fromhdr = tohdr = cchdr = bcchdr = NULL;
     lines = 0;
-    sizeticker = MSGBUFSIZE;
+    sizeticker = 0;
     while (delimited || len > 0) {
        if ((n = SockGets(socket,buf,sizeof(buf))) < 0)
            return(PS_SOCKET);
@@ -574,7 +597,7 @@ int rewrite;
            if (delimited && *bufp == 0)
                break;  /* end of message */
        }
-       strcat(bufp,"\n");
+       strcat(bufp, output == TO_SMTP && !inheaders ? "\r\n" : "\n");
      
        if (inheaders)
         {
@@ -592,8 +615,18 @@ int rewrite;
            }
            else
            {
-               int     newlen = oldlen + strlen(bufp);
+               int     newlen;
 
+               /*
+                * We deal with RFC822 continuation lines here.
+                * Replace previous '\n' with '\r' so nxtaddr 
+                * and reply-hack will be able to see past it.
+                * We'll undo this before writing the header.
+                */
+               if (isspace(bufp[0]))
+                   headers[oldlen-1] = '\r';
+
+               newlen = oldlen + strlen(bufp);
                headers = realloc(headers, newlen + 1);
                if (headers == NULL)
                    return(PS_IOERR);
@@ -626,7 +659,7 @@ int rewrite;
                    return(PS_SMTP);
 #ifdef SMTP_RESEND
                /*
-                * This is what we'd do if popclient were a real MDA
+                * This is what we'd do if fetchmail were a real MDA
                 * a la sendmail -- crack all the destination headers
                 * and send to every address we can reach via SMTP.
                 */
@@ -657,6 +690,8 @@ int rewrite;
                    return(PS_SMTP);
 #endif /* SMTP_RESEND */
                SMTP_data(mboxfd);
+               if (outlevel == O_VERBOSE)
+                   fputs("SMTP> ", stderr);
                break;
 
            case TO_FOLDER:
@@ -684,6 +719,11 @@ int rewrite;
                break;
            }
 
+           /* change continuation markers back to regular newlines */
+           for (cp = headers; cp < headers +  oldlen; cp++)
+               if (*cp == '\r')
+                   *cp = '\n';
+
            if (write(mboxfd,headers,oldlen) < 0)
            {
                free(headers);
@@ -691,6 +731,8 @@ int rewrite;
                perror("gen_readmsg: writing RFC822 headers");
                return(PS_IOERR);
            }
+           else if (outlevel == O_VERBOSE)
+               fputs("#", stderr);
            free(headers);
            headers = NULL;
        }
@@ -701,19 +743,24 @@ int rewrite;
            perror("gen_readmsg: writing message text");
            return(PS_IOERR);
        }
+       else if (outlevel == O_VERBOSE)
+           fputc('*', stderr);
 
     skipwrite:;
 
-       sizeticker -= strlen(bufp);
-       if (sizeticker <= 0)
+       sizeticker += strlen(bufp);
+       while (sizeticker >= MSGBUFSIZE)
        {
            if (outlevel > O_SILENT && outlevel < O_VERBOSE && mboxfd != 1)
                fputc('.',stderr);
-           sizeticker = MSGBUFSIZE;
+           sizeticker -= MSGBUFSIZE;
        }
        lines++;
     }
 
+    if (outlevel == O_VERBOSE)
+       fputc('\n', stderr);
+
     /* write message terminator, if any */
     switch (output)
     {
@@ -741,13 +788,14 @@ int rewrite;
            return(PS_IOERR);
        }
 #endif /* BINMAIL_TERM */
+       break;
     }
 
     /* 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);
+       fputs("\n",stderr);
     else
        ;
     return(0);