diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | fetchmail.c | 5 | ||||
-rw-r--r-- | fetchmail.h | 15 | ||||
-rw-r--r-- | fetchmail.man | 14 | ||||
-rwxr-xr-x | fetchmailconf | 6 | ||||
-rw-r--r-- | options.c | 20 | ||||
-rw-r--r-- | rcfile_l.l | 1 | ||||
-rw-r--r-- | rcfile_y.y | 5 | ||||
-rw-r--r-- | sample.rcfile | 1 | ||||
-rw-r--r-- | sink.c | 70 |
10 files changed, 119 insertions, 21 deletions
@@ -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) @@ -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); @@ -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; } @@ -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 # @@ -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 */ |