diff options
author | peter <peter@FreeBSD.org> | 1995-12-02 17:30:23 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1995-12-02 17:30:23 +0000 |
commit | 88797ecc8d2743a86e4e574fadaac061649931a1 (patch) | |
tree | c3349cbdc3f0c451b9b3d949b54a30e08ff75375 /usr.sbin/sendmail/src/savemail.c | |
parent | 78d9d5927fb62a9d93abb0c1a0027bdd84b89117 (diff) | |
download | FreeBSD-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.c | 783 |
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; { |