diff options
author | Eric S. Raymond <esr@thyrsus.com> | 1999-02-07 21:06:13 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 1999-02-07 21:06:13 +0000 |
commit | 207f1d7aa75ebf4cd695fc1bc735dc98c49cc5f5 (patch) | |
tree | 23b00b775bf6fd70d6b43a8429910f0969a5e738 | |
parent | 683373ce143e698b1455452f83341f75e0f31135 (diff) | |
download | fetchmail-207f1d7aa75ebf4cd695fc1bc735dc98c49cc5f5.tar.gz fetchmail-207f1d7aa75ebf4cd695fc1bc735dc98c49cc5f5.tar.bz2 fetchmail-207f1d7aa75ebf4cd695fc1bc735dc98c49cc5f5.zip |
Added bouncemail option.
svn path=/trunk/; revision=2382
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | conf.c | 1 | ||||
-rw-r--r-- | design-notes.html | 17 | ||||
-rw-r--r-- | fetchmail.c | 9 | ||||
-rw-r--r-- | fetchmail.h | 1 | ||||
-rw-r--r-- | fetchmail.man | 17 | ||||
-rwxr-xr-x | fetchmailconf | 18 | ||||
-rw-r--r-- | options.c | 70 | ||||
-rw-r--r-- | rcfile_l.l | 1 | ||||
-rw-r--r-- | rcfile_y.y | 6 | ||||
-rw-r--r-- | sink.c | 44 |
11 files changed, 122 insertions, 65 deletions
@@ -10,6 +10,9 @@ fetchmail-4.7.8 (): * FreeBSD support for interface and monitor options by Andy Doran <ad@psn.ie>. * Fixed server-deletion bug in fetchmailconf. * Timestamps now generated into logfiles at start of poll cycle. +* New `nobounce' debugging option (specifically exempted from feature freeze) + allows SMTP error bouncemail to be redirected from sender to local + postmaster. There are 257 people on fetchmail-friends and 348 on fetchmail-announce. @@ -188,6 +188,7 @@ void dump_config(struct runctl *runp, struct query *querylist) stringdump("logfile", runp->logfile); stringdump("idfile", runp->idfile); stringdump("postmaster", runp->postmaster); + booldump("bouncemail", runp->bouncemail); stringdump("properties", runp->properties); booldump("invisible", runp->invisible); booldump("syslog", runp->use_syslog); diff --git a/design-notes.html b/design-notes.html index 8a48ba6f..fcc446bf 100644 --- a/design-notes.html +++ b/design-notes.html @@ -10,7 +10,7 @@ <table width="100%" cellpadding=0><tr> <td width="30%">Back to <a href="/~esr/index.html">Fetchmail Home Page</a> <td width="30%" align=center>To <a href="/~esr/sitemap.html">Site Map</a> -<td width="30%" align=right>$Date: 1999/01/01 18:49:07 $ +<td width="30%" align=right>$Date: 1999/02/07 21:06:09 $ </table> <HR> <H1 ALIGN=CENTER>Design Notes On Fetchmail</H1> @@ -318,15 +318,15 @@ a lot of fiddly details in the process. You'll need to do the following minimum steps. <UL> -<LI>Add a field to represent the control in <code>struct query</code> or - <code>struct hostdata</code>. - -<LI>Pick a token to declare the option in the .fetchmailrc file. Add - the token to <code>rcfile_l</code>. +<LI>Add a field to represent the control in <code>struct run</code>, + <code>struct query</code>, or <code>struct hostdata</code>. <LI>Go to <code>rcfile_y.y</code>. Add the token to the grammar. Don't forget the <code>%token</code> declaration. +<LI>Pick an actual string to declare the option in the .fetchmailrc file. Add + the token to <code>rcfile_l</code>. + <LI>Pick a long-form option name, and a one-letter short option if any are left. Go to <code>options.c</code>. Pick a new <code>LA_</code> value. Hack the <code>longoptions</code> table to set up the @@ -339,7 +339,8 @@ following minimum steps. <LI>Add code to dump the option value in <code>fetchmail.c:dump_params</code>. <LI>Add proper <code>FLAG_MERGE</code> actions in fetchmail.c's - optmerge() function. + optmerge() function. (If it's a global option, add an override + at the end of load_params. <LI>Document the option in fetchmail.man. This will require at least two changes; one to the collected table of options, and one full @@ -530,7 +531,7 @@ all shaped the design in one way or another.<P> <table width="100%" cellpadding=0><tr> <td width="30%">Back to <a href="index.html">Fetchmail Home Page</a> <td width="30%" align=center>To <a href="/~esr/sitemap.html">Site Map</a> -<td width="30%" align=right>$Date: 1999/01/01 18:49:07 $ +<td width="30%" align=right>$Date: 1999/02/07 21:06:09 $ </table> <P><ADDRESS>Eric S. Raymond <A HREF="mailto:esr@thyrsus.com"><esr@snark.thyrsus.com></A></ADDRESS> diff --git a/fetchmail.c b/fetchmail.c index 03af1481..cfbbb863 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -874,6 +874,8 @@ static int load_params(int argc, char **argv, int optind) struct passwd *pw; struct query def_opts, *ctl; + run.bouncemail = TRUE; + memset(&def_opts, '\0', sizeof(struct query)); def_opts.smtp_socket = -1; def_opts.smtpaddress = (char *)0; @@ -1161,6 +1163,8 @@ static int load_params(int argc, char **argv, int optind) run.use_syslog = (cmd_run.use_syslog == FLAG_TRUE); if (cmd_run.postmaster) run.postmaster = cmd_run.postmaster; + if (cmd_run.bouncemail) + run.bouncemail = cmd_run.bouncemail; /* check and daemon options are not compatible */ if (check_only && run.poll_interval) @@ -1351,6 +1355,11 @@ static void dump_params (struct runctl *runp, printf(_("Fetchmail will forward misaddressed multidrop messages to %s.\n"), runp->postmaster); + if (!runp->bouncemail) + printf(_("Fetchmail will direct error mail to the postmaster.\n")); + else if (outlevel >= O_VERBOSE) + printf(_("Fetchmail will direct error mail to the sender.\n")); + for (ctl = querylist; ctl; ctl = ctl->next) { if (!ctl->active || (implicit && ctl->server.skip)) diff --git a/fetchmail.h b/fetchmail.h index e0e53933..3549130a 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -104,6 +104,7 @@ struct runctl char *idfile; int poll_interval; char *postmaster; + flag bouncemail; char *properties; flag use_syslog; flag invisible; diff --git a/fetchmail.man b/fetchmail.man index 0cb7f688..8005cc6e 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -765,6 +765,12 @@ can be found. Normally this is just the user who invoked fetchmail. If the invoking user is root, then the default of this option is the user `postmaster'. .PP +The +.B --nobounce +option suppresses the normal action of bouncing errors back to the +sender in an RFC1894-conformant error message. If nobounce is on, the +message will go to the postmaster instead. +.PP The .B --invisible option (keyword: set invisible) tries to make fetchmail invisible. @@ -956,6 +962,9 @@ T} set postmaster \& T{ Give the name of the last-resort mail recipient T} +set nobouncemail \& T{ +Direct error mail to postmaster rather than sender +T} set logfile \& T{ Name of a file to dump error and status messages to T} @@ -1216,10 +1225,10 @@ of `dns', `checkalias', `localdomains', and `aka' for details on how matching addresses are handled. .PP If \fIfetchmail\fR cannot match any mailserver usernames or -localdomain addresses, the default recipient is the value of the -`postmaster' global option if that has been set; otherwise it's the -calling user (as set by the USER or LOGNAME variable in the -environment). +localdomain addresses, the mail will be bounced. +Normally it will be bounced to the sender, but if `nobounce' is on +it will go to the postmaster (which in turn defaults to being the +calling user). .PP The `dns' option (normally on) controls the way addresses from multidrop mailboxes are checked. On, it enables logic to check each diff --git a/fetchmailconf b/fetchmailconf index 75e0de01..9537cb14 100755 --- a/fetchmailconf +++ b/fetchmailconf @@ -19,6 +19,7 @@ class Configuration: self.logfile = None # No logfile, initially self.idfile = os.environ["HOME"] + "/.fetchids" # Default idfile, initially self.postmaster = None # No last-resort address, initially + self.bouncemail = TRUE # Vounce errors to users self.properties = None # No exiguous properties self.invisible = FALSE # Suppress Received line & spoof? self.syslog = FALSE # Use syslogd for logging? @@ -28,6 +29,7 @@ class Configuration: ('logfile', 'String'), ('idfile', 'String'), ('postmaster', 'String'), + ('bouncemail', 'Boolean'), ('properties', 'String'), ('syslog', 'Boolean'), ('invisible', 'Boolean')) @@ -42,6 +44,10 @@ class Configuration: str = str + ("set idfile \"%s\"\n" % (self.idfile,)); if self.postmaster != ConfigurationDefaults.postmaster: str = str + ("set postmaster \"%s\"\n" % (self.postmaster,)); + if self.bouncemail: + str = str + ("set bouncemail\n") + else: + str = str + ("set nobouncemail\n") if self.properties != ConfigurationDefaults.properties: str = str + ("set properties \"%s\"\n" % (self.properties,)); if self.poll_interval > 0: @@ -591,6 +597,10 @@ Postmaster invoking user as the address of last resort unless that user is root. If that user is root, fetchmail sends to `postmaster'. +Bounces to sender? + If this option is on (the default) error mail goes to the sender. + Otherwise it goes to the postmaster. + Invisible If false (the default) fetchmail generates a Received line into each message and generates a HELO from the machine it is running on. @@ -658,6 +668,7 @@ class ConfigurationEdit(Frame, MyWidget): # Set the postmaster log = LabeledEntry(ff, ' Postmaster:', self.postmaster, '14') log.pack(side=RIGHT, anchor=E) + # Set the poll interval de = LabeledEntry(ff, ' Poll interval:', self.poll_interval, '14') de.pack(side=RIGHT, anchor=E) @@ -666,6 +677,13 @@ class ConfigurationEdit(Frame, MyWidget): df.pack() if self.mode != 'novice': + pf = Frame(gf) + Checkbutton(pf, + {'text':'Bounces to sender?', + 'variable':self.bouncemail, + 'relief':GROOVE}).pack(side=LEFT, anchor=W) + pf.pack(fill=X) + sf = Frame(gf) Checkbutton(sf, {'text':'Log to syslog?', @@ -37,38 +37,39 @@ #define LA_RCFILE 13 #define LA_IDFILE 14 #define LA_POSTMASTER 15 -#define LA_PROTOCOL 16 -#define LA_UIDL 17 -#define LA_PORT 18 -#define LA_AUTHENTICATE 19 -#define LA_TIMEOUT 20 -#define LA_ENVELOPE 21 -#define LA_QVIRTUAL 22 -#define LA_USERNAME 23 -#define LA_ALL 24 -#define LA_NOKEEP 25 -#define LA_KEEP 26 -#define LA_FLUSH 27 -#define LA_NOREWRITE 28 -#define LA_LIMIT 29 -#define LA_WARNINGS 30 -#define LA_FOLDER 31 -#define LA_SMTPHOST 32 -#define LA_SMTPADDR 33 -#define LA_ANTISPAM 34 -#define LA_BATCHLIMIT 35 -#define LA_FETCHLIMIT 36 -#define LA_EXPUNGE 37 -#define LA_MDA 38 -#define LA_BSMTP 39 -#define LA_LMTP 40 -#define LA_PLUGIN 41 -#define LA_PLUGOUT 42 -#define LA_NETSEC 43 -#define LA_INTERFACE 44 -#define LA_MONITOR 45 -#define LA_CONFIGDUMP 46 -#define LA_YYDEBUG 47 +#define LA_NOBOUNCE 16 +#define LA_PROTOCOL 17 +#define LA_UIDL 18 +#define LA_PORT 19 +#define LA_AUTHENTICATE 20 +#define LA_TIMEOUT 21 +#define LA_ENVELOPE 22 +#define LA_QVIRTUAL 23 +#define LA_USERNAME 24 +#define LA_ALL 25 +#define LA_NOKEEP 26 +#define LA_KEEP 27 +#define LA_FLUSH 28 +#define LA_NOREWRITE 29 +#define LA_LIMIT 30 +#define LA_WARNINGS 31 +#define LA_FOLDER 32 +#define LA_SMTPHOST 33 +#define LA_SMTPADDR 34 +#define LA_ANTISPAM 35 +#define LA_BATCHLIMIT 36 +#define LA_FETCHLIMIT 37 +#define LA_EXPUNGE 38 +#define LA_MDA 39 +#define LA_BSMTP 40 +#define LA_LMTP 41 +#define LA_PLUGIN 42 +#define LA_PLUGOUT 43 +#define LA_NETSEC 44 +#define LA_INTERFACE 45 +#define LA_MONITOR 46 +#define LA_CONFIGDUMP 47 +#define LA_YYDEBUG 48 /* options still left: CDgGhHjJoORwWxXYz */ static const char *shortoptions = @@ -91,6 +92,7 @@ static const struct option longoptions[] = { {"fetchmailrc",required_argument,(int *) 0, LA_RCFILE }, {"idfile", required_argument, (int *) 0, LA_IDFILE }, {"postmaster",required_argument, (int *) 0, LA_POSTMASTER }, + {"nobounce", no_argument, (int *) 0, LA_NOBOUNCE }, {"protocol", required_argument, (int *) 0, LA_PROTOCOL }, {"proto", required_argument, (int *) 0, LA_PROTOCOL }, @@ -297,6 +299,9 @@ struct query *ctl; /* option record to be initialized */ rctl->postmaster = (char *) xmalloc(strlen(optarg)+1); strcpy(rctl->postmaster,optarg); break; + case LA_NOBOUNCE: + run.bouncemail = FALSE; + break; case 'p': case LA_PROTOCOL: /* XXX -- should probably use a table lookup here */ @@ -565,6 +570,7 @@ struct query *ctl; /* option record to be initialized */ P(_(" -f, --fetchmailrc specify alternate run control file\n")); P(_(" -i, --idfile specify alternate UIDs file\n")); P(_(" --postmaster specify recipient of last resort\n")); + P(_(" --nobounce redirect bounces from user to postmaster.")); #if (defined(linux) && !INET6) || defined(__FreeBSD__) P(_(" -I, --interface interface required specification\n")); P(_(" -M, --monitor monitor interface for activity\n")); @@ -28,6 +28,7 @@ daemon { return DAEMON; } syslog { return SYSLOG; } invisible { return INVISIBLE; } postmaster { return POSTMASTER; } +bouncemail { return BOUNCEMAIL; } warnings { return WARNINGS; } defaults { return DEFAULTS; } @@ -60,11 +60,11 @@ 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 BSMTP LMTP -%token SMTPADDRESS SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT +%token SMTPADDRESS SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS %token NETSEC INTERFACE MONITOR PLUGIN PLUGOUT %token IS HERE THERE TO MAP WILDCARD %token BATCHLIMIT FETCHLIMIT EXPUNGE PROPERTIES -%token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE POSTMASTER WARNINGS +%token SET LOGFILE DAEMON SYSLOG IDFILE INVISIBLE POSTMASTER BOUNCEMAIL %token <proto> PROTO %token <sval> STRING %token <number> NUMBER @@ -88,6 +88,8 @@ statement : SET LOGFILE optmap STRING {run.logfile = xstrdup($4);} | SET IDFILE optmap STRING {run.idfile = xstrdup($4);} | SET DAEMON optmap NUMBER {run.poll_interval = $4;} | SET POSTMASTER optmap STRING {run.postmaster = xstrdup($4);} + | SET BOUNCEMAIL {run.bouncemail = TRUE;} + | SET NO BOUNCEMAIL {run.bouncemail = FALSE;} | SET PROPERTIES optmap STRING {run.properties =xstrdup($4);} | SET SYSLOG {run.use_syslog = TRUE;} | SET INVISIBLE {run.invisible = TRUE;} @@ -252,18 +252,21 @@ static void sanitize(char *s) *cp = '_'; } -static int send_bouncemail(struct msgblk *msg, int userclass, - char *message, int nerrors, char *errors[]) +static int send_bouncemail(struct query *ctl, struct msgblk *msg, + int userclass, char *message, + int nerrors, char *errors[]) /* bounce back an error report a la RFC 1892 */ { char daemon_name[18 + HOSTLEN] = "FETCHMAIL-DAEMON@"; - char boundary[BUFSIZ], *ts; + char boundary[BUFSIZ], *ts, *bounce_to; int sock; /* don't bounce in reply to undeliverable bounces */ if (!msg->return_path[0] || strcmp(msg->return_path, "<>") == 0) return(FALSE); + bounce_to = (run.bouncemail ? msg->return_path : run.postmaster); + SMTP_setmode(SMTP_MODE); strcat(daemon_name, fetchmailhost); @@ -273,7 +276,7 @@ static int send_bouncemail(struct msgblk *msg, int userclass, || SMTP_ok(sock) != SM_OK || SMTP_helo(sock, "localhost") != SM_OK || SMTP_from(sock, daemon_name, (char *)NULL) != SM_OK - || SMTP_rcpt(sock, msg->return_path) != SM_OK + || SMTP_rcpt(sock, bounce_to) != SM_OK || SMTP_data(sock) != SM_OK) return(FALSE); @@ -289,7 +292,7 @@ static int send_bouncemail(struct msgblk *msg, int userclass, /* bouncemail headers */ SockPrintf(sock, "Return-Path: <>\r\n"); SockPrintf(sock, "From: %s\r\n", daemon_name); - SockPrintf(sock, "To: %s\r\n", msg->return_path); + SockPrintf(sock, "To: %s\r\n", bounce_to); SockPrintf(sock, "MIME-Version: 1.0\r\n"); SockPrintf(sock, "Content-Type: multipart/report; report-type=delivery-status;\r\n\tboundary=\"%s\"\r\n", boundary); SockPrintf(sock, "\r\n"); @@ -367,6 +370,7 @@ static int send_bouncemail(struct msgblk *msg, int userclass, static int handle_smtp_report(struct query *ctl, struct msgblk *msg) /* handle SMTP errors based on the content of SMTP_response */ +/* Mail is deleted from the server if this function returns PS_REFUSED. */ { int smtperr = atoi(smtp_response); char *responses[1]; @@ -399,7 +403,7 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) * 571 = sendmail's "unsolicited email refused" * */ - send_bouncemail(msg, XMIT_ACCEPT, + send_bouncemail(ctl, msg, XMIT_ACCEPT, "Our spam filter rejected this transaction.\r\n", 1, responses); return(PS_REFUSED); @@ -439,26 +443,26 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) * ESMTP server. Don't try to ship the message, * and allow it to be deleted. */ - send_bouncemail(msg, XMIT_ACCEPT, + send_bouncemail(ctl, msg, XMIT_ACCEPT, "This message was too large.\r\n", 1, responses); - return(PS_REFUSED); - + return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT); + case 553: /* invalid sending domain */ /* * These latter days 553 usually means a spammer is trying to * cover his tracks. */ - send_bouncemail(msg, XMIT_ACCEPT, + send_bouncemail(ctl, msg, XMIT_ACCEPT, "Invalid address.\r\n", 1, responses); return(PS_REFUSED); default: /* bounce the error back to the sender */ - if (send_bouncemail(msg, XMIT_ACCEPT, + if (send_bouncemail(ctl, msg, XMIT_ACCEPT, "General SMTP/ESMTP error.\r\n", 1, responses)) - return(PS_REFUSED); + return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT); else return(PS_TRANSIENT); } @@ -761,7 +765,7 @@ int open_sink(struct query *ctl, struct msgblk *msg, } } if (*bad_addresses) - send_bouncemail(msg, XMIT_RCPTBAD, + send_bouncemail(ctl, msg, XMIT_RCPTBAD, "Some addresses were rejected by the MDA fetchmail forwards to.\r\n", *bad_addresses, from_responses); /* @@ -941,13 +945,15 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward) else /* * One or more deliveries failed. - * If we can bounce a failures list back to the sender, - * return TRUE, deleting the message from the server so - * it won't be re-forwarded on subsequent poll cycles. + * If we can bounce a failures list back to the + * sender, and the postmaster does not want to + * deal with the bounces return TRUE, deleting the + * message from the server so it won't be + * re-forwarded on subsequent poll cycles. */ - return(send_bouncemail(msg, XMIT_ACCEPT, - "LSMTP partial delivery failure.\r\n", - errors, responses)); + return(send_bouncemail(ctl, msg, XMIT_ACCEPT, + "LSMTP partial delivery failure.\r\n", + errors, responses)); } } |