#endif
/* makes the open_sink()/close_sink() pair non-reentrant */
-static lmtp_responses;
+static int lmtp_responses;
static int smtp_open(struct query *ctl)
/* try to open a socket to the appropriate SMTP server for this query */
{
/* maybe it's time to close the socket in order to force delivery */
- if (NUM_NONZERO(ctl->batchlimit) && (ctl->smtp_socket != -1) && batchcount++ == ctl->batchlimit)
+ if (NUM_NONZERO(ctl->batchlimit) && (ctl->smtp_socket != -1) && ++batchcount == ctl->batchlimit)
{
close(ctl->smtp_socket);
ctl->smtp_socket = -1;
for (idp = ctl->smtphunt; idp; idp = idp->next)
{
char *cp, *parsed_host;
-#ifdef INET6
+#ifdef INET6_ENABLE
char *portnum = SMTP_PORT;
#else
int portnum = SMTP_PORT;
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
xalloca(parsed_host, char *, strlen(idp->id) + 1);
if ((cp = strrchr(parsed_host, '/')))
{
*cp++ = 0;
-#ifdef INET6
+#ifdef INET6_ENABLE
portnum = cp;
#else
portnum = atoi(cp);
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
}
if ((ctl->smtp_socket = SockOpen(parsed_host,portnum,NULL,
ctl->destaddr = ctl->smtpaddress ? ctl->smtpaddress : ( ctl->smtphost ? ctl->smtphost : "localhost");
if (outlevel >= O_DEBUG && ctl->smtp_socket != -1)
- report(stdout, 0, _("forwarding to %s"), ctl->smtphost);
+ report(stdout, _("forwarding to %s\n"), ctl->smtphost);
return(ctl->smtp_socket);
}
* decorated any . lines it sends back up.
*/
if (*buf == '.')
+ {
if (ctl->server.base_protocol->delimited) /* server has already byte-stuffed */
{
if (ctl->mda)
else
/* leave it alone */;
}
+ }
/* we may need to strip carriage returns */
if (ctl->stripcr)
*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);
|| 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);
sprintf(boundary,
"om-mani-padme-hum-%d-%d-%ld",
- getpid(), getppid(), time((time_t *)NULL));
+ (int)getpid(), (int)getppid(), time((time_t *)NULL));
ts = rfc822timestamp();
if (outlevel >= O_VERBOSE)
- report(stdout, 0, "SMTP: (bounce-message body)");
+ report(stdout, "SMTP: (bounce-message body)\n");
/* 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");
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];
- responses[0] = smtp_response;
-
- /* required by RFC1870; sets us up to be able to send bouncemail */
- SMTP_rset(ctl->smtp_socket);
+ xalloca(responses[0], char *, strlen(smtp_response)+1);
+ strcpy(responses[0], smtp_response);
/*
* Note: send_bouncemail message strings are not made subject
* coming from this address, probably due to an
* anti-spam domain exclusion. Respect this. Don't
* try to ship the message, and don't prevent it from
- * being deleted. Typical values:
+ * being deleted. Default values:
*
- * 501 = exim's old antispam response
- * 550 = exim's new antispam response (temporary)
- * 553 = sendmail 8.8.7's generic REJECT
* 571 = sendmail's "unsolicited email refused"
+ * 550 = exim's new antispam response (temporary)
+ * 501 = exim's old antispam response
+ * 554 = Postfix antispam response.
*
*/
- send_bouncemail(msg, XMIT_ACCEPT,
+ SMTP_rset(ctl->smtp_socket); /* stay on the safe site */
+ send_bouncemail(ctl, msg, XMIT_ACCEPT,
"Our spam filter rejected this transaction.\r\n",
1, responses);
return(PS_REFUSED);
* an error when the return code is less specific.
*/
if (smtperr >= 400)
- report(stderr, 0, _("%cMTP error: %s"),
+ report(stderr, _("%cMTP error: %s\n"),
ctl->listener,
smtp_response);
* this is not an actual failure, we're very likely to be
* able to recover on the next cycle.
*/
+ SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
return(PS_TRANSIENT);
case 552: /* message exceeds fixed maximum message size */
* ESMTP server. Don't try to ship the message,
* and allow it to be deleted.
*/
- send_bouncemail(msg, XMIT_ACCEPT,
+ SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
+ 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.
+ * cover his tracks. We never bouncemail on these, because
+ * (a) the return address is invalid by definition, and
+ * (b) we wouldn't want spammers to get confirmation that
+ * this address is live, anyway.
*/
- send_bouncemail(msg, XMIT_ACCEPT,
+ SMTP_rset(ctl->smtp_socket); /* stay on the safe side */
+ 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,
- "General SMTP/ESMTP error.\r\n",
- 1, responses))
- return(PS_REFUSED);
- else
- return(PS_TRANSIENT);
+ default: /* bounce non-transient errors back to the sender */
+ SMTP_rset(ctl->smtp_socket); /* stay on the safe side */
+ if (smtperr >= 500 && smtperr <= 599)
+ if (send_bouncemail(ctl, msg, XMIT_ACCEPT,
+ "General SMTP/ESMTP error.\r\n",
+ 1, responses))
+ return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT);
+ return(PS_TRANSIENT);
}
}
if (ferror(sinkfp))
{
- report(stderr, 0, _("BSMTP file open or preamble write failed"));
+ report(stderr, _("BSMTP file open or preamble write failed\n"));
return(PS_BSMTP);
}
}
if (outlevel >= O_DEBUG)
- report(stdout, 0, _("about to deliver with: %s"), before);
+ report(stdout, _("about to deliver with: %s\n"), before);
#ifdef HAVE_SETEUID
/*
if (!sinkfp)
{
- report(stderr, 0, _("MDA open failed"));
+ report(stderr, _("MDA open failed\n"));
return(PS_IOERR);
}
/* build a connection to the SMTP listener */
if ((smtp_open(ctl) == -1))
{
- report(stderr, errno, _("%cMTP connect to %s failed"),
+ report(stderr, _("%cMTP connect to %s failed\n"),
ctl->listener,
ctl->smtphost ? ctl->smtphost : "localhost");
return(PS_SMTP);
(*bad_addresses)++;
idp->val.status.mark = XMIT_RCPTBAD;
if (outlevel >= O_VERBOSE)
- report(stderr, 0,
- _("%cMTP listener doesn't like recipient address `%s'"),
+ report(stderr,
+ _("%cMTP listener doesn't like recipient address `%s'\n"),
ctl->listener, addr);
}
}
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);
/*
if (SMTP_rcpt(ctl->smtp_socket, addr) != SM_OK)
{
- report(stderr, 0, _("can't even send to %s!"), run.postmaster);
+ report(stderr, _("can't even send to %s!\n"), run.postmaster);
SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
return(PS_SMTP);
}
if (outlevel >= O_VERBOSE)
- report(stderr, 0, _("no address matches; forwarding to %s."), run.postmaster);
+ report(stderr, _("no address matches; forwarding to %s.\n"), run.postmaster);
}
/*
signal(SIGCHLD, sigchld);
if (rc)
{
- report(stderr, 0, _("MDA exited abnormally or returned nonzero status"));
+ report(stderr,
+ _("MDA exited abnormally or returned nonzero status\n"));
return(FALSE);
}
}
fclose(sinkfp);
if (ferror(sinkfp))
{
- report(stderr, 0, _("Message termination or close of BSMTP file failed"));
+ report(stderr,
+ _("Message termination or close of BSMTP file failed\n"));
return(FALSE);
}
}
return(FALSE);
else
{
- report(stderr, 0, _("SMTP listener refused delivery"));
+ report(stderr, _("SMTP listener refused delivery\n"));
return(TRUE);
}
}
* to people who got it the first time.
*/
if (ctl->listener == LMTP_MODE)
+ {
if (lmtp_responses == 0)
{
SMTP_ok(ctl->smtp_socket);
* comply.
*/
if (atoi(smtp_response) == 503)
- report(stderr, 0, _("LMTP delivery error on EOM"));
+ report(stderr, _("LMTP delivery error on EOM\n"));
else
- report(stderr, 0,
- _("Unexpected non-503 response to LMTP EOM: %s"),
+ report(stderr,
+ _("Unexpected non-503 response to LMTP EOM: %s\n"),
smtp_response);
/*
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));
}
+ }
}
return(TRUE);