summaryrefslogtreecommitdiffstats
path: root/usr.sbin/sendmail/src/savemail.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1995-12-02 17:30:23 +0000
committerpeter <peter@FreeBSD.org>1995-12-02 17:30:23 +0000
commit88797ecc8d2743a86e4e574fadaac061649931a1 (patch)
treec3349cbdc3f0c451b9b3d949b54a30e08ff75375 /usr.sbin/sendmail/src/savemail.c
parent78d9d5927fb62a9d93abb0c1a0027bdd84b89117 (diff)
downloadFreeBSD-src-88797ecc8d2743a86e4e574fadaac061649931a1.zip
FreeBSD-src-88797ecc8d2743a86e4e574fadaac061649931a1.tar.gz
Import Sendmail-8.7.2 as discussed on -current.
The conflict merge will happen shortly after.
Diffstat (limited to 'usr.sbin/sendmail/src/savemail.c')
-rw-r--r--usr.sbin/sendmail/src/savemail.c783
1 files changed, 669 insertions, 114 deletions
diff --git a/usr.sbin/sendmail/src/savemail.c b/usr.sbin/sendmail/src/savemail.c
index 214dca5..78c9149 100644
--- a/usr.sbin/sendmail/src/savemail.c
+++ b/usr.sbin/sendmail/src/savemail.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1983 Eric P. Allman
+ * Copyright (c) 1983, 1995 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -33,11 +33,10 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)savemail.c 8.29 (Berkeley) 5/10/94";
+static char sccsid[] = "@(#)savemail.c 8.87 (Berkeley) 10/28/95";
#endif /* not lint */
# include "sendmail.h"
-# include <pwd.h>
/*
** SAVEMAIL -- Save mail on error
@@ -49,6 +48,8 @@ static char sccsid[] = "@(#)savemail.c 8.29 (Berkeley) 5/10/94";
**
** Parameters:
** e -- the envelope containing the message in error.
+** sendbody -- if TRUE, also send back the body of the
+** message; otherwise just send the header.
**
** Returns:
** none
@@ -74,8 +75,10 @@ static char sccsid[] = "@(#)savemail.c 8.29 (Berkeley) 5/10/94";
# endif
-savemail(e)
+void
+savemail(e, sendbody)
register ENVELOPE *e;
+ bool sendbody;
{
register struct passwd *pw;
register FILE *fp;
@@ -83,8 +86,8 @@ savemail(e)
auto ADDRESS *q = NULL;
register char *p;
MCI mcibuf;
+ int sfflags;
char buf[MAXLINE+1];
- extern struct passwd *getpwnam();
extern char *ttypath();
typedef int (*fnptr)();
extern bool writable();
@@ -143,11 +146,6 @@ savemail(e)
break;
case EM_BERKNET:
- /* mail back, but return o.k. exit status */
- ExitStat = EX_OK;
-
- /* fall through.... */
-
case EM_MAIL:
state = ESM_MAIL;
break;
@@ -187,7 +185,7 @@ savemail(e)
switch (state)
{
case ESM_QUIET:
- if (e->e_from.q_mailer == LocalMailer)
+ if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
state = ESM_DEADLETTER;
else
state = ESM_MAIL;
@@ -207,7 +205,7 @@ savemail(e)
break;
}
- expand("\201n", buf, &buf[sizeof buf - 1], e);
+ expand("\201n", buf, sizeof buf, e);
printf("\r\nMessage from %s...\r\n", buf);
printf("Errors occurred while sending mail.\r\n");
if (e->e_xfp != NULL)
@@ -256,12 +254,12 @@ savemail(e)
if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
{
(void) sendtolist("postmaster",
- NULLADDR, &e->e_errorqueue, e);
+ NULLADDR, &e->e_errorqueue, 0, e);
}
- if (strcmp(e->e_from.q_paddr, "<>") != 0)
+ if (!emptyaddr(&e->e_from))
{
(void) sendtolist(e->e_from.q_paddr,
- NULLADDR, &e->e_errorqueue, e);
+ NULLADDR, &e->e_errorqueue, 0, e);
}
/*
@@ -285,7 +283,7 @@ savemail(e)
break;
}
if (returntosender(e->e_message, e->e_errorqueue,
- (e->e_class >= 0), e) == 0)
+ sendbody, e) == 0)
{
state = ESM_DONE;
break;
@@ -301,15 +299,14 @@ savemail(e)
*/
q = NULL;
- if (sendtolist("postmaster", NULL, &q, e) <= 0)
+ if (sendtolist("postmaster", NULL, &q, 0, e) <= 0)
{
syserr("553 cannot parse postmaster!");
ExitStat = EX_SOFTWARE;
state = ESM_USRTMP;
break;
}
- if (returntosender(e->e_message,
- q, (e->e_class >= 0), e) == 0)
+ if (returntosender(e->e_message, q, sendbody, e) == 0)
{
state = ESM_DONE;
break;
@@ -330,44 +327,36 @@ savemail(e)
*/
p = NULL;
- if (e->e_from.q_mailer == LocalMailer)
+ if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
{
if (e->e_from.q_home != NULL)
p = e->e_from.q_home;
- else if ((pw = getpwnam(e->e_from.q_user)) != NULL)
+ else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
p = pw->pw_dir;
}
- if (p == NULL)
+ if (p == NULL || e->e_dfp == NULL)
{
- /* no local directory */
+ /* no local directory or no data file */
state = ESM_MAIL;
break;
}
- if (e->e_dfp != NULL)
+
+ /* we have a home directory; write dead.letter */
+ define('z', p, e);
+ expand("\201z/dead.letter", buf, sizeof buf, e);
+ sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
+ e->e_to = buf;
+ if (mailfile(buf, NULL, sfflags, e) == EX_OK)
{
bool oldverb = Verbose;
- /* we have a home directory; open dead.letter */
- define('z', p, e);
- expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e);
Verbose = TRUE;
- message("Saving message in %s", buf);
+ message("Saved message in %s", buf);
Verbose = oldverb;
- e->e_to = buf;
- q = NULL;
- (void) sendtolist(buf, &e->e_from, &q, e);
- if (q != NULL &&
- !bitset(QBADADDR, q->q_flags) &&
- deliver(e, q) == 0)
- state = ESM_DONE;
- else
- state = ESM_MAIL;
- }
- else
- {
- /* no data file -- try mailing back */
- state = ESM_MAIL;
+ state = ESM_DONE;
+ break;
}
+ state = ESM_MAIL;
break;
case ESM_USRTMP:
@@ -381,15 +370,19 @@ savemail(e)
break;
}
- strcpy(buf, _PATH_VARTMP);
- strcat(buf, "dead.letter");
- if (!writable(buf, NULLADDR, SFF_NOSLINK))
+ if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
{
state = ESM_PANIC;
break;
}
- fp = dfopen(buf, O_WRONLY|O_CREAT|O_APPEND, FileMode);
- if (fp == NULL)
+
+ strcpy(buf, _PATH_VARTMP);
+ strcat(buf, "dead.letter");
+
+ sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT;
+ if (!writable(buf, NULL, sfflags) ||
+ (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND,
+ FileMode, sfflags)) == NULL)
{
state = ESM_PANIC;
break;
@@ -402,13 +395,26 @@ savemail(e)
mcibuf.mci_flags |= MCIF_7BIT;
putfromline(&mcibuf, e);
- (*e->e_puthdr)(&mcibuf, e);
- putline("\n", &mcibuf);
+ (*e->e_puthdr)(&mcibuf, e->e_header, e);
(*e->e_putbody)(&mcibuf, e, NULL);
putline("\n", &mcibuf);
(void) fflush(fp);
- state = ferror(fp) ? ESM_PANIC : ESM_DONE;
- (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter");
+ if (!ferror(fp))
+ {
+ bool oldverb = Verbose;
+
+ Verbose = TRUE;
+ message("Saved message in %s", buf);
+ Verbose = oldverb;
+#ifdef LOG
+ if (LogLevel > 3)
+ syslog(LOG_NOTICE, "Saved message in %s", buf);
+#endif
+ state = ESM_DONE;
+ break;
+ }
+ state = ESM_PANIC;
+ (void) xfclose(fp, "savemail", buf);
break;
default:
@@ -418,6 +424,7 @@ savemail(e)
case ESM_PANIC:
/* leave the locked queue & transcript files around */
+ loseqfile(e, "savemail panic");
syserr("!554 savemail: cannot save rejected email anywhere");
}
}
@@ -441,24 +448,24 @@ savemail(e)
** mail.
*/
-static bool SendBody;
-
#define MAXRETURNS 6 /* max depth of returning messages */
#define ERRORFUDGE 100 /* nominal size of error message text */
+int
returntosender(msg, returnq, sendbody, e)
char *msg;
ADDRESS *returnq;
bool sendbody;
register ENVELOPE *e;
{
- char buf[MAXNAME];
- extern putheader(), errbody();
register ENVELOPE *ee;
ENVELOPE *oldcur = CurEnv;
ENVELOPE errenvelope;
static int returndepth;
register ADDRESS *q;
+ char *p;
+ char buf[MAXNAME + 1];
+ extern void errbody __P((MCI *, ENVELOPE *, char *));
if (returnq == NULL)
return (-1);
@@ -468,9 +475,14 @@ returntosender(msg, returnq, sendbody, e)
if (tTd(6, 1))
{
- printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
+ printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
msg, returndepth, e);
printaddr(returnq, TRUE);
+ if (tTd(6, 20))
+ {
+ printf("Sendq=");
+ printaddr(e->e_sendqueue, TRUE);
+ }
}
if (++returndepth >= MAXRETURNS)
@@ -482,9 +494,10 @@ returntosender(msg, returnq, sendbody, e)
return (0);
}
- SendBody = sendbody;
define('g', e->e_from.q_paddr, e);
define('u', NULL, e);
+
+ /* initialize error envelope */
ee = newenvelope(&errenvelope, e);
define('a', "\201b", ee);
define('r', "internal", ee);
@@ -497,45 +510,97 @@ returntosender(msg, returnq, sendbody, e)
ee->e_flags &= ~EF_OLDSTYLE;
ee->e_sendqueue = returnq;
ee->e_msgsize = ERRORFUDGE;
- if (!NoReturn)
+ if (sendbody)
ee->e_msgsize += e->e_msgsize;
+ else
+ ee->e_flags |= EF_NO_BODY_RETN;
initsys(ee);
for (q = returnq; q != NULL; q = q->q_next)
{
if (bitset(QBADADDR, q->q_flags))
continue;
- if (!bitset(QDONTSEND, q->q_flags))
- ee->e_nrcpts++;
-
if (!DontPruneRoutes && pruneroute(q->q_paddr))
+ {
+ register ADDRESS *p;
+
parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e);
+ for (p = returnq; p != NULL; p = p->q_next)
+ {
+ if (p != q && sameaddr(p, q))
+ q->q_flags |= QDONTSEND;
+ }
+ }
+
+ if (!bitset(QDONTSEND, q->q_flags))
+ ee->e_nrcpts++;
if (q->q_alias == NULL)
- addheader("To", q->q_paddr, ee);
+ addheader("To", q->q_paddr, &ee->e_header);
}
# ifdef LOG
if (LogLevel > 5)
- syslog(LOG_INFO, "%s: %s: return to sender: %s",
- e->e_id, ee->e_id, msg);
+ {
+ if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags))
+ p = "return to sender";
+ else
+ p = "postmaster notify";
+ syslog(LOG_INFO, "%s: %s: %s: %s",
+ e->e_id, ee->e_id, p, shortenstring(msg, 203));
+ }
# endif
- (void) sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg);
- addheader("Subject", buf, ee);
if (SendMIMEErrors)
{
- addheader("MIME-Version", "1.0", ee);
- (void) sprintf(buf, "%s.%ld/%s",
+ addheader("MIME-Version", "1.0", &ee->e_header);
+
+ (void) sprintf(buf, "%s.%ld/%.100s",
ee->e_id, curtime(), MyHostName);
ee->e_msgboundary = newstr(buf);
- (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"",
- ee->e_msgboundary);
- addheader("Content-Type", buf, ee);
+ (void) sprintf(buf,
+#if DSN
+ "multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
+#else
+ "multipart/mixed; boundary=\"%s\"",
+#endif
+ ee->e_msgboundary);
+ addheader("Content-Type", buf, &ee->e_header);
+
+ p = hvalue("Content-Transfer-Encoding", e->e_header);
+ if (p != NULL && strcasecmp(p, "binary") != 0)
+ p = NULL;
+ if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
+ p = "8bit";
+ if (p != NULL)
+ addheader("Content-Transfer-Encoding", p, &ee->e_header);
+ }
+ if (strncmp(msg, "Warning:", 8) == 0)
+ {
+ addheader("Subject", msg, &ee->e_header);
+ p = "warning-timeout";
+ }
+ else if (strncmp(msg, "Postmaster warning:", 19) == 0)
+ {
+ addheader("Subject", msg, &ee->e_header);
+ p = "postmaster-warning";
+ }
+ else if (strcmp(msg, "Return receipt") == 0)
+ {
+ addheader("Subject", msg, &ee->e_header);
+ p = "return-receipt";
+ }
+ else
+ {
+ sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg);
+ addheader("Subject", buf, &ee->e_header);
+ p = "failure";
}
+ (void) sprintf(buf, "auto-generated (%s)", p);
+ addheader("Auto-Submitted", buf, &ee->e_header);
/* fake up an address header for the from person */
- expand("\201n", buf, &buf[sizeof buf - 1], e);
+ expand("\201n", buf, sizeof buf, e);
if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
{
syserr("553 Can't parse myself!");
@@ -562,8 +627,15 @@ returntosender(msg, returnq, sendbody, e)
CurEnv = oldcur;
returndepth--;
- /* should check for delivery errors here */
- return (0);
+ /* check for delivery errors */
+ if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags))
+ return 0;
+ for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ if (bitset(QSENT, q->q_flags))
+ return 0;
+ }
+ return -1;
}
/*
** ERRBODY -- output the body of an error message.
@@ -574,6 +646,8 @@ returntosender(msg, returnq, sendbody, e)
** Parameters:
** mci -- the mailer connection information.
** e -- the envelope we are working in.
+** separator -- any possible MIME separator.
+** flags -- to modify the behaviour.
**
** Returns:
** none
@@ -582,16 +656,25 @@ returntosender(msg, returnq, sendbody, e)
** Outputs the body of an error message.
*/
-errbody(mci, e)
+void
+errbody(mci, e, separator)
register MCI *mci;
register ENVELOPE *e;
+ char *separator;
{
register FILE *xfile;
char *p;
register ADDRESS *q;
bool printheader;
+ bool sendbody;
char buf[MAXLINE];
+ extern char *xuntextify();
+ if (bitset(MCIF_INHEADER, mci->mci_flags))
+ {
+ putline("", mci);
+ mci->mci_flags &= ~MCIF_INHEADER;
+ }
if (e->e_parent == NULL)
{
syserr("errbody: null parent");
@@ -635,7 +718,7 @@ errbody(mci, e)
sprintf(buf, "The original message was received at %s",
arpadate(ctime(&e->e_parent->e_ctime)));
putline(buf, mci);
- expand("from \201_", buf, &buf[sizeof buf - 1], e->e_parent);
+ expand("from \201_", buf, sizeof buf, e->e_parent);
putline(buf, mci);
putline("", mci);
@@ -643,7 +726,7 @@ errbody(mci, e)
** Output error message header (if specified and available).
*/
- if (ErrMsgFile != NULL)
+ if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
{
if (*ErrMsgFile == '/')
{
@@ -652,7 +735,7 @@ errbody(mci, e)
{
while (fgets(buf, sizeof buf, xfile) != NULL)
{
- expand(buf, buf, &buf[sizeof buf - 1], e);
+ expand(buf, buf, sizeof buf, e);
putline(buf, mci);
}
(void) fclose(xfile);
@@ -661,7 +744,7 @@ errbody(mci, e)
}
else
{
- expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e);
+ expand(ErrMsgFile, buf, sizeof buf, e);
putline(buf, mci);
putline("", mci);
}
@@ -674,27 +757,46 @@ errbody(mci, e)
printheader = TRUE;
for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
{
- if (bitset(QBADADDR|QREPORT, q->q_flags))
+ if (bitset(QBADADDR, q->q_flags))
{
- if (printheader)
- {
- putline(" ----- The following addresses had delivery problems -----",
- mci);
- printheader = FALSE;
- }
- strcpy(buf, q->q_paddr);
- if (bitset(QBADADDR, q->q_flags))
- strcat(buf, " (unrecoverable error)");
+ if (!bitset(QPINGONFAILURE, q->q_flags))
+ continue;
+ p = "unrecoverable error";
+ }
+ else if (!bitset(QPRIMARY, q->q_flags))
+ continue;
+ else if (bitset(QDELAYED, q->q_flags))
+ p = "transient failure";
+ else if (!bitset(QPINGONSUCCESS, q->q_flags))
+ continue;
+ else if (bitset(QRELAYED, q->q_flags))
+ p = "relayed to non-DSN-aware mailer";
+ else if (bitset(QDELIVERED, q->q_flags))
+ {
+ if (bitset(QEXPANDED, q->q_flags))
+ p = "successfully delivered to mailing list";
else
- strcat(buf, " (transient failure)");
+ p = "successfully delivered to mailbox";
+ }
+ else if (bitset(QEXPANDED, q->q_flags))
+ p = "expanded by alias";
+ else
+ continue;
+
+ if (printheader)
+ {
+ putline(" ----- The following addresses have delivery notifications -----",
+ mci);
+ printheader = FALSE;
+ }
+
+ sprintf(buf, "%s (%s)", shortenstring(q->q_paddr, 203), p);
+ putline(buf, mci);
+ if (q->q_alias != NULL)
+ {
+ sprintf(buf, " (expanded from: %s)",
+ shortenstring(q->q_alias->q_paddr, 203));
putline(buf, mci);
- if (q->q_alias != NULL)
- {
- strcpy(buf, " (expanded from: ");
- strcat(buf, q->q_alias->q_paddr);
- strcat(buf, ")");
- putline(buf, mci);
- }
}
}
if (!printheader)
@@ -713,46 +815,256 @@ errbody(mci, e)
}
else
{
- putline(" ----- Transcript of session follows -----\n", mci);
+ printheader = TRUE;
if (e->e_xfp != NULL)
(void) fflush(e->e_xfp);
while (fgets(buf, sizeof buf, xfile) != NULL)
+ {
+ if (printheader)
+ putline(" ----- Transcript of session follows -----\n", mci);
+ printheader = FALSE;
putline(buf, mci);
+ }
(void) xfclose(xfile, "errbody xscript", p);
}
errno = 0;
+#if DSN
+ /*
+ ** Output machine-readable version.
+ */
+
+ if (e->e_msgboundary != NULL)
+ {
+ putline("", mci);
+ (void) sprintf(buf, "--%s", e->e_msgboundary);
+ putline(buf, mci);
+ putline("Content-Type: message/delivery-status", mci);
+ putline("", mci);
+
+ /*
+ ** Output per-message information.
+ */
+
+ /* original envelope id from MAIL FROM: line */
+ if (e->e_parent->e_envid != NULL)
+ {
+ (void) sprintf(buf, "Original-Envelope-Id: %.800s",
+ xuntextify(e->e_parent->e_envid));
+ putline(buf, mci);
+ }
+
+ /* Reporting-MTA: is us (required) */
+ (void) sprintf(buf, "Reporting-MTA: dns; %.800s", MyHostName);
+ putline(buf, mci);
+
+ /* DSN-Gateway: not relevant since we are not translating */
+
+ /* Received-From-MTA: shows where we got this message from */
+ if (RealHostName != NULL)
+ {
+ /* XXX use $s for type? */
+ if (e->e_parent->e_from.q_mailer == NULL ||
+ (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
+ p = "dns";
+ (void) sprintf(buf, "Received-From-MTA: %s; %.800s",
+ p, RealHostName);
+ putline(buf, mci);
+ }
+
+ /* Arrival-Date: -- when it arrived here */
+ (void) sprintf(buf, "Arrival-Date: %s",
+ arpadate(ctime(&e->e_parent->e_ctime)));
+ putline(buf, mci);
+
+ /*
+ ** Output per-address information.
+ */
+
+ for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
+ {
+ register ADDRESS *r;
+ char *action;
+
+ if (bitset(QBADADDR, q->q_flags))
+ action = "failed";
+ else if (!bitset(QPRIMARY, q->q_flags))
+ continue;
+ else if (bitset(QDELIVERED, q->q_flags))
+ {
+ if (bitset(QEXPANDED, q->q_flags))
+ action = "delivered (to mailing list)";
+ else
+ action = "delivered (to mailbox)";
+ }
+ else if (bitset(QRELAYED, q->q_flags))
+ action = "relayed (to non-DSN-aware mailer)";
+ else if (bitset(QEXPANDED, q->q_flags))
+ action = "expanded (to multi-recipient alias)";
+ else if (bitset(QDELAYED, q->q_flags))
+ action = "delayed";
+ else
+ continue;
+
+ putline("", mci);
+
+ /* Original-Recipient: -- passed from on high */
+ if (q->q_orcpt != NULL)
+ {
+ (void) sprintf(buf, "Original-Recipient: %.800s",
+ q->q_orcpt);
+ putline(buf, mci);
+ }
+
+ /* Final-Recipient: -- the name from the RCPT command */
+ p = e->e_parent->e_from.q_mailer->m_addrtype;
+ if (p == NULL)
+ p = "rfc822";
+ for (r = q; r->q_alias != NULL; r = r->q_alias)
+ continue;
+ if (strchr(r->q_user, '@') == NULL)
+ {
+ (void) sprintf(buf, "Final-Recipient: %s; %.700s@%.100s",
+ p, r->q_user, MyHostName);
+ }
+ else
+ {
+ (void) sprintf(buf, "Final-Recipient: %s; %.800s",
+ p, r->q_user);
+ }
+ putline(buf, mci);
+
+ /* X-Actual-Recipient: -- the real problem address */
+ if (r != q && q->q_user[0] != '\0')
+ {
+ if (strchr(q->q_user, '@') == NULL)
+ {
+ (void) sprintf(buf, "X-Actual-Recipient: %s; %.700s@%.100s",
+ p, q->q_user, MyHostName);
+ }
+ else
+ {
+ (void) sprintf(buf, "X-Actual-Recipient: %s; %.800s",
+ p, q->q_user);
+ }
+ putline(buf, mci);
+ }
+
+ /* Action: -- what happened? */
+ sprintf(buf, "Action: %s", action);
+ putline(buf, mci);
+
+ /* Status: -- what _really_ happened? */
+ strcpy(buf, "Status: ");
+ if (q->q_status != NULL)
+ strcat(buf, q->q_status);
+ else if (bitset(QBADADDR, q->q_flags))
+ strcat(buf, "5.0.0");
+ else if (bitset(QQUEUEUP, q->q_flags))
+ strcat(buf, "4.0.0");
+ else
+ strcat(buf, "2.0.0");
+ putline(buf, mci);
+
+ /* Remote-MTA: -- who was I talking to? */
+ if (q->q_statmta != NULL)
+ {
+ if (q->q_mailer == NULL ||
+ (p = q->q_mailer->m_mtatype) == NULL)
+ p = "dns";
+ (void) sprintf(buf, "Remote-MTA: %s; %.800s",
+ p, q->q_statmta);
+ p = &buf[strlen(buf) - 1];
+ if (*p == '.')
+ *p = '\0';
+ putline(buf, mci);
+ }
+
+ /* Diagnostic-Code: -- actual result from other end */
+ if (q->q_rstatus != NULL)
+ {
+ p = q->q_mailer->m_diagtype;
+ if (p == NULL)
+ p = "smtp";
+ (void) sprintf(buf, "Diagnostic-Code: %s; %.800s",
+ p, q->q_rstatus);
+ putline(buf, mci);
+ }
+
+ /* Last-Attempt-Date: -- fine granularity */
+ if (q->q_statdate == (time_t) 0L)
+ q->q_statdate = curtime();
+ (void) sprintf(buf, "Last-Attempt-Date: %s",
+ arpadate(ctime(&q->q_statdate)));
+ putline(buf, mci);
+
+ /* Will-Retry-Until: -- for delayed messages only */
+ if (bitset(QQUEUEUP, q->q_flags) &&
+ !bitset(QBADADDR, q->q_flags))
+ {
+ time_t xdate;
+
+ xdate = e->e_parent->e_ctime +
+ TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
+ sprintf(buf, "Will-Retry-Until: %s",
+ arpadate(ctime(&xdate)));
+ putline(buf, mci);
+ }
+ }
+ }
+#endif
+
/*
** Output text of original message
*/
- if (NoReturn)
- SendBody = FALSE;
putline("", mci);
- if (e->e_parent->e_df != NULL)
+ if (bitset(EF_HAS_DF, e->e_parent->e_flags))
{
- if (SendBody)
- putline(" ----- Original message follows -----\n", mci);
- else
- putline(" ----- Message header follows -----\n", mci);
- (void) fflush(mci->mci_out);
+ sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
+ !bitset(EF_NO_BODY_RETN, e->e_flags);
- if (e->e_msgboundary != NULL)
+ if (e->e_msgboundary == NULL)
+ {
+ if (sendbody)
+ putline(" ----- Original message follows -----\n", mci);
+ else
+ putline(" ----- Message header follows -----\n", mci);
+ (void) fflush(mci->mci_out);
+ }
+ else
{
- putline("", mci);
(void) sprintf(buf, "--%s", e->e_msgboundary);
+
putline(buf, mci);
- putline("Content-Type: message/rfc822", mci);
- putline("", mci);
+ (void) sprintf(buf, "Content-Type: %s",
+ sendbody ? "message/rfc822"
+ : "text/rfc822-headers");
+ putline(buf, mci);
+
+ p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header);
+ if (p != NULL && strcasecmp(p, "binary") != 0)
+ p = NULL;
+ if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags))
+ p = "8bit";
+ if (p != NULL)
+ {
+ (void) sprintf(buf, "Content-Transfer-Encoding: %s",
+ p);
+ putline(buf, mci);
+ }
}
- putheader(mci, e->e_parent);
putline("", mci);
- if (SendBody)
+ putheader(mci, e->e_parent->e_header, e->e_parent);
+ if (sendbody)
putbody(mci, e->e_parent, e->e_msgboundary);
- else
+ else if (e->e_msgboundary == NULL)
+ {
+ putline("", mci);
putline(" ----- Message body suppressed -----", mci);
+ }
}
- else
+ else if (e->e_msgboundary == NULL)
{
putline(" ----- No message was collected -----\n", mci);
}
@@ -773,6 +1085,248 @@ errbody(mci, e)
syserr("errbody: I/O error");
}
/*
+** SMTPTODSN -- convert SMTP to DSN status code
+**
+** Parameters:
+** smtpstat -- the smtp status code (e.g., 550).
+**
+** Returns:
+** The DSN version of the status code.
+*/
+
+char *
+smtptodsn(smtpstat)
+ int smtpstat;
+{
+ if (smtpstat < 0)
+ return "4.4.2";
+
+ switch (smtpstat)
+ {
+ case 450: /* Req mail action not taken: mailbox unavailable */
+ return "4.2.0";
+
+ case 451: /* Req action aborted: local error in processing */
+ return "4.3.0";
+
+ case 452: /* Req action not taken: insufficient sys storage */
+ return "4.3.1";
+
+ case 500: /* Syntax error, command unrecognized */
+ return "5.5.2";
+
+ case 501: /* Syntax error in parameters or arguments */
+ return "5.5.4";
+
+ case 502: /* Command not implemented */
+ return "5.5.1";
+
+ case 503: /* Bad sequence of commands */
+ return "5.5.1";
+
+ case 504: /* Command parameter not implemented */
+ return "5.5.4";
+
+ case 550: /* Req mail action not taken: mailbox unavailable */
+ return "5.2.0";
+
+ case 551: /* User not local; please try <...> */
+ return "5.1.6";
+
+ case 552: /* Req mail action aborted: exceeded storage alloc */
+ return "5.2.2";
+
+ case 553: /* Req action not taken: mailbox name not allowed */
+ return "5.1.3";
+
+ case 554: /* Transaction failed */
+ return "5.0.0";
+ }
+
+ if ((smtpstat / 100) == 2)
+ return "2.0.0";
+ if ((smtpstat / 100) == 4)
+ return "4.0.0";
+ return "5.0.0";
+}
+ /*
+** XTEXTIFY -- take regular text and turn it into DSN-style xtext
+**
+** Parameters:
+** t -- the text to convert.
+**
+** Returns:
+** The xtext-ified version of the same string.
+*/
+
+char *
+xtextify(t)
+ register char *t;
+{
+ register char *p;
+ int l;
+ int nbogus;
+ static char *bp = NULL;
+ static int bplen = 0;
+
+ /* figure out how long this xtext will have to be */
+ nbogus = l = 0;
+ for (p = t; *p != '\0'; p++)
+ {
+ register int c = (*p & 0xff);
+
+ /* ASCII dependence here -- this is the way the spec words it */
+ if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(')
+ nbogus++;
+ l++;
+ }
+ if (nbogus == 0)
+ return t;
+ l += nbogus * 2 + 1;
+
+ /* now allocate space if necessary for the new string */
+ if (l > bplen)
+ {
+ if (bp != NULL)
+ free(bp);
+ bp = xalloc(l);
+ bplen = l;
+ }
+
+ /* ok, copy the text with byte expansion */
+ for (p = bp; *t != '\0'; )
+ {
+ register int c = (*t++ & 0xff);
+
+ /* ASCII dependence here -- this is the way the spec words it */
+ if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(')
+ {
+ *p++ = '+';
+ *p++ = "0123456789abcdef"[c >> 4];
+ *p++ = "0123456789abcdef"[c & 0xf];
+ }
+ else
+ *p++ = c;
+ }
+ *p = '\0';
+ return bp;
+}
+ /*
+** XUNTEXTIFY -- take xtext and turn it into plain text
+**
+** Parameters:
+** t -- the xtextified text.
+**
+** Returns:
+** The decoded text. No attempt is made to deal with
+** null strings in the resulting text.
+*/
+
+char *
+xuntextify(t)
+ register char *t;
+{
+ register char *p;
+ int l;
+ static char *bp = NULL;
+ static int bplen = 0;
+
+ /* heuristic -- if no plus sign, just return the input */
+ if (strchr(t, '+') == NULL)
+ return t;
+
+ /* xtext is always longer than decoded text */
+ l = strlen(t);
+ if (l > bplen)
+ {
+ if (bp != NULL)
+ free(bp);
+ bp = xalloc(l);
+ bplen = l;
+ }
+
+ /* ok, copy the text with byte compression */
+ for (p = bp; *t != '\0'; t++)
+ {
+ register int c = *t & 0xff;
+
+ if (c != '+')
+ {
+ *p++ = c;
+ continue;
+ }
+
+ c = *++t & 0xff;
+ if (!isascii(c) || !isxdigit(c))
+ {
+ /* error -- first digit is not hex */
+ usrerr("bogus xtext: +%c", c);
+ t--;
+ continue;
+ }
+ if (isdigit(c))
+ c -= '0';
+ else if (isupper(c))
+ c -= 'A' - 10;
+ else
+ c -= 'a' - 10;
+ *p = c << 4;
+
+ c = *++t & 0xff;
+ if (!isascii(c) || !isxdigit(c))
+ {
+ /* error -- second digit is not hex */
+ usrerr("bogus xtext: +%x%c", *p >> 4, c);
+ t--;
+ continue;
+ }
+ if (isdigit(c))
+ c -= '0';
+ else if (isupper(c))
+ c -= 'A' - 10;
+ else
+ c -= 'a' - 10;
+ *p++ |= c;
+ }
+ return bp;
+}
+ /*
+** XTEXTOK -- check if a string is legal xtext
+**
+** Xtext is used in Delivery Status Notifications. The spec was
+** taken from draft-ietf-notary-mime-delivery-04.txt.
+**
+** Parameters:
+** s -- the string to check.
+**
+** Returns:
+** TRUE -- if 's' is legal xtext.
+** FALSE -- if it has any illegal characters in it.
+*/
+
+bool
+xtextok(s)
+ char *s;
+{
+ int c;
+
+ while ((c = *s++) != '\0')
+ {
+ if (c == '+')
+ {
+ c = *s++;
+ if (!isascii(c) || !isxdigit(c))
+ return FALSE;
+ c = *s++;
+ if (!isascii(c) || !isxdigit(c))
+ return FALSE;
+ }
+ else if (c < '!' || c > '~' || c == '=')
+ return FALSE;
+ }
+ return TRUE;
+}
+ /*
** PRUNEROUTE -- prune an RFC-822 source route
**
** Trims down a source route to the last internet-registered hop.
@@ -789,6 +1343,7 @@ errbody(mci, e)
** modifies addr in-place
*/
+bool
pruneroute(addr)
char *addr;
{
OpenPOWER on IntegriCloud