/* these are shared by open_sink and stuffline */
static FILE *sinkfp;
+#ifndef HAVE_SIGACTION
static RETSIGTYPE (*sigchld)(int);
+#else
+static struct sigaction sa_old;
+#endif /* HAVE_SIGACTION */
int stuffline(struct query *ctl, char *buf)
/* ship a line to the given control block's output sink (SMTP server or MDA) */
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. */
+/* return of PS_REFUSED deletes mail from the server; PS_TRANSIENT keeps it */
{
int smtperr = atoi(smtp_response);
char *responses[1];
xalloca(responses[0], char *, strlen(smtp_response)+1);
strcpy(responses[0], smtp_response);
+ SMTP_rset(ctl->smtp_socket); /* stay on the safe site */
+
+ if (outlevel >= O_DEBUG)
+ report(stdout, "Saved error is still %d\n", smtperr);
+
/*
* Note: send_bouncemail message strings are not made subject
* to gettext translation because (a) they're going to be
* 554 = Postfix antispam response.
*
*/
- 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);
switch (smtperr)
{
- case 452: /* insufficient system storage */
- /*
- * Temporary out-of-queue-space condition on the
- * ESMTP server. Don't try to ship the message,
- * and suppress deletion so it can be retried on
- * a future retrieval cycle.
- *
- * Bouncemail *might* be appropriate here as a delay
- * notification (note; if we ever add this, we must make
- * sure the RFC1894 Action field is "delayed" rather thwn
- * "failed"). But it's not really necessary because
- * 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 */
/*
* Permanent no-go condition on the
* ESMTP server. Don't try to ship the message,
* and allow it to be deleted.
*/
- SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
send_bouncemail(ctl, msg, XMIT_ACCEPT,
- "This message was too large.\r\n",
+ "This message was too large (SMTP error 552).\r\n",
1, responses);
return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT);
* (b) we wouldn't want spammers to get confirmation that
* this address is live, anyway.
*/
- SMTP_rset(ctl->smtp_socket); /* stay on the safe side */
send_bouncemail(ctl, msg, XMIT_ACCEPT,
- "Invalid address.\r\n",
+ "Invalid address in MAIL FROM (SMTP error 553).\r\n",
1, responses);
return(PS_REFUSED);
- default: /* bounce non-transient errors back to the sender */
- SMTP_rset(ctl->smtp_socket); /* stay on the safe side */
+ default:
+ /* bounce non-transient errors back to the sender */
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);
+ /*
+ * We're going to end up here on 4xx errors, like:
+ *
+ * 451: temporarily unable to identify sender (exim)
+ * 452: temporary out-of-queue-space condition on the ESMTP server.
+ *
+ * These are temporary errors. Don't try to ship the message,
+ * and suppress deletion so it can be retried on a future
+ * retrieval cycle.
+ *
+ * Bouncemail *might* be appropriate here as a delay
+ * notification (note; if we ever add this, we must make
+ * sure the RFC1894 Action field is "delayed" rather thwn
+ * "failed"). But it's not really necessary because
+ * these are not actual failures, we're very likely to be
+ * able to recover on the next cycle.
+ */
return(PS_TRANSIENT);
}
}
/* set up sinkfp to be an input sink we can ship a message to */
{
struct idlist *idp;
+#ifdef HAVE_SIGACTION
+ struct sigaction sa_new;
+#endif /* HAVE_SIGACTION */
*bad_addresses = *good_addresses = 0;
fputs(" BODY=7BIT", sinkfp);
/* exim's BSMTP processor does not handle SIZE */
- /* fprintf(sinkfp, " SIZE=%d\r\n", msg->reallen); */
+ /* fprintf(sinkfp, " SIZE=%d", msg->reallen); */
+
+ fprintf(sinkfp, "\r\n");
/*
* RFC 1123 requires that the domain name part of the
for (idp = msg->recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_ACCEPT)
{
- if (strchr(idp->id, '@'))
- fprintf(sinkfp,
- "RCPT TO: %s\r\n", idp->id);
+ if (ctl->smtpname)
+ fprintf(sinkfp, "RCPT TO: %s\r\n", ctl->smtpname);
+ else 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);
+ "RCPT TO: %s@%s\r\n", idp->id, ctl->destaddr);
*good_addresses = 0;
}
return(PS_IOERR);
}
+#ifndef HAVE_SIGACTION
sigchld = signal(SIGCHLD, SIG_DFL);
+#else
+ memset (&sa_new, 0, sizeof sa_new);
+ sigemptyset (&sa_new.sa_mask);
+ sa_new.sa_handler = SIG_DFL;
+ sigaction (SIGCHLD, &sa_new, &sa_old);
+#endif /* HAVE_SIGACTION */
}
else /* forward to an SMTP or LMTP listener */
{
/*
* Try to get the SMTP listener to take the Return-Path
- * address as MAIL FROM . If it won't, fall back on the
- * calling-user ID. This won't affect replies, which use the
- * header From address anyway.
+ * address as MAIL FROM. If it won't, fall back on the
+ * remotename and mailserver host. This won't affect replies,
+ * which use the header From address anyway; the MAIL FROM
+ * address is a place for the SMTP listener to send
+ * bouncemail. The point is to guarantee a FQDN in the MAIL
+ * FROM line -- some SMTP listeners, like smail, become
+ * unhappy otherwise.
*
* RFC 1123 requires that the domain name part of the
* MAIL FROM address be "canonicalized", that is a
- * FQDN or MX but not a CNAME. We'll assume the From
+ * FQDN or MX but not a CNAME. We'll assume the Return-Path
* header is already in this form here (it certainly
* is if rewrite is on). RFC 1123 is silent on whether
* a nonexistent hostname part is considered canonical.
*
* This is a potential problem if the MTAs further upstream
* didn't pass canonicalized From/Return-Path lines, *and* the
- * local SMTP listener insists on them.
+ * local SMTP listener insists on them.
*/
- ap = (msg->return_path[0]) ? msg->return_path : user;
+ if (!msg->return_path[0])
+ {
+ sprintf(addr, "%s@%s", ctl->remotename, ctl->server.truename);
+ ap = addr;
+ }
+ else if (strchr(msg->return_path, '@'))
+ ap = msg->return_path;
+ else /* in case Return-Path existed but was local */
+ {
+ sprintf(addr, "%s@%s", msg->return_path, ctl->server.truename);
+ ap = addr;
+ }
+
if (SMTP_from(ctl->smtp_socket, ap, options) != SM_OK)
return(handle_smtp_report(ctl, msg));
{
if (strchr(idp->id, '@'))
strcpy(addr, idp->id);
- else
+ else {
+ if (ctl->smtpname) {
#ifdef HAVE_SNPRINTF
- snprintf(addr, sizeof(addr)-1, "%s@%s", idp->id, ctl->destaddr);
+ snprintf(addr, sizeof(addr)-1, "%s", ctl->smtpname);
#else
- sprintf(addr, "%s@%s", idp->id, ctl->destaddr);
+ sprintf(addr, "%s", ctl->smtpname);
#endif /* HAVE_SNPRINTF */
+ } else {
+#ifdef HAVE_SNPRINTF
+ snprintf(addr, sizeof(addr)-1, "%s@%s", idp->id, ctl->destaddr);
+#else
+ sprintf(addr, "%s@%s", idp->id, ctl->destaddr);
+#endif /* HAVE_SNPRINTF */
+ }
+ }
if (SMTP_rcpt(ctl->smtp_socket, addr) == SM_OK)
(*good_addresses)++;
else
pclose(sinkfp);
sinkfp = (FILE *)NULL;
}
+#ifndef HAVE_SIGACTION
signal(SIGCHLD, sigchld);
+#else
+ sigaction (SIGCHLD, &sa_old, NULL);
+#endif /* HAVE_SIGACTION */
}
}
}
else
rc = 0;
+#ifndef HAVE_SIGACTION
signal(SIGCHLD, sigchld);
+#else
+ sigaction (SIGCHLD, &sa_old, NULL);
+#endif /* HAVE_SIGACTION */
if (rc)
{
report(stderr,
}
else if (ctl->bsmtp)
{
+ int error;
+
/* implicit disk-full check here... */
fputs(".\r\n", sinkfp);
+ error = ferror(sinkfp);
if (strcmp(ctl->bsmtp, "-"))
- fclose(sinkfp);
- if (ferror(sinkfp))
+ if (fclose(sinkfp) == EOF) error = 1;
+ if (error)
{
report(stderr,
_("Message termination or close of BSMTP file failed\n"));