]> Pileus Git - ~andy/fetchmail/commitdiff
Restore --mda, with cleaner implementation this time.
authorEric S. Raymond <esr@thyrsus.com>
Fri, 4 Oct 1996 17:58:17 +0000 (17:58 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 4 Oct 1996 17:58:17 +0000 (17:58 -0000)
svn path=/trunk/; revision=214

NEWS
driver.c
fetchmail.c
fetchmail.h
fetchmail.man
options.c
rcfile_l.l
rcfile_y.y
sample.rcfile

diff --git a/NEWS b/NEWS
index e70b32c8ff31c75151c49148600a70c1b8e575ba..617b2f6ec26cad8b5689fc8aa632b43e64d81da6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,9 @@ fetchmail-1.6 ():
 * Fix a bonehead coding error in pop3_delete() that was masked by the
   Intel register architecture.  *blush*  Thanks to Jay Anderson.
 
+* Restore --mda, seems some people either can't run a port 25 listener
+  due to bizarre dynamic-SLIP problems, or won't for security reasons.
+
 fetchmail-1.5 (Thu Oct  3 04:35:15 EDT 1996):
 
 * Naturally, my decision to announce 1.4 on comp.os.linux.announce 
index cd6712a259cc81d58cee22e22576b48d22c9911e..86211d8b86b1f7b81f4b96df91e30ad16a38a90f 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -264,23 +264,20 @@ char *hdr;
     mboxfd       open file descriptor to which the retrieved message will
                  be written.
     len          length of text 
-    popuser      name of the POP user 
-    pophost      name of the POP host 
-    output       output mode
+    delimited    does the protocol use a message delimiter?
+    queryctl     host control block
 
   return value:  zero if success else PS_* return code.
   calls:         SockGets.
   globals:       reads outlevel. 
  *********************************************************************/
 
-static int gen_readmsg (socket,mboxfd,len,delimited,popuser,pophost,rewrite)
+static int gen_readmsg (socket, mboxfd, len, delimited, queryctl)
 int socket;
 int mboxfd;
 long len;
 int delimited;
-char *popuser;
-char *pophost;
-int rewrite;
+struct hostrec *queryctl;
 { 
     char buf [MSGBUFSIZE+1]; 
     char fromBuf[MSGBUFSIZE+1];
@@ -293,12 +290,8 @@ int rewrite;
     static int msgnum = 0;  
 
     /* set up for status message if outlevel allows it */
-    if (outlevel > O_SILENT && outlevel < O_VERBOSE) {
+    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);
-    }
 
     /* read the message content from the server */
     inheaders = 1;
@@ -321,8 +314,8 @@ int rewrite;
      
        if (inheaders)
         {
-           if (rewrite)
-               reply_hack(bufp, pophost);
+           if (!queryctl->norewrite)
+               reply_hack(bufp, queryctl->servername);
 
            if (!lines)
            {
@@ -340,7 +333,7 @@ int rewrite;
                /*
                 * We deal with RFC822 continuation lines here.
                 * Replace previous '\n' with '\r' so nxtaddr 
-                * and reply-hack will be able to see past it.
+                * and reply_hack will be able to see past it.
                 * We'll undo this before writing the header.
                 */
                if (isspace(bufp[0]))
@@ -372,43 +365,46 @@ int rewrite;
        {
            char        *cp;
 
-           if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK)
-               return(PS_SMTP);
+           if (!queryctl->mda[0])
+           {
+               if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK)
+                   return(PS_SMTP);
 #ifdef SMTP_RESEND
-           /*
-            * 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.
-            */
-           if (tohdr && (cp = nxtaddr(tohdr)) != (char *)NULL)
-               do {
-                   if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
-                       return(PS_SMTP);
-               } while
-                   (cp = nxtaddr(NULL));
-           if (cchdr && (cp = nxtaddr(cchdr)) != (char *)NULL)
-               do {
-                   if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
-                       return(PS_SMTP);
-               } while
-                   (cp = nxtaddr(NULL));
-           if (bcchdr && (cp = nxtaddr(bcchdr)) != (char *)NULL)
-               do {
-                   if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
-                       return(PS_SMTP);
-               } while
-                   (cp = nxtaddr(NULL));
+               /*
+                * 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.
+                */
+               if (tohdr && (cp = nxtaddr(tohdr)) != (char *)NULL)
+                   do {
+                       if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
+                           return(PS_SMTP);
+                   } while
+                       (cp = nxtaddr(NULL));
+               if (cchdr && (cp = nxtaddr(cchdr)) != (char *)NULL)
+                   do {
+                       if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
+                           return(PS_SMTP);
+                   } while
+                       (cp = nxtaddr(NULL));
+               if (bcchdr && (cp = nxtaddr(bcchdr)) != (char *)NULL)
+                   do {
+                       if (SMTP_rcpt(mboxfd, cp) == SM_UNRECOVERABLE)
+                           return(PS_SMTP);
+                   } while
+                       (cp = nxtaddr(NULL));
 #else
-           /*
-            * Since we're really only fetching mail for one user
-            * per host query, we can be simpler
-            */
-           if (SMTP_rcpt(mboxfd, popuser) == SM_UNRECOVERABLE)
-               return(PS_SMTP);
+               /*
+                * Since we're really only fetching mail for one user
+                * per host query, we can be simpler
+                */
+               if (SMTP_rcpt(mboxfd, queryctl->localname) == SM_UNRECOVERABLE)
+                   return(PS_SMTP);
 #endif /* SMTP_RESEND */
-           SMTP_data(mboxfd);
-           if (outlevel == O_VERBOSE)
-               fputs("SMTP> ", stderr);
+               SMTP_data(mboxfd);
+               if (outlevel == O_VERBOSE)
+                   fputs("SMTP> ", stderr);
+           }
 
            /* change continuation markers back to regular newlines */
            for (cp = headers; cp < headers +  oldlen; cp++)
@@ -439,28 +435,27 @@ int rewrite;
 
     skipwrite:;
 
+       /* write the message size dots */
        sizeticker += strlen(bufp);
        while (sizeticker >= SIZETICKER)
        {
-           if (outlevel > O_SILENT && outlevel < O_VERBOSE && mboxfd != 1)
+           if (outlevel > O_SILENT && outlevel < O_VERBOSE)
                fputc('.',stderr);
            sizeticker -= SIZETICKER;
        }
        lines++;
     }
 
+
+    /* finish up display output */
     if (outlevel == O_VERBOSE)
-       fputc('\n', stderr);
+       fprintf(stderr,"\n(%d lines of message content)\n",lines);
+    else if (outlevel > O_SILENT) 
+       fputs("\n", stderr);
 
     /* write message terminator */
     if (SMTP_eom(mboxfd) != SM_OK)
        return(PS_SMTP);
-
-    /* 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);
     return(0);
 }
 
@@ -568,24 +563,17 @@ struct method *proto;
 
     if (count > 0)
     {
-       ok = PS_SMTP;
-       if ((mboxfd = Socket(queryctl->smtphost, SMTP_PORT)) < 0) 
-           goto cleanUp;
-       
-       /* eat the greeting message */
-       if (SMTP_ok(mboxfd, NULL) != SM_OK) {
-           close(mboxfd);
-           mboxfd = -1;
-           goto cleanUp;
-       }
+       if (queryctl->mda[0] == '\0')
+           if ((mboxfd = Socket(queryctl->smtphost, SMTP_PORT)) < 0
+               || SMTP_ok(mboxfd, NULL) != SM_OK
+               || SMTP_helo(mboxfd, queryctl->servername) != SM_OK)
+           {
+               ok = PS_SMTP;
+               close(mboxfd);
+               mboxfd = -1;
+               goto cleanUp;
+           }
     
-       /* make it look like mail is coming from the server */
-       if (SMTP_helo(mboxfd,queryctl->servername) != SM_OK) {
-           close(mboxfd);
-           mboxfd = -1;
-           goto cleanUp;
-       }
-
        /* read, forward, and delete messages */
        for (num = 1; num <= count; num++)
        {
@@ -608,14 +596,21 @@ struct method *proto;
                                "fetching message %d (%d bytes)\n",
                                num, len);
 
+               /* open the delivery pipe now if we're using an MDA */
+               if (queryctl->mda[0])
+                   if ((mboxfd = openmailpipe(queryctl)) < 0)
+                       goto cleanUp;
+
                /* read the message and ship it to the output sink */
-               ok = gen_readmsg(socket,
-                                mboxfd,
-                                len,
+               ok = gen_readmsg(socket, mboxfd,
+                                len, 
                                 protocol->delimited,
-                                queryctl->localname,
-                                queryctl->servername,
-                                !queryctl->norewrite);
+                                queryctl);
+
+               /* close the delivery pipe, we'll reopen before next message */
+               if (queryctl->mda[0])
+                   if ((ok = closemailpipe(mboxfd)) != 0)
+                       goto cleanUp;
 
                /* tell the server we got it OK and resynchronize */
                if (protocol->trail)
index 86ea3872f09365ce4703a6de033b7894f78d4be3..0e228811108bcaa3d1c409f1ba83bb0a1a2052bb 100644 (file)
 
 #ifdef HAVE_PROTOTYPES
 /* prototypes for internal functions */
-int showoptions (struct hostrec *queryctl);
-int showversioninfo (void);
-int dump_options (struct hostrec *queryctl);
-int query_host(struct hostrec *queryctl);
+static int showversioninfo (void);
+static int dump_options (struct hostrec *queryctl);
+static int query_host(struct hostrec *queryctl);
 #endif
 
 /* controls the detail level of status/progress messages written to stderr */
@@ -118,8 +117,34 @@ char **argv;
 
        prc_mergeoptions(servername, &cmd_opts, &def_opts, hostp);
        strcpy(hostp->servername, servername);
+
        hostp->next = hostlist;
        hostlist = hostp;
+
+       if (hostp->mda[0])
+       {
+           int argi;
+           char *argp;
+
+           /* expand the %s escape if any before parsing */
+           sprintf(hostp->mdabuf, hostp->mda, hostp->localname);
+
+           /* now punch nulls into the delimiting whitespace in the args */
+           for (argp = hostp->mdabuf, argi = 1; *argp != '\0'; argi++)
+           {
+               hostp->mda_argv[argi] = argp;
+               while (!(*argp == '\0' || isspace(*argp)))
+                   argp++;
+               if (*argp != '\0')
+                   *(argp++) = '\0';  
+           }
+
+           hostp->mda_argv[argi] = (char *)NULL;
+
+           hostp->mda_argv[0] = hostp->mda_argv[1];
+           if ((argp = strrchr(hostp->mda_argv[1], '/')) != (char *)NULL)
+               hostp->mda_argv[1] = argp + 1 ;
+       }
     }
 
     /* set up to do lock protocol */
@@ -264,7 +289,7 @@ void termhook(int sig)
   globals:       none.
  *********************************************************************/
 
-char *showproto(proto)
+static char *showproto(proto)
 int proto;
 {
     switch (proto)
@@ -284,7 +309,7 @@ int proto;
  */
 static const int autoprobe[] = {P_IMAP, P_POP3, P_POP2};
 
-int query_host(queryctl)
+static int query_host(queryctl)
 /* perform fetch transaction with single host */
 struct hostrec *queryctl;
 {
@@ -328,14 +353,14 @@ struct hostrec *queryctl;
  
 /*********************************************************************
   function:      showversioninfo
-  description:   display program release and compiler info
+  description:   display program release
   arguments:     none.
   return value:  none.
   calls:         none.
   globals:       none.
  *********************************************************************/
 
-int showversioninfo()
+static int showversioninfo()
 {
     printf("This is fetchmail release %s\n",RELEASE_ID);
 }
@@ -354,8 +379,6 @@ int showversioninfo()
 int dump_params (queryctl)
 struct hostrec *queryctl;
 {
-    char *cp;
-
     if (queryctl->skip || outlevel == O_VERBOSE)
        printf("  This host will%s be queried when no host is specified.\n",
               queryctl->skip ? " not" : "");
@@ -388,7 +411,101 @@ struct hostrec *queryctl;
     printf("  Rewrite of server-local addresses is %sabled (--norewrite %s)\n",
           queryctl->norewrite ? "dis" : "en",
           queryctl->norewrite ? "on" : "off");
-    printf("  Messages will be SMTP-forwarded to '%s'\n", queryctl->smtphost);
+    if (queryctl->mda[0])
+    {
+       char **cp;
+
+       printf("  Messages will be delivered with %s, args:",
+              queryctl->mda_argv[0]);
+       for (cp = queryctl->mda_argv+1; *cp; cp++)
+           printf(" %s", *cp);
+       putchar('\n');
+    }
+    else
+       printf("  Messages will be SMTP-forwarded to '%s'\n", queryctl->smtphost);
+}
+
+/*********************************************************************
+  function:      openmailpipe
+  description:   open a one-way pipe to the mail delivery agent.
+  arguments:     
+    queryctl     fully-determined options (i.e. parsed, defaults invoked,
+                 etc).
+
+  return value:  open file descriptor for the pipe or -1.
+  calls:         none.
+  globals:       reads mda_argv.
+ *********************************************************************/
+
+int openmailpipe (queryctl)
+struct hostrec *queryctl;
+{
+    int pipefd [2];
+    int childpid;
+
+    if (pipe(pipefd) < 0) {
+       perror("fetchmail: openmailpipe: pipe");
+       return(-1);
+    }
+    if ((childpid = fork()) < 0) {
+       perror("fetchmail: openmailpipe: fork");
+       return(-1);
+    }
+    else if (childpid == 0) {
+
+       /* in child process space */
+       close(pipefd[1]);  /* close the 'write' end of the pipe */
+       close(0);          /* get rid of inherited stdin */
+       if (dup(pipefd[0]) != 0) {
+           fputs("fetchmail: openmailpipe: dup() failed\n",stderr);
+           exit(1);
+       }
+
+       execv(queryctl->mda_argv[0], queryctl->mda_argv + 1);
+
+       /* if we got here, an error occurred */
+       perror("fetchmail: openmailpipe: exec");
+       _exit(PS_SYNTAX);
+
+    }
+
+    /* in the parent process space */
+    close(pipefd[0]);  /* close the 'read' end of the pipe */
+    return(pipefd[1]);
 }
 
+/*********************************************************************
+  function:      closemailpipe
+  description:   close pipe to the mail delivery agent.
+  arguments:     
+    queryctl     fully-determined options record
+    fd           pipe descriptor.
+
+  return value:  0 if success, else -1.
+  calls:         none.
+  globals:       none.
+ *********************************************************************/
+
+int closemailpipe (fd)
+int fd;
+{
+    int err;
+    int childpid;
+
+    if (outlevel == O_VERBOSE)
+       fprintf(stderr, "about to close pipe %d\n", fd);
 
+    err = close(fd);
+#if defined(STDC_HEADERS)
+    childpid = wait(NULL);
+#else
+    childpid = wait((int *) 0);
+#endif
+    if (err)
+       perror("fetchmail: closemailpipe: close");
+
+    if (outlevel == O_VERBOSE)
+       fprintf(stderr, "closed pipe %d\n", fd);
+  
+    return(err);
+}
index 70f97fc1db97db44547ce3d40344da5e4cf0876e..56d047472774cf527658639cbd596a2100f1e123 100644 (file)
@@ -27,6 +27,7 @@
 #define                PASSWORDLEN     MAX_PASSWORD_LENGTH
 #define                FOLDERLEN       256     /* max folder name length */
 #define                DIGESTLEN       33      /* length of MD5 digest */
+#define                MDALEN          256     /* length of delivery agent command */
 #define                IDLEN           128     /* length of UIDL message ID */
 
 /* exit code values */
@@ -58,9 +59,14 @@ struct hostrec
     char password [PASSWORDLEN+1];
     char remotefolder [FOLDERLEN];
     char smtphost[HOSTLEN+1];
+    char mda [MDALEN+1];
     int protocol;
     int port;
 
+    /* MDA arguments */
+    char *mda_argv[32];
+    char mdabuf[MDALEN+1];
+
     /* control flags */
     int keep;
     int fetchall;
@@ -121,6 +127,7 @@ int parsecmdline (int, char **, struct hostrec *);
 int setdefaults (struct hostrec *);
 char *getnextserver (int argc, char **, int *);
 char *MD5Digest (char *);
+int openmailpipe (struct hostrec *);
 void append_server_names(int *, char **, int);
 int daemonize(const char *, void (*)(int));
 
index 1c50856e380fee557e4337f27af77cc82b5f2cbe..b92aaed6873ee78bc7dcac574b922b855a6e412f 100644 (file)
@@ -25,7 +25,7 @@ mail-retrieval protocols: POP2 (as specified in RFC 937), POP3 (RFC
 IMAP4 (as specified by RFC1730).  It can use (but does not require)
 the RPOP and LAST facilities removed from later POP3 versions.
 .PP
-As each message is retrieved \fIfetchmail\fR delivers it via SMTP to
+As each message is retrieved \fIfetchmail\fR normally delivers it via SMTP to
 port 25 on the machine it is running on (localhost), just as though it
 were being passed in over a normal TCP/IP link.  The mail will then be
 delivered locally via your system's MDA (Mail Delivery Agent, usually
@@ -60,6 +60,17 @@ command, behaves as though --all is always on (see KNOWN PROBLEMS below).
 .B \-S host, --smtphost host
 Specify an host to forward mail to (other than localhost).
 .TP
+.B \-m, \--mda
+You can force mail to be passed to an MDA directly (rather than
+forwarded to port 25) with the -mda or -m
+option (this can be useful if you don't want to run sendmail as an
+SMTP listener for security or other reasons).  
+Some possible MDAs are "/usr/sbin/sendmail -oem %s",
+"/usr/lib/sendmail -oem %s",
+"/usr/formail", and "/usr/bin/deliver %s" (if the MDA command contains
+%s, that escape will be expanded into your username on the client
+machine).
+.TP
 .B \-F, --flush
 POP3/IMAP only.  Delete old (previously retrieved) messages from the mailserver
 before retrieving new messages.
@@ -289,6 +300,7 @@ Legal keywords are:
     password (or pass)
     remotefolder (or remote)
     smtphost (or smtp)
+    mda
     keep
     flush
     fetchall
@@ -367,6 +379,7 @@ string in double quotes.  Thus:
         proto pop3
         user jsmith
         pass "u can't krak this"
+        mda "/bin/mail %s"
 .fi
 
 Finally, you may have an initial server description headed by the keyword
index 84556c425c925a25792c9fd1ecf5870f63487caa..29abbe039af2fac6d1915399d00349d36a6d2ae3 100644 (file)
--- a/options.c
+++ b/options.c
 #define LA_REMOTEFILE  13
 #define LA_PORT                14
 #define LA_SMTPHOST    15
-#define LA_LOGFILE     16
-#define LA_QUIT                17
-#define LA_NOREWRITE   18
-#define LA_HELP                19
-#define LA_YYDEBUG     20
+#define LA_MDA         16
+#define LA_LOGFILE     17
+#define LA_QUIT                18
+#define LA_NOREWRITE   19
+#define LA_HELP                20
+#define LA_YYDEBUG     21
 
-static char *shortoptions = "PVaKkvS:sFd:f:u:r:L:qN?";
+static char *shortoptions = "PVaKkvS:m:sFd:f:u:r:L:qN?";
 static struct option longoptions[] = {
   {"version",   no_argument,       (int *) 0, LA_VERSION    },
   {"all",      no_argument,       (int *) 0, LA_ALL        },
@@ -57,6 +58,7 @@ static struct option longoptions[] = {
   {"remote",    required_argument, (int *) 0, LA_REMOTEFILE },
   {"port",     required_argument, (int *) 0, LA_PORT       },
   {"smtphost", required_argument, (int *) 0, LA_SMTPHOST   },
+  {"mda",      required_argument, (int *) 0, LA_MDA        },
   {"logfile",  required_argument, (int *) 0, LA_LOGFILE    },
   {"quit",     no_argument,       (int *) 0, LA_QUIT       },
   {"norewrite",        no_argument,       (int *) 0, LA_NOREWRITE  },
@@ -172,6 +174,10 @@ struct hostrec *queryctl;
       case LA_REMOTEFILE:
         strncpy(queryctl->remotefolder,optarg,sizeof(queryctl->remotefolder)-1);
         break;
+      case 'm':
+      case LA_MDA:
+        strncpy(queryctl->mda,optarg,sizeof(queryctl->mda));
+        break;
       case 'P':
       case LA_PORT:
        queryctl->port = atoi(optarg);
index 173042a97502daedcaf35a11619162c6c315aa14..e4c70f93031016cf0f28f1faefbd1e073341b50b 100644 (file)
@@ -30,6 +30,7 @@ user(name)?   { return KW_USERNAME; }
 pass(word)?    { return KW_PASSWORD; }
 remote(folder)? { return KW_REMOTEFOLDER; }
 smtp(host)?    { return KW_SMTPHOST; }
+mda            { return KW_MDA; }
 keep           { yylval.flag = FLAG_TRUE; return KW_KEEP; }
 flush          { yylval.flag = FLAG_TRUE; return KW_FLUSH; }
 fetchall       { yylval.flag = FLAG_TRUE; return KW_FETCHALL; }
index 196433a5280465cc1d4cea7388e8c310c46e82cd..a899315de9313ec0cd273e6799772540b67c21f4 100644 (file)
@@ -30,7 +30,7 @@ int yydebug;  /* in case we didn't generate with -- debug */
 }
 
 %token KW_SERVER KW_PROTOCOL KW_USERNAME KW_PASSWORD
-%token KW_REMOTEFOLDER KW_SMTPHOST KW_DEFAULTS
+%token KW_REMOTEFOLDER KW_SMTPHOST KW_MDA KW_DEFAULTS
 %token <proto> KW_PROTO
 %token <sval>  PARAM_STRING
 %token <flag>  KW_KEEP KW_FLUSH KW_FETCHALL KW_REWRITE KW_PORT KW_SKIP
@@ -67,6 +67,7 @@ serv_option_clause:
        |       KW_PASSWORD PARAM_STRING     {prc_setpassword($2);}
        |       KW_REMOTEFOLDER PARAM_STRING {prc_setremote($2);}
        |       KW_SMTPHOST PARAM_STRING     {prc_setsmtphost($2);}
+       |       KW_MDA PARAM_STRING          {prc_setmda($2);}
        |       KW_KEEP                      {prc_setkeep($1==FLAG_TRUE);}
        |       KW_FLUSH                     {prc_setflush($1==FLAG_TRUE);}
        |       KW_FETCHALL                  {prc_setfetchall($1==FLAG_TRUE);}
index 515dfa17189af6e5b65c4dcb8262c2b9591cdfc5..e8d757ead681e0e70d62eda8587258f775a0335b 100644 (file)
@@ -26,6 +26,7 @@
 #   remotefolder (or remote)
 #   localfolder (or local)
 #   smtphost (or smtp)
+#   mda
 #   keep
 #   flush
 #   fetchall