aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--fetchmail.c5
-rw-r--r--fetchmail.h15
-rw-r--r--fetchmail.man14
-rwxr-xr-xfetchmailconf6
-rw-r--r--options.c20
-rw-r--r--rcfile_l.l1
-rw-r--r--rcfile_y.y5
-rw-r--r--sample.rcfile1
-rw-r--r--sink.c70
10 files changed, 119 insertions, 21 deletions
diff --git a/NEWS b/NEWS
index 678ce07e..7f320fc6 100644
--- a/NEWS
+++ b/NEWS
@@ -2,8 +2,9 @@
fetchmail-4.6.5 ():
* Fixed a bug in reply_hack that could occasionally cause malloc smashes.
+* Added --bsmtp option to dump mail as a BSMTP batch.
-There are 245 people on fetchmail-friends and 306 on fetchmail-announce.
+There are 247 people on fetchmail-friends and 306 on fetchmail-announce.
fetchmail-4.6.4 (Tue Oct 27 09:07:58 EST 1998):
* Code cleanup fixes by Jonathan T. Agnew <jtagnew@amherst.edu>.
diff --git a/fetchmail.c b/fetchmail.c
index a6b4603d..bcad08fb 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -749,6 +749,7 @@ static void optmerge(struct query *h2, struct query *h1, int force)
FLAG_MERGE(remotename);
FLAG_MERGE(password);
FLAG_MERGE(mda);
+ FLAG_MERGE(bsmtp);
FLAG_MERGE(smtpaddress);
FLAG_MERGE(preconnect);
FLAG_MERGE(postconnect);
@@ -1344,7 +1345,9 @@ void dump_params (struct runctl *runp, struct query *querylist, flag implicit)
else if (outlevel >= O_VERBOSE)
printf(" No expunges (--expunge 0).\n");
}
- if (ctl->mda && (ctl->server.protocol != P_ETRN))
+ if (ctl->bsmtp)
+ printf(" Messages will be appended to %s as BSMTP\n", visbuf(ctl->bsmtp));
+ else if (ctl->mda && (ctl->server.protocol != P_ETRN))
printf(" Messages will be delivered with \"%s\".\n", visbuf(ctl->mda));
else
{
diff --git a/fetchmail.h b/fetchmail.h
index 99a8dfbe..7558984d 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -64,12 +64,14 @@
#define PS_EXCLUDE 8 /* client-side exclusion error */
#define PS_LOCKBUSY 9 /* server responded lock busy */
#define PS_SMTP 10 /* SMTP error */
-#define PS_DNS 11 /* fatal DNS error */
-#define PS_UNDEFINED 12 /* something I hadn't thought of */
-#define PS_TRANSIENT 13 /* transient failure (internal use) */
-#define PS_REFUSED 14 /* mail refused (internal use) */
-#define PS_RETAINED 15 /* message retained (internal use) */
-#define PS_TRUNCATED 16 /* headers incomplete (internal use) */
+#define PS_DNS 11 /* fatal DNS error */
+#define PS_BSMTP 12 /* output batch could not be opened */
+/* leave space for more codes */
+#define PS_UNDEFINED 23 /* something I hadn't thought of */
+#define PS_TRANSIENT 24 /* transient failure (internal use) */
+#define PS_REFUSED 25 /* mail refused (internal use) */
+#define PS_RETAINED 26 /* message retained (internal use) */
+#define PS_TRUNCATED 27 /* headers incomplete (internal use) */
/* output noise level */
#define O_SILENT 0 /* mute, max squelch, etc. */
@@ -222,6 +224,7 @@ struct query
char *smtpaddress; /* address we want to force in the delivery messages */
struct idlist *antispam; /* list of listener's antispam response */
char *mda; /* local MDA to pass mail to */
+ char *bsmtp; /* BSMTP output file */
char *preconnect; /* pre-connection command to execute */
char *postconnect; /* post-connection command to execute */
diff --git a/fetchmail.man b/fetchmail.man
index c5085183..d3994051 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -271,6 +271,15 @@ mail message's From address will be inserted where you place an %F. Do
"sendmail -oem -t" that dispatches on the contents of To/Cc/Bcc, it
will create mail loops and bring the just wrath of many postmasters
down upon your head.
+.TP \--bsmtp
+(keyword: bsmtp)
+Append fetched mail to a BSMTP file. This simply contains the SMTP
+commands that would normally be generated by fetchmail when passing
+mail to an SMTP listener daemon. An argument of `-' causes the mail
+to be written to standard output. Note that fetchmail's
+reconstruction of MAIL FROM and RCPT TO lines is not guaranteed
+correct; the caveats discussed under THE USE AND ABUSE OF MULTIDROP
+MAILBOXES below apply.
.SS Resource Limit Control Options
.TP
.B \-l, --limit
@@ -982,6 +991,9 @@ T}
mda -m T{
Specify MDA for local delivery
T}
+bsmtp -o T{
+Specify BSMTP batch file to append to
+T}
preconnect \& T{
Command to be executed before each connection
T}
@@ -1606,6 +1618,8 @@ run failed while trying to do an SMTP port open or transaction.
Fatal DNS error. Fetchmail encountered an error while performing
a DNS lookup at startup and could not proceed.
.IP 12
+BSMTP batch file could not be opened.
+.IP 23
Internal error. You should see a message on standard error with
details.
.PP
diff --git a/fetchmailconf b/fetchmailconf
index 87c8d774..d054cd60 100755
--- a/fetchmailconf
+++ b/fetchmailconf
@@ -183,6 +183,7 @@ class User:
self.preconnect = None # Connection setup
self.postconnect = None # Connection wrapup
self.mda = None # Mail Delivery Agent
+ self.bsmtp = None # BSMTP output file
self.antispam = "571 550 501" # Listener's spam-block code
self.keep = FALSE # Keep messages
self.flush = FALSE # Flush messages
@@ -208,6 +209,7 @@ class User:
('preconnect', 'String'),
('postconnect', 'String'),
('mda', 'String'),
+ ('bsmtp', 'String'),
('antispam', 'String'),
('keep', 'Boolean'),
('flush', 'Boolean'),
@@ -289,7 +291,7 @@ class User:
for x in self.mailboxes:
str = str + " " + x
str = str + "\n"
- for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'properties'):
+ for fld in ('smtpaddress', 'preconnect', 'postconnect', 'mda', 'bsmtp', 'properties'):
if getattr(self, fld):
str = str + " %s %s\n" % (fld, `getattr(self, fld)`)
if self.antispam != UserDefaults.antispam:
@@ -1191,6 +1193,8 @@ class UserEdit(Frame, MyWidget):
self.postconnect, '26').pack(side=TOP, fill=X)
LabeledEntry(targwin, 'Local delivery agent:',
self.mda, '26').pack(side=TOP, fill=X)
+ LabeledEntry(targwin, 'BSMTP output file:',
+ self.bsmtp, '26').pack(side=TOP, fill=X)
LabeledEntry(targwin, 'Listener spam-block codes:',
self.antispam, '26').pack(side=TOP, fill=X)
targwin.pack(fill=X, anchor=N)
diff --git a/options.c b/options.c
index bd7998bc..f173dd3a 100644
--- a/options.c
+++ b/options.c
@@ -58,11 +58,12 @@
#define LA_FETCHLIMIT 36
#define LA_EXPUNGE 37
#define LA_MDA 38
-#define LA_NETSEC 39
-#define LA_INTERFACE 40
-#define LA_MONITOR 41
-#define LA_CONFIGDUMP 42
-#define LA_YYDEBUG 43
+#define LA_BSMTP 39
+#define LA_NETSEC 40
+#define LA_INTERFACE 41
+#define LA_MONITOR 42
+#define LA_CONFIGDUMP 43
+#define LA_YYDEBUG 44
/* options still left: CDgGhHjJoORwWxXYz */
static const char *shortoptions =
@@ -115,9 +116,10 @@ static const struct option longoptions[] = {
{"fetchlimit",required_argument, (int *) 0, LA_FETCHLIMIT },
{"expunge", required_argument, (int *) 0, LA_EXPUNGE },
{"mda", required_argument, (int *) 0, LA_MDA },
+ {"bsmtp", required_argument, (int *) 0, LA_BSMTP },
#ifdef INET6
- {"netsec", required_argument, (int *) 0, LA_NETSEC },
+ {"netsec", required_argument, (int *) 0, LA_NETSEC },
#endif /* INET6 */
#if defined(linux) && !INET6
@@ -468,6 +470,10 @@ struct query *ctl; /* option record to be initialized */
ctl->mda = xstrdup(optarg);
ocount++;
break;
+ case LA_BSMTP:
+ ctl->bsmtp = xstrdup(optarg);
+ ocount++;
+ break;
case 'T':
case LA_NETSEC:
@@ -571,6 +577,8 @@ struct query *ctl; /* option record to be initialized */
P(" -b, --batchlimit set batch limit for SMTP connections\n");
P(" -B, --fetchlimit set fetch limit for server connections\n");
P(" -e, --expunge set max deletions between expunges\n");
+ P(" --mda set MDA to use for forwarding\n");
+ P(" --bsmtp set output BSMTP file\n");
P(" -r, --folder specify remote folder name\n");
#undef P
return(-1);
diff --git a/rcfile_l.l b/rcfile_l.l
index 12989832..ce67630f 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -56,6 +56,7 @@ smtp(host)? { return SMTPHOST; }
smtpaddress { return SMTPADDRESS; }
antispam { return SPAMRESPONSE; }
mda { return MDA; }
+bsmtp { return BSMTP; }
pre(connect)? { return PRECONNECT; }
post(connect)? { return POSTCONNECT; }
netsec { return NETSEC; }
diff --git a/rcfile_y.y b/rcfile_y.y
index bdd4c88b..044cf0c3 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -59,8 +59,8 @@ extern char * yytext;
%token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
%token AUTHENTICATE TIMEOUT KPOP SDPS KERBEROS4 KERBEROS5 KERBEROS
-%token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA SMTPADDRESS
-%token SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT
+%token ENVELOPE QVIRTUAL USERNAME PASSWORD FOLDER SMTPHOST MDA BSMTP
+%token SMTPADDRESS SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT
%token NETSEC INTERFACE MONITOR
%token IS HERE THERE TO MAP WILDCARD
%token BATCHLIMIT FETCHLIMIT EXPUNGE PROPERTIES
@@ -297,6 +297,7 @@ user_option : TO localnames HERE
| SMTPADDRESS STRING {current.smtpaddress = xstrdup($2);}
| SPAMRESPONSE num_list
| MDA STRING {current.mda = xstrdup($2);}
+ | BSMTP STRING {current.bsmtp = xstrdup($2);}
| PRECONNECT STRING {current.preconnect = xstrdup($2);}
| POSTCONNECT STRING {current.postconnect = xstrdup($2);}
diff --git a/sample.rcfile b/sample.rcfile
index cbd35593..158b387b 100644
--- a/sample.rcfile
+++ b/sample.rcfile
@@ -49,6 +49,7 @@
# smtpaddress -- must be followed by a host name
# antispam -- must be followed by a numeric response value
# mda -- must be followed by an MDA command string
+# bsmtp -- must be followed by a filename or -
# preconnect (or pre) -- must be followed by an executable command
# postconnect (or post) -- must be followed by an executable command
#
diff --git a/sink.c b/sink.c
index b45c2b99..14aa8fc4 100644
--- a/sink.c
+++ b/sink.c
@@ -222,7 +222,7 @@ int stuffline(struct query *ctl, char *buf)
}
n = 0;
- if (ctl->mda)
+ if (ctl->mda || ctl->bsmtp)
n = fwrite(buf, 1, last - buf, sinkfp);
else if (ctl->smtp_socket != -1)
n = SockWrite(ctl->smtp_socket, buf, last - buf);
@@ -253,7 +253,55 @@ int open_sink(struct query *ctl,
*bad_addresses = *good_addresses = 0;
- if (ctl->mda) /* we have a declared MDA */
+ if (ctl->bsmtp) /* dump to a BSMTP batch file */
+ {
+ if (strcmp(ctl->bsmtp, "-") == 0)
+ sinkfp = stdout;
+ else
+ sinkfp = fopen(ctl->bsmtp, "a");
+
+ /* see the ap computation under the SMTP branch */
+ fprintf(sinkfp,
+ "MAIL FROM: %s", (return_path[0]) ? return_path : user);
+
+ if (ctl->pass8bits || (ctl->mimemsg & MSG_IS_8BIT))
+ fputs(" BODY=8BITMIME", sinkfp);
+ else if (ctl->mimemsg & MSG_IS_7BIT)
+ fputs(" BODY=7BIT", sinkfp);
+
+ fprintf(sinkfp, " SIZE=%ld\r\n", reallen);
+
+ /*
+ * RFC 1123 requires that the domain name part of the
+ * RCPT TO address be "canonicalized", that is a FQDN
+ * or MX but not a CNAME. Some listeners (like exim)
+ * enforce this. Now that we have the actual hostname,
+ * compute what we should canonicalize with.
+ */
+ ctl->destaddr = ctl->smtpaddress ? ctl->smtpaddress : "localhost";
+
+ *bad_addresses = 0;
+ for (idp = xmit_names; idp; idp = idp->next)
+ if (idp->val.status.mark == XMIT_ACCEPT)
+ {
+ if (strchr(idp->id, '@'))
+ fprintf(sinkfp,
+ "RCPT TO: %s\r\n", idp->id);
+ else
+ fprintf(sinkfp,
+ "RCPT TO: %s@%s\r\n", idp->id, ctl->destaddr);
+ *good_addresses = 0;
+ }
+
+ fputs("DATA\r\n", sinkfp);
+
+ if (ferror(sinkfp))
+ {
+ error(0, -1, "BSMTP file open or preamble write failed");
+ return(PS_BSMTP);
+ }
+ }
+ else if (ctl->mda) /* we have a declared MDA */
{
int length = 0, fromlen = 0, nameslen = 0;
char *names = NULL, *before, *after, *from = NULL;
@@ -399,7 +447,7 @@ int open_sink(struct query *ctl,
sigchld = signal(SIGCHLD, SIG_DFL);
}
- else
+ else /* forward to an SMTP listener */
{
const char *ap;
char options[MSGBUFSIZE], addr[128];
@@ -574,7 +622,9 @@ int open_sink(struct query *ctl,
void release_sink(struct query *ctl)
/* release the per-message output sink, whether it's a pipe or SMTP socket */
{
- if (ctl->mda)
+ if (ctl->bsmtp)
+ fclose(sinkfp);
+ else if (ctl->mda)
{
if (sinkfp)
{
@@ -607,6 +657,18 @@ int close_sink(struct query *ctl, flag forward)
return(FALSE);
}
}
+ else if (ctl->bsmtp)
+ {
+ /* implicit disk-full check here... */
+ fputs("..\r\n", sinkfp);
+ if (strcmp(ctl->bsmtp, "-"))
+ fclose(sinkfp);
+ if (ferror(sinkfp))
+ {
+ error(0, -1, "Message termination or close of BSMTP file failed");
+ return(FALSE);
+ }
+ }
else if (forward)
{
/* write message terminator */