diff options
author | Eric S. Raymond <esr@thyrsus.com> | 1996-10-04 17:58:17 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 1996-10-04 17:58:17 +0000 |
commit | 50b3d54cadeda8be3e837358f43e0e9b904d091a (patch) | |
tree | 053b6784c6706e60e870986e78c52b1085a7f09d | |
parent | c6a786da423edc936db3d62e00ce2dc06b2e2a44 (diff) | |
download | fetchmail-50b3d54cadeda8be3e837358f43e0e9b904d091a.tar.gz fetchmail-50b3d54cadeda8be3e837358f43e0e9b904d091a.tar.bz2 fetchmail-50b3d54cadeda8be3e837358f43e0e9b904d091a.zip |
Restore --mda, with cleaner implementation this time.
svn path=/trunk/; revision=214
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | driver.c | 155 | ||||
-rw-r--r-- | fetchmail.c | 139 | ||||
-rw-r--r-- | fetchmail.h | 7 | ||||
-rw-r--r-- | fetchmail.man | 15 | ||||
-rw-r--r-- | options.c | 18 | ||||
-rw-r--r-- | rcfile_l.l | 1 | ||||
-rw-r--r-- | rcfile_y.y | 3 | ||||
-rw-r--r-- | sample.rcfile | 1 |
9 files changed, 243 insertions, 99 deletions
@@ -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 @@ -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) diff --git a/fetchmail.c b/fetchmail.c index 86ea3872..0e228811 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -40,10 +40,9 @@ #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); +} diff --git a/fetchmail.h b/fetchmail.h index 70f97fc1..56d04747 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -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)); diff --git a/fetchmail.man b/fetchmail.man index 1c50856e..b92aaed6 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -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 @@ -33,13 +33,14 @@ #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); @@ -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; } @@ -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);} diff --git a/sample.rcfile b/sample.rcfile index 515dfa17..e8d757ea 100644 --- a/sample.rcfile +++ b/sample.rcfile @@ -26,6 +26,7 @@ # remotefolder (or remote) # localfolder (or local) # smtphost (or smtp) +# mda # keep # flush # fetchall |