aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--conf.c1
-rw-r--r--design-notes.html17
-rw-r--r--fetchmail.c9
-rw-r--r--fetchmail.h1
-rw-r--r--fetchmail.man17
-rwxr-xr-xfetchmailconf18
-rw-r--r--options.c70
-rw-r--r--rcfile_l.l1
-rw-r--r--rcfile_y.y6
-rw-r--r--sink.c44
11 files changed, 122 insertions, 65 deletions
diff --git a/NEWS b/NEWS
index 9db1077d..8d800777 100644
--- a/NEWS
+++ b/NEWS
@@ -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.
diff --git a/conf.c b/conf.c
index e7f9f9c9..24f71a37 100644
--- a/conf.c
+++ b/conf.c
@@ -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">&lt;esr@snark.thyrsus.com&gt;</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?',
diff --git a/options.c b/options.c
index 0832b892..9d8cc486 100644
--- a/options.c
+++ b/options.c
@@ -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"));
diff --git a/rcfile_l.l b/rcfile_l.l
index d86f790b..92466316 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -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; }
diff --git a/rcfile_y.y b/rcfile_y.y
index 19e788d5..7935ba17 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -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;}
diff --git a/sink.c b/sink.c
index 9a1ef93c..72d97904 100644
--- a/sink.c
+++ b/sink.c
@@ -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));
}
}