aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1996-10-04 17:58:17 +0000
committerEric S. Raymond <esr@thyrsus.com>1996-10-04 17:58:17 +0000
commit50b3d54cadeda8be3e837358f43e0e9b904d091a (patch)
tree053b6784c6706e60e870986e78c52b1085a7f09d
parentc6a786da423edc936db3d62e00ce2dc06b2e2a44 (diff)
downloadfetchmail-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--NEWS3
-rw-r--r--driver.c155
-rw-r--r--fetchmail.c139
-rw-r--r--fetchmail.h7
-rw-r--r--fetchmail.man15
-rw-r--r--options.c18
-rw-r--r--rcfile_l.l1
-rw-r--r--rcfile_y.y3
-rw-r--r--sample.rcfile1
9 files changed, 243 insertions, 99 deletions
diff --git a/NEWS b/NEWS
index e70b32c8..617b2f6e 100644
--- 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
diff --git a/driver.c b/driver.c
index cd6712a2..86211d8b 100644
--- 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)
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
diff --git a/options.c b/options.c
index 84556c42..29abbe03 100644
--- a/options.c
+++ b/options.c
@@ -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);
diff --git a/rcfile_l.l b/rcfile_l.l
index 173042a9..e4c70f93 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -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; }
diff --git a/rcfile_y.y b/rcfile_y.y
index 196433a5..a899315d 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -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