122711Sdist /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
362531Sbostic * Copyright (c) 1988, 1993
462531Sbostic * The Regents of the University of California. All rights reserved.
533731Sbostic *
642829Sbostic * %sccs.include.redist.c%
733731Sbostic */
822711Sdist
922711Sdist #ifndef lint
10*69924Seric static char sccsid[] = "@(#)savemail.c 8.79 (Berkeley) 06/18/95";
1133731Sbostic #endif /* not lint */
1222711Sdist
1363937Seric # include "sendmail.h"
14297Seric
15297Seric /*
16297Seric ** SAVEMAIL -- Save mail on error
17297Seric **
189375Seric ** If mailing back errors, mail it back to the originator
19297Seric ** together with an error message; otherwise, just put it in
20297Seric ** dead.letter in the user's home directory (if he exists on
21297Seric ** this machine).
22297Seric **
23297Seric ** Parameters:
249337Seric ** e -- the envelope containing the message in error.
2567981Seric ** sendbody -- if TRUE, also send back the body of the
2667981Seric ** message; otherwise just send the header.
27297Seric **
28297Seric ** Returns:
29297Seric ** none
30297Seric **
31297Seric ** Side Effects:
32297Seric ** Saves the letter, by writing or mailing it back to the
33297Seric ** sender, or by putting it in dead.letter in her home
34297Seric ** directory.
35297Seric */
36297Seric
3724942Seric /* defines for state machine */
3824942Seric # define ESM_REPORT 0 /* report to sender's terminal */
3924942Seric # define ESM_MAIL 1 /* mail back to sender */
4024942Seric # define ESM_QUIET 2 /* messages have already been returned */
4124942Seric # define ESM_DEADLETTER 3 /* save in ~/dead.letter */
4224942Seric # define ESM_POSTMASTER 4 /* return to postmaster */
4324942Seric # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */
4424942Seric # define ESM_PANIC 6 /* leave the locked queue/transcript files */
4524942Seric # define ESM_DONE 7 /* the message is successfully delivered */
4624942Seric
4765174Seric # ifndef _PATH_VARTMP
4865174Seric # define _PATH_VARTMP "/usr/tmp/"
4965174Seric # endif
5024942Seric
5165174Seric
5269748Seric void
savemail(e,sendbody)5367981Seric savemail(e, sendbody)
549337Seric register ENVELOPE *e;
5567981Seric bool sendbody;
56297Seric {
57297Seric register struct passwd *pw;
5824942Seric register FILE *fp;
5924942Seric int state;
6059290Seric auto ADDRESS *q = NULL;
6165870Seric register char *p;
6265870Seric MCI mcibuf;
6368802Seric int sfflags;
64297Seric char buf[MAXLINE+1];
65297Seric extern char *ttypath();
665846Seric typedef int (*fnptr)();
6764945Seric extern bool writable();
68297Seric
697676Seric if (tTd(6, 1))
7058680Seric {
7166317Seric printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=",
7266317Seric e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
7366317Seric ExitStat);
7458680Seric printaddr(&e->e_from, FALSE);
7558680Seric }
767361Seric
7759101Seric if (e->e_id == NULL)
7859101Seric {
7959101Seric /* can't return a message with no id */
8059101Seric return;
8159101Seric }
8259101Seric
83297Seric /*
84297Seric ** In the unhappy event we don't know who to return the mail
85297Seric ** to, make someone up.
86297Seric */
87297Seric
889337Seric if (e->e_from.q_paddr == NULL)
89297Seric {
9058733Seric e->e_sender = "Postmaster";
9164284Seric if (parseaddr(e->e_sender, &e->e_from,
9264284Seric RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
93297Seric {
9458733Seric syserr("553 Cannot parse Postmaster!");
95297Seric ExitStat = EX_SOFTWARE;
96297Seric finis();
97297Seric }
98297Seric }
999337Seric e->e_to = NULL;
100297Seric
101297Seric /*
10224942Seric ** Basic state machine.
10324942Seric **
10424942Seric ** This machine runs through the following states:
10524942Seric **
10624942Seric ** ESM_QUIET Errors have already been printed iff the
10724942Seric ** sender is local.
10824942Seric ** ESM_REPORT Report directly to the sender's terminal.
10924942Seric ** ESM_MAIL Mail response to the sender.
11024942Seric ** ESM_DEADLETTER Save response in ~/dead.letter.
11124942Seric ** ESM_POSTMASTER Mail response to the postmaster.
11224942Seric ** ESM_PANIC Save response anywhere possible.
113297Seric */
114297Seric
11524942Seric /* determine starting state */
11658734Seric switch (e->e_errormode)
117297Seric {
11824942Seric case EM_WRITE:
11924942Seric state = ESM_REPORT;
12024942Seric break;
12124942Seric
12224942Seric case EM_BERKNET:
12324942Seric case EM_MAIL:
12424942Seric state = ESM_MAIL;
12524942Seric break;
12624942Seric
12724942Seric case EM_PRINT:
12824979Seric case '\0':
12924942Seric state = ESM_QUIET;
13024942Seric break;
13124942Seric
13224942Seric case EM_QUIET:
13324942Seric /* no need to return anything at all */
13424942Seric return;
13524979Seric
13624979Seric default:
13758734Seric syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
13824979Seric state = ESM_MAIL;
13924979Seric break;
140297Seric }
141297Seric
14259094Seric /* if this is already an error response, send to postmaster */
14359094Seric if (bitset(EF_RESPONSE, e->e_flags))
14459094Seric {
14559094Seric if (e->e_parent != NULL &&
14659094Seric bitset(EF_RESPONSE, e->e_parent->e_flags))
14759094Seric {
14859094Seric /* got an error sending a response -- can it */
14959094Seric return;
15059094Seric }
15159094Seric state = ESM_POSTMASTER;
15259094Seric }
15359094Seric
15424942Seric while (state != ESM_DONE)
155297Seric {
15624979Seric if (tTd(6, 5))
15724979Seric printf(" state %d\n", state);
15824979Seric
15924942Seric switch (state)
160297Seric {
16124979Seric case ESM_QUIET:
16267473Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
16324979Seric state = ESM_DEADLETTER;
16424979Seric else
16524979Seric state = ESM_MAIL;
16624979Seric break;
16724979Seric
16824942Seric case ESM_REPORT:
16924942Seric
17024942Seric /*
17124942Seric ** If the user is still logged in on the same terminal,
17224942Seric ** then write the error messages back to hir (sic).
17324942Seric */
17424942Seric
17524942Seric p = ttypath();
17624942Seric if (p == NULL || freopen(p, "w", stdout) == NULL)
17724942Seric {
17824942Seric state = ESM_MAIL;
17924942Seric break;
18024942Seric }
18124942Seric
18268529Seric expand("\201n", buf, sizeof buf, e);
1839375Seric printf("\r\nMessage from %s...\r\n", buf);
1849375Seric printf("Errors occurred while sending mail.\r\n");
1859542Seric if (e->e_xfp != NULL)
1869375Seric {
1879542Seric (void) fflush(e->e_xfp);
18824942Seric fp = fopen(queuename(e, 'x'), "r");
1899375Seric }
1909375Seric else
19124942Seric fp = NULL;
19224942Seric if (fp == NULL)
1939375Seric {
1949337Seric syserr("Cannot open %s", queuename(e, 'x'));
1959375Seric printf("Transcript of session is unavailable.\r\n");
1969375Seric }
1979375Seric else
1989375Seric {
1999375Seric printf("Transcript follows:\r\n");
20024942Seric while (fgets(buf, sizeof buf, fp) != NULL &&
2019375Seric !ferror(stdout))
2029375Seric fputs(buf, stdout);
20358680Seric (void) xfclose(fp, "savemail transcript", e->e_id);
2049375Seric }
20524942Seric printf("Original message will be saved in dead.letter.\r\n");
20624942Seric state = ESM_DEADLETTER;
20724942Seric break;
208297Seric
20924942Seric case ESM_MAIL:
21024942Seric /*
21124942Seric ** If mailing back, do it.
21224942Seric ** Throw away all further output. Don't alias,
21324942Seric ** since this could cause loops, e.g., if joe
21424942Seric ** mails to joe@x, and for some reason the network
21524942Seric ** for @x is down, then the response gets sent to
21624942Seric ** joe@x, which gives a response, etc. Also force
21724942Seric ** the mail to be delivered even if a version of
21824942Seric ** it has already been sent to the sender.
21963841Seric **
22063841Seric ** If this is a configuration or local software
22163841Seric ** error, send to the local postmaster as well,
22263841Seric ** since the originator can't do anything
22363841Seric ** about it anyway. Note that this is a full
22463841Seric ** copy of the message (intentionally) so that
22563841Seric ** the Postmaster can forward things along.
22624942Seric */
227297Seric
22863841Seric if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
22963841Seric {
23063841Seric (void) sendtolist("postmaster",
23167982Seric NULLADDR, &e->e_errorqueue, 0, e);
23263841Seric }
23367939Seric if (!emptyaddr(&e->e_from))
23463841Seric {
23558680Seric (void) sendtolist(e->e_from.q_paddr,
23667982Seric NULLADDR, &e->e_errorqueue, 0, e);
23763841Seric }
23858680Seric
23963841Seric /*
24063841Seric ** Deliver a non-delivery report to the
24163841Seric ** Postmaster-designate (not necessarily
24263841Seric ** Postmaster). This does not include the
24363841Seric ** body of the message, for privacy reasons.
24463841Seric ** You really shouldn't need this.
24563841Seric */
24663841Seric
24763849Seric e->e_flags |= EF_PM_NOTIFY;
24858178Seric
24964792Seric /* check to see if there are any good addresses */
25064792Seric for (q = e->e_errorqueue; q != NULL; q = q->q_next)
25164792Seric if (!bitset(QBADADDR|QDONTSEND, q->q_flags))
25264792Seric break;
25358680Seric if (q == NULL)
25458680Seric {
25558680Seric /* this is an error-error */
25658680Seric state = ESM_POSTMASTER;
25758680Seric break;
25858680Seric }
25966303Seric if (returntosender(e->e_message, e->e_errorqueue,
26067981Seric sendbody, e) == 0)
26158680Seric {
26258680Seric state = ESM_DONE;
26358680Seric break;
26458680Seric }
26524981Seric
26658680Seric /* didn't work -- return to postmaster */
26758680Seric state = ESM_POSTMASTER;
26858680Seric break;
26958306Seric
27058680Seric case ESM_POSTMASTER:
27158680Seric /*
27258680Seric ** Similar to previous case, but to system postmaster.
27358680Seric */
27458680Seric
27559432Seric q = NULL;
27667982Seric if (sendtolist("postmaster", NULL, &q, 0, e) <= 0)
27724942Seric {
27858680Seric syserr("553 cannot parse postmaster!");
27958680Seric ExitStat = EX_SOFTWARE;
28058680Seric state = ESM_USRTMP;
28158680Seric break;
28224942Seric }
28367981Seric if (returntosender(e->e_message, q, sendbody, e) == 0)
28424942Seric {
28524942Seric state = ESM_DONE;
28624942Seric break;
28724942Seric }
288297Seric
28958680Seric /* didn't work -- last resort */
29058680Seric state = ESM_USRTMP;
29124942Seric break;
292297Seric
29324942Seric case ESM_DEADLETTER:
29424942Seric /*
29524942Seric ** Save the message in dead.letter.
29624942Seric ** If we weren't mailing back, and the user is
29724942Seric ** local, we should save the message in
29824942Seric ** ~/dead.letter so that the poor person doesn't
29924942Seric ** have to type it over again -- and we all know
30024942Seric ** what poor typists UNIX users are.
30124942Seric */
3025315Seric
30324942Seric p = NULL;
30467473Seric if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
30524942Seric {
30624942Seric if (e->e_from.q_home != NULL)
30724942Seric p = e->e_from.q_home;
30868693Seric else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
30924942Seric p = pw->pw_dir;
31024942Seric }
31168802Seric if (p == NULL || e->e_dfp == NULL)
31224942Seric {
31368802Seric /* no local directory or no data file */
31424942Seric state = ESM_MAIL;
31524942Seric break;
31624942Seric }
31724942Seric
31869787Seric /* we have a home directory; write dead.letter */
31968802Seric define('z', p, e);
32068802Seric expand("\201z/dead.letter", buf, sizeof buf, e);
32168802Seric sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
32268802Seric e->e_to = buf;
32369787Seric if (mailfile(buf, NULL, sfflags, e) == EX_OK)
32469787Seric {
32569787Seric bool oldverb = Verbose;
32624942Seric
32769787Seric Verbose = TRUE;
32869787Seric message("Saved message in %s", buf);
32969787Seric Verbose = oldverb;
33069787Seric state = ESM_DONE;
33169787Seric break;
33269787Seric }
33369787Seric state = ESM_MAIL;
33469787Seric break;
33569787Seric
33624942Seric case ESM_USRTMP:
33724942Seric /*
33824942Seric ** Log the mail in /usr/tmp/dead.letter.
33924942Seric */
34024942Seric
34157438Seric if (e->e_class < 0)
34257438Seric {
34357438Seric state = ESM_DONE;
34457438Seric break;
34557438Seric }
34657438Seric
34768490Seric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0')
34868490Seric {
34968490Seric state = ESM_PANIC;
35068490Seric break;
35168490Seric }
35268490Seric
35365174Seric strcpy(buf, _PATH_VARTMP);
35465174Seric strcat(buf, "dead.letter");
35568802Seric
356*69924Seric sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK;
35769787Seric if (!writable(buf, NULL, sfflags) ||
35868802Seric (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND,
35968802Seric FileMode, sfflags)) == NULL)
36064945Seric {
36169787Seric state = ESM_PANIC;
36264945Seric break;
36364945Seric }
36424942Seric
36565870Seric bzero(&mcibuf, sizeof mcibuf);
36665870Seric mcibuf.mci_out = fp;
36765870Seric mcibuf.mci_mailer = FileMailer;
36865870Seric if (bitnset(M_7BITS, FileMailer->m_flags))
36965870Seric mcibuf.mci_flags |= MCIF_7BIT;
37065870Seric
37165870Seric putfromline(&mcibuf, e);
37268228Seric (*e->e_puthdr)(&mcibuf, e->e_header, e);
37368228Seric (*e->e_putbody)(&mcibuf, e, NULL);
37465870Seric putline("\n", &mcibuf);
37524942Seric (void) fflush(fp);
37668802Seric if (!ferror(fp))
37768802Seric {
37868802Seric bool oldverb = Verbose;
37968802Seric
38068802Seric Verbose = TRUE;
38168802Seric message("Saved message in %s", buf);
38268802Seric Verbose = oldverb;
383*69924Seric #ifdef LOG
384*69924Seric if (LogLevel > 3)
385*69924Seric syslog(LOG_NOTICE, "Saved message in %s", buf);
386*69924Seric #endif
38768802Seric state = ESM_DONE;
388*69924Seric break;
38968802Seric }
39069787Seric state = ESM_PANIC;
39167809Seric (void) xfclose(fp, "savemail", buf);
39224942Seric break;
39324942Seric
39424942Seric default:
39558151Seric syserr("554 savemail: unknown state %d", state);
39624942Seric
39724942Seric /* fall through ... */
39824942Seric
39924942Seric case ESM_PANIC:
40024942Seric /* leave the locked queue & transcript files around */
40168490Seric loseqfile(e, "savemail panic");
40264949Seric syserr("!554 savemail: cannot save rejected email anywhere");
40324942Seric }
404297Seric }
405297Seric }
406297Seric /*
4074633Seric ** RETURNTOSENDER -- return a message to the sender with an error.
4084633Seric **
4094633Seric ** Parameters:
4104633Seric ** msg -- the explanatory message.
41116479Seric ** returnq -- the queue of people to send the message to.
4125984Seric ** sendbody -- if TRUE, also send back the body of the
4135984Seric ** message; otherwise just send the header.
41455012Seric ** e -- the current envelope.
4154633Seric **
4164633Seric ** Returns:
4174633Seric ** zero -- if everything went ok.
4184633Seric ** else -- some error.
4194633Seric **
4204633Seric ** Side Effects:
4214633Seric ** Returns the current message to the sender via
4224633Seric ** mail.
4234633Seric */
4244633Seric
4257045Seric #define MAXRETURNS 6 /* max depth of returning messages */
42658559Seric #define ERRORFUDGE 100 /* nominal size of error message text */
4277045Seric
42869748Seric int
returntosender(msg,returnq,sendbody,e)42955012Seric returntosender(msg, returnq, sendbody, e)
4304633Seric char *msg;
43116479Seric ADDRESS *returnq;
4325984Seric bool sendbody;
43355012Seric register ENVELOPE *e;
4344633Seric {
4356978Seric register ENVELOPE *ee;
43658680Seric ENVELOPE *oldcur = CurEnv;
4376978Seric ENVELOPE errenvelope;
4387045Seric static int returndepth;
4399375Seric register ADDRESS *q;
44068228Seric char *p;
44169748Seric char buf[MAXNAME + 1];
44269748Seric extern void errbody __P((MCI *, ENVELOPE *, char *));
4434633Seric
44460010Seric if (returnq == NULL)
44560010Seric return (-1);
44660010Seric
44758966Seric if (msg == NULL)
44858966Seric msg = "Unable to deliver mail";
44958966Seric
4507676Seric if (tTd(6, 1))
4517287Seric {
45267987Seric printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
45355012Seric msg, returndepth, e);
45416479Seric printaddr(returnq, TRUE);
45567987Seric if (tTd(6, 20))
45667987Seric {
45767987Seric printf("Sendq=");
45867987Seric printaddr(e->e_sendqueue, TRUE);
45967987Seric }
4607287Seric }
4617287Seric
4627045Seric if (++returndepth >= MAXRETURNS)
4637045Seric {
4647045Seric if (returndepth != MAXRETURNS)
46558151Seric syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
4667045Seric /* don't "unrecurse" and fake a clean exit */
4677045Seric /* returndepth--; */
4687045Seric return (0);
4697045Seric }
4707045Seric
47158680Seric define('g', e->e_from.q_paddr, e);
47264940Seric define('u', NULL, e);
47367880Seric
47467880Seric /* initialize error envelope */
47558179Seric ee = newenvelope(&errenvelope, e);
47658050Seric define('a', "\201b", ee);
47759057Seric define('r', "internal", ee);
47859057Seric define('s', "localhost", ee);
47959057Seric define('_', "localhost", ee);
4806978Seric ee->e_puthdr = putheader;
4816978Seric ee->e_putbody = errbody;
48264120Seric ee->e_flags |= EF_RESPONSE|EF_METOO;
48355012Seric if (!bitset(EF_OLDSTYLE, e->e_flags))
48445155Seric ee->e_flags &= ~EF_OLDSTYLE;
48516479Seric ee->e_sendqueue = returnq;
48664655Seric ee->e_msgsize = ERRORFUDGE;
48768559Seric if (sendbody)
48864655Seric ee->e_msgsize += e->e_msgsize;
48968802Seric else
49068802Seric ee->e_flags |= EF_NO_BODY_RETN;
49164737Seric initsys(ee);
49216479Seric for (q = returnq; q != NULL; q = q->q_next)
4939375Seric {
49459989Seric if (bitset(QBADADDR, q->q_flags))
49558559Seric continue;
49658559Seric
49768141Seric if (!DontPruneRoutes && pruneroute(q->q_paddr))
49868141Seric {
49968141Seric register ADDRESS *p;
50068141Seric
50168141Seric parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e);
50268141Seric for (p = returnq; p != NULL; p = p->q_next)
50368141Seric {
50468141Seric if (p != q && sameaddr(p, q))
50568141Seric q->q_flags |= QDONTSEND;
50668141Seric }
50768141Seric }
50868141Seric
50959989Seric if (!bitset(QDONTSEND, q->q_flags))
51059989Seric ee->e_nrcpts++;
51158559Seric
5129375Seric if (q->q_alias == NULL)
51367546Seric addheader("To", q->q_paddr, &ee->e_header);
5149375Seric }
51524942Seric
51657642Seric # ifdef LOG
51758020Seric if (LogLevel > 5)
51865054Seric syslog(LOG_INFO, "%s: %s: return to sender: %s",
51957642Seric e->e_id, ee->e_id, msg);
52057642Seric # endif
52157642Seric
52268003Seric if (SendMIMEErrors)
52367261Seric {
52468003Seric addheader("MIME-Version", "1.0", &ee->e_header);
52569908Seric
52668003Seric (void) sprintf(buf, "%s.%ld/%s",
52768003Seric ee->e_id, curtime(), MyHostName);
52868003Seric ee->e_msgboundary = newstr(buf);
52968003Seric (void) sprintf(buf,
53068848Seric #if DSN
53169858Seric "multipart/report; report-type=X-delivery-status-03 (Draft of May 5, 1995);\n\tboundary=\"%s\"",
53268028Seric #else
53368028Seric "multipart/mixed; boundary=\"%s\"",
53468028Seric #endif
53568003Seric ee->e_msgboundary);
53668003Seric addheader("Content-Type", buf, &ee->e_header);
53769908Seric
53869908Seric p = hvalue("Content-Transfer-Encoding", e->e_header);
53969908Seric if (p != NULL && strcasecmp(p, "binary") != 0)
54069908Seric p = NULL;
54169908Seric if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
54269908Seric p = "8bit";
54369908Seric if (p != NULL)
54469908Seric addheader("Content-Transfer-Encoding", p, &ee->e_header);
54568003Seric }
54668228Seric if (strncmp(msg, "Warning:", 8) == 0)
54768003Seric {
54868879Seric addheader("Subject", msg, &ee->e_header);
54968228Seric p = "warning-timeout";
55067261Seric }
55167429Seric else if (strcmp(msg, "Return receipt") == 0)
55267429Seric {
55368879Seric addheader("Subject", msg, &ee->e_header);
55468228Seric p = "return-receipt";
55567429Seric }
55667261Seric else
55767261Seric {
55867261Seric sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg);
55967546Seric addheader("Subject", buf, &ee->e_header);
56068228Seric p = "failure";
56167261Seric }
56268228Seric (void) sprintf(buf, "auto-generated (%s)", p);
56368228Seric addheader("Auto-Submitted", buf, &ee->e_header);
5644633Seric
5654633Seric /* fake up an address header for the from person */
56668529Seric expand("\201n", buf, sizeof buf, e);
56764284Seric if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
5684633Seric {
56958151Seric syserr("553 Can't parse myself!");
5704633Seric ExitStat = EX_SOFTWARE;
5717045Seric returndepth--;
5724633Seric return (-1);
5734633Seric }
57458704Seric ee->e_sender = ee->e_from.q_paddr;
5755984Seric
5766978Seric /* push state into submessage */
5776978Seric CurEnv = ee;
57858050Seric define('f', "\201n", ee);
5799375Seric define('x', "Mail Delivery Subsystem", ee);
58058929Seric eatheader(ee, TRUE);
5815984Seric
58263753Seric /* mark statistics */
58364284Seric markstats(ee, NULLADDR);
58463753Seric
5856978Seric /* actually deliver the error message */
58614876Seric sendall(ee, SM_DEFAULT);
5876978Seric
5886978Seric /* restore state */
5897811Seric dropenvelope(ee);
59058680Seric CurEnv = oldcur;
5917045Seric returndepth--;
5926978Seric
593*69924Seric /* check for delivery errors */
594*69924Seric if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags))
595*69924Seric return 0;
596*69924Seric for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
597*69924Seric {
598*69924Seric if (bitset(QSENT, q->q_flags))
599*69924Seric return 0;
600*69924Seric }
601*69924Seric return -1;
6024633Seric }
6034633Seric /*
6046978Seric ** ERRBODY -- output the body of an error message.
6056978Seric **
6066978Seric ** Typically this is a copy of the transcript plus a copy of the
6076978Seric ** original offending message.
6086978Seric **
609297Seric ** Parameters:
61065870Seric ** mci -- the mailer connection information.
6119542Seric ** e -- the envelope we are working in.
61267546Seric ** separator -- any possible MIME separator.
61367936Seric ** flags -- to modify the behaviour.
614297Seric **
615297Seric ** Returns:
616297Seric ** none
617297Seric **
618297Seric ** Side Effects:
6196978Seric ** Outputs the body of an error message.
620297Seric */
621297Seric
62269748Seric void
errbody(mci,e,separator)62368228Seric errbody(mci, e, separator)
62465870Seric register MCI *mci;
6259542Seric register ENVELOPE *e;
62667546Seric char *separator;
627297Seric {
6286978Seric register FILE *xfile;
62959082Seric char *p;
63059082Seric register ADDRESS *q;
63159082Seric bool printheader;
63268559Seric bool sendbody;
6333189Seric char buf[MAXLINE];
63469858Seric extern char *xuntextify();
635297Seric
63667546Seric if (bitset(MCIF_INHEADER, mci->mci_flags))
63767546Seric {
63867546Seric putline("", mci);
63967546Seric mci->mci_flags &= ~MCIF_INHEADER;
64067546Seric }
64158680Seric if (e->e_parent == NULL)
64258680Seric {
64358680Seric syserr("errbody: null parent");
64465870Seric putline(" ----- Original message lost -----\n", mci);
64558680Seric return;
64658680Seric }
64758680Seric
6489057Seric /*
64959730Seric ** Output MIME header.
65059730Seric */
65159730Seric
65259730Seric if (e->e_msgboundary != NULL)
65359730Seric {
65465870Seric putline("This is a MIME-encapsulated message", mci);
65565870Seric putline("", mci);
65659730Seric (void) sprintf(buf, "--%s", e->e_msgboundary);
65765870Seric putline(buf, mci);
65865870Seric putline("", mci);
65959730Seric }
66059730Seric
66159730Seric /*
66263852Seric ** Output introductory information.
66363852Seric */
66463852Seric
66564718Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
66664718Seric if (bitset(QBADADDR, q->q_flags))
66764718Seric break;
66865054Seric if (q == NULL &&
66965054Seric !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
67064718Seric {
67164718Seric putline(" **********************************************",
67265870Seric mci);
67364718Seric putline(" ** THIS IS A WARNING MESSAGE ONLY **",
67465870Seric mci);
67564718Seric putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **",
67665870Seric mci);
67764718Seric putline(" **********************************************",
67865870Seric mci);
67965870Seric putline("", mci);
68064718Seric }
68164718Seric sprintf(buf, "The original message was received at %s",
68264718Seric arpadate(ctime(&e->e_parent->e_ctime)));
68365870Seric putline(buf, mci);
68468529Seric expand("from \201_", buf, sizeof buf, e->e_parent);
68565870Seric putline(buf, mci);
68665870Seric putline("", mci);
68763852Seric
68863852Seric /*
68955372Seric ** Output error message header (if specified and available).
69055372Seric */
69155372Seric
69267682Seric if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
69355372Seric {
69455372Seric if (*ErrMsgFile == '/')
69555372Seric {
69655372Seric xfile = fopen(ErrMsgFile, "r");
69755372Seric if (xfile != NULL)
69855372Seric {
69955372Seric while (fgets(buf, sizeof buf, xfile) != NULL)
70055425Seric {
70168529Seric expand(buf, buf, sizeof buf, e);
70265870Seric putline(buf, mci);
70355425Seric }
70455372Seric (void) fclose(xfile);
70565870Seric putline("\n", mci);
70655372Seric }
70755372Seric }
70855372Seric else
70955372Seric {
71068529Seric expand(ErrMsgFile, buf, sizeof buf, e);
71165870Seric putline(buf, mci);
71265870Seric putline("", mci);
71355372Seric }
71455372Seric }
71555372Seric
71655372Seric /*
71759082Seric ** Output message introduction
71859082Seric */
71959082Seric
72059082Seric printheader = TRUE;
72159082Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
72259082Seric {
72368868Seric if (bitset(QBADADDR, q->q_flags))
72459082Seric {
72568868Seric if (!bitset(QPINGONFAILURE, q->q_flags))
72668603Seric continue;
72768868Seric p = "unrecoverable error";
72868868Seric }
72968868Seric else if (!bitset(QPRIMARY, q->q_flags))
73068868Seric continue;
73168868Seric else if (bitset(QRELAYED, q->q_flags))
73268868Seric p = "relayed to non-DSN-aware mailer";
73368868Seric else if (bitset(QDELIVERED, q->q_flags))
73468868Seric {
73568868Seric if (bitset(QEXPANDED, q->q_flags))
73668868Seric p = "successfully delivered to mailing list";
73763787Seric else
73868868Seric p = "successfully delivered to mailbox";
73968868Seric }
74068868Seric else if (bitset(QEXPANDED, q->q_flags))
74168868Seric p = "expanded by alias";
74268868Seric else if (bitset(QDELAYED, q->q_flags))
74368868Seric p = "transient failure";
74468868Seric else
74568868Seric continue;
74668868Seric
74768868Seric if (printheader)
74868868Seric {
74968868Seric putline(" ----- The following addresses have delivery notifications -----",
75068868Seric mci);
75168868Seric printheader = FALSE;
75268868Seric }
75368868Seric
75468868Seric sprintf(buf, "%s (%s)", q->q_paddr, p);
75568868Seric putline(buf, mci);
75668868Seric if (q->q_alias != NULL)
75768868Seric {
75868868Seric strcpy(buf, " (expanded from: ");
75968868Seric strcat(buf, q->q_alias->q_paddr);
76068868Seric strcat(buf, ")");
76165870Seric putline(buf, mci);
76259082Seric }
76359082Seric }
76459082Seric if (!printheader)
76565870Seric putline("\n", mci);
76659082Seric
76759082Seric /*
7689057Seric ** Output transcript of errors
7699057Seric */
7709057Seric
7714086Seric (void) fflush(stdout);
7729542Seric p = queuename(e->e_parent, 'x');
7739337Seric if ((xfile = fopen(p, "r")) == NULL)
7749057Seric {
7759337Seric syserr("Cannot open %s", p);
77665870Seric putline(" ----- Transcript of session is unavailable -----\n", mci);
7779057Seric }
7789057Seric else
7799057Seric {
78068868Seric printheader = TRUE;
7819542Seric if (e->e_xfp != NULL)
7829542Seric (void) fflush(e->e_xfp);
7839057Seric while (fgets(buf, sizeof buf, xfile) != NULL)
78468868Seric {
78568868Seric if (printheader)
78668868Seric putline(" ----- Transcript of session follows -----\n", mci);
78768868Seric printheader = FALSE;
78865870Seric putline(buf, mci);
78968868Seric }
79058680Seric (void) xfclose(xfile, "errbody xscript", p);
7919057Seric }
792297Seric errno = 0;
7934318Seric
79468848Seric #if DSN
7954318Seric /*
79667880Seric ** Output machine-readable version.
79767880Seric */
79867880Seric
79967880Seric if (e->e_msgboundary != NULL)
80067880Seric {
80167880Seric putline("", mci);
80267880Seric (void) sprintf(buf, "--%s", e->e_msgboundary);
80367880Seric putline(buf, mci);
80469858Seric putline("Content-Type: message/X-delivery-status-05 (Draft of May 29, 1995)", mci);
80567880Seric putline("", mci);
80667880Seric
80767880Seric /*
80867880Seric ** Output per-message information.
80967880Seric */
81067880Seric
81167880Seric /* original envelope id from MAIL FROM: line */
81267880Seric if (e->e_parent->e_envid != NULL)
81367880Seric {
81467880Seric (void) sprintf(buf, "Original-Envelope-Id: %s",
81569858Seric xuntextify(e->e_parent->e_envid));
81667880Seric putline(buf, mci);
81767880Seric }
81867880Seric
81968228Seric /* Reporting-MTA: is us (required) */
82069858Seric (void) sprintf(buf, "Reporting-MTA: dns; %s", MyHostName);
82167880Seric putline(buf, mci);
82267880Seric
82368868Seric /* DSN-Gateway: not relevant since we are not translating */
82468868Seric
82568228Seric /* Received-From-MTA: shows where we got this message from */
82667990Seric if (RealHostName != NULL)
82767990Seric {
82868228Seric /* XXX use $s for type? */
82968228Seric p = e->e_parent->e_from.q_mailer->m_mtatype;
83068228Seric if (p == NULL)
83168228Seric p = "dns";
83268228Seric (void) sprintf(buf, "Received-From-MTA: %s; %s",
83369858Seric p, RealHostName);
83467990Seric putline(buf, mci);
83567990Seric }
83667963Seric
83767963Seric /* Arrival-Date: -- when it arrived here */
83867963Seric (void) sprintf(buf, "Arrival-Date: %s",
83967963Seric arpadate(ctime(&e->e_parent->e_ctime)));
84067963Seric putline(buf, mci);
84167963Seric
84267880Seric /*
84367880Seric ** Output per-address information.
84467880Seric */
84567880Seric
84667880Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
84767880Seric {
84867880Seric register ADDRESS *r;
84968603Seric char *action;
85067880Seric
85168603Seric if (bitset(QBADADDR, q->q_flags))
85268868Seric action = "failed";
85368603Seric else if (!bitset(QPRIMARY, q->q_flags))
85467880Seric continue;
85568868Seric else if (bitset(QDELIVERED, q->q_flags))
85668868Seric {
85768868Seric if (bitset(QEXPANDED, q->q_flags))
85868868Seric action = "delivered (to mailing list)";
85968868Seric else
86068868Seric action = "delivered (to mailbox)";
86168868Seric }
86268603Seric else if (bitset(QRELAYED, q->q_flags))
86368868Seric action = "relayed (to non-DSN-aware mailer)";
86468868Seric else if (bitset(QEXPANDED, q->q_flags))
86568868Seric action = "expanded (to multi-recipient alias)";
86668868Seric else if (bitset(QDELAYED, q->q_flags))
86768603Seric action = "delayed";
86868603Seric else
86968603Seric continue;
87068603Seric
87167880Seric putline("", mci);
87267880Seric
87368228Seric /* Original-Recipient: -- passed from on high */
87468228Seric if (q->q_orcpt != NULL)
87568228Seric {
87668228Seric (void) sprintf(buf, "Original-Recipient: %s",
87769858Seric q->q_orcpt);
87868228Seric putline(buf, mci);
87968228Seric }
88068228Seric
88168228Seric /* Final-Recipient: -- the name from the RCPT command */
88268228Seric p = e->e_parent->e_from.q_mailer->m_addrtype;
88368228Seric if (p == NULL)
88468228Seric p = "rfc822";
88568228Seric for (r = q; r->q_alias != NULL; r = r->q_alias)
88668228Seric continue;
88768228Seric if (strchr(r->q_user, '@') == NULL)
88868583Seric {
88968583Seric (void) sprintf(buf, "Final-Recipient: %s; %s@",
89069858Seric p, r->q_user);
89169858Seric strcat(buf, MyHostName);
89268583Seric }
89367998Seric else
89468583Seric {
89568228Seric (void) sprintf(buf, "Final-Recipient: %s; %s",
89669858Seric p, r->q_user);
89768583Seric }
89867880Seric putline(buf, mci);
89967880Seric
90068603Seric /* X-Actual-Recipient: -- the real problem address */
90169897Seric if (r != q && q->q_user[0] != '\0')
90268603Seric {
90368603Seric if (strchr(q->q_user, '@') == NULL)
90468603Seric {
90568603Seric (void) sprintf(buf, "X-Actual-Recipient: %s; %s@",
90669858Seric p, q->q_user);
90769858Seric strcat(buf, MyHostName);
90868603Seric }
90968603Seric else
91068603Seric {
91168603Seric (void) sprintf(buf, "X-Actual-Recipient: %s; %s",
91269858Seric p, q->q_user);
91368603Seric }
91468603Seric putline(buf, mci);
91568603Seric }
91668603Seric
91767880Seric /* Action: -- what happened? */
91868603Seric sprintf(buf, "Action: %s", action);
91968603Seric putline(buf, mci);
92067880Seric
92167880Seric /* Status: -- what _really_ happened? */
92267880Seric strcpy(buf, "Status: ");
92367880Seric if (q->q_status != NULL)
92467880Seric strcat(buf, q->q_status);
92567880Seric else if (bitset(QBADADDR, q->q_flags))
92668228Seric strcat(buf, "5.0.0");
92767880Seric else if (bitset(QQUEUEUP, q->q_flags))
92868228Seric strcat(buf, "4.0.0");
92967880Seric else
93068228Seric strcat(buf, "2.0.0");
93167880Seric putline(buf, mci);
93267880Seric
93368228Seric /* Remote-MTA: -- who was I talking to? */
93468228Seric p = q->q_mailer->m_mtatype;
93568228Seric if (p == NULL)
93668228Seric p = "dns";
93768228Seric (void) sprintf(buf, "Remote-MTA: %s; ", p);
93868228Seric if (q->q_statmta != NULL)
93968228Seric p = q->q_statmta;
94068603Seric else if (q->q_host != NULL && q->q_host[0] != '\0')
94168228Seric p = q->q_host;
94268228Seric else
94368228Seric p = NULL;
94468228Seric if (p != NULL)
94568228Seric {
94668228Seric strcat(buf, p);
94768228Seric p = &buf[strlen(buf) - 1];
94868228Seric if (*p == '.')
94968228Seric *p = '\0';
95068228Seric putline(buf, mci);
95168228Seric }
95268228Seric
95368228Seric /* Diagnostic-Code: -- actual result from other end */
95468228Seric if (q->q_rstatus != NULL)
95568228Seric {
95668228Seric p = q->q_mailer->m_diagtype;
95768228Seric if (p == NULL)
95868228Seric p = "smtp";
95968228Seric (void) sprintf(buf, "Diagnostic-Code: %s; %s",
96069858Seric p, q->q_rstatus);
96168228Seric putline(buf, mci);
96268228Seric }
96368228Seric
96468228Seric /* Last-Attempt-Date: -- fine granularity */
96567880Seric if (q->q_statdate == (time_t) 0L)
96667880Seric q->q_statdate = curtime();
96768228Seric (void) sprintf(buf, "Last-Attempt-Date: %s",
96867880Seric arpadate(ctime(&q->q_statdate)));
96967880Seric putline(buf, mci);
97067880Seric
97168868Seric /* Will-Retry-Until: -- for delayed messages only */
97267963Seric if (bitset(QQUEUEUP, q->q_flags) &&
97367963Seric !bitset(QBADADDR, q->q_flags))
97467963Seric {
97567963Seric time_t xdate;
97667963Seric
97767963Seric xdate = e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass];
97868868Seric sprintf(buf, "Will-Retry-Until: %s",
97967963Seric arpadate(ctime(&xdate)));
98067963Seric putline(buf, mci);
98167963Seric }
98267880Seric }
98367880Seric }
98468028Seric #endif
98567880Seric
98667880Seric /*
9874318Seric ** Output text of original message
9884318Seric */
9894318Seric
99065870Seric putline("", mci);
99168564Seric if (bitset(EF_HAS_DF, e->e_parent->e_flags))
9924199Seric {
99368802Seric sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
99468802Seric !bitset(EF_NO_BODY_RETN, e->e_flags);
99568559Seric
99667880Seric if (e->e_msgboundary == NULL)
99767880Seric {
99868559Seric if (sendbody)
99967880Seric putline(" ----- Original message follows -----\n", mci);
100067880Seric else
100167880Seric putline(" ----- Message header follows -----\n", mci);
100267880Seric (void) fflush(mci->mci_out);
100367880Seric }
10045984Seric else
10055984Seric {
100659730Seric (void) sprintf(buf, "--%s", e->e_msgboundary);
100769918Seric
100865870Seric putline(buf, mci);
100968859Seric (void) sprintf(buf, "Content-Type: %s",
101068859Seric sendbody ? "message/rfc822"
101168859Seric : "text/rfc822-headers");
101268228Seric putline(buf, mci);
101369918Seric
101469918Seric p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header);
101569918Seric if (p != NULL && strcasecmp(p, "binary") != 0)
101669918Seric p = NULL;
101769918Seric if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags))
101869918Seric p = "8bit";
101969918Seric if (p != NULL)
102069918Seric {
102169918Seric (void) sprintf(buf, "Content-Transfer-Encoding: %s",
102269918Seric p);
102369918Seric putline(buf, mci);
102469918Seric }
10255984Seric }
102667981Seric putline("", mci);
102768228Seric putheader(mci, e->e_parent->e_header, e->e_parent);
102868559Seric if (sendbody)
102968228Seric putbody(mci, e->e_parent, e->e_msgboundary);
103068228Seric else if (e->e_msgboundary == NULL)
103167546Seric {
103267546Seric putline("", mci);
103365870Seric putline(" ----- Message body suppressed -----", mci);
103467546Seric }
10354199Seric }
103668228Seric else if (e->e_msgboundary == NULL)
103710170Seric {
103865870Seric putline(" ----- No message was collected -----\n", mci);
103910170Seric }
10404318Seric
104160010Seric if (e->e_msgboundary != NULL)
104260010Seric {
104365870Seric putline("", mci);
104460010Seric (void) sprintf(buf, "--%s--", e->e_msgboundary);
104565870Seric putline(buf, mci);
104660010Seric }
104765870Seric putline("", mci);
104859730Seric
10494318Seric /*
10504318Seric ** Cleanup and exit
10514318Seric */
10524318Seric
1053297Seric if (errno != 0)
10546978Seric syserr("errbody: I/O error");
1055297Seric }
105658144Seric /*
105768228Seric ** SMTPTODSN -- convert SMTP to DSN status code
105868228Seric **
105968228Seric ** Parameters:
106068228Seric ** smtpstat -- the smtp status code (e.g., 550).
106168228Seric **
106268228Seric ** Returns:
106368228Seric ** The DSN version of the status code.
106468228Seric */
106568228Seric
106668228Seric char *
smtptodsn(smtpstat)106768228Seric smtptodsn(smtpstat)
106868228Seric int smtpstat;
106968228Seric {
107068857Seric if (smtpstat < 0)
107168857Seric return "4.4.2";
107268857Seric
107368228Seric switch (smtpstat)
107468228Seric {
107568228Seric case 450: /* Req mail action not taken: mailbox unavailable */
107668228Seric return "4.2.0";
107768228Seric
107868228Seric case 451: /* Req action aborted: local error in processing */
107968228Seric return "4.3.0";
108068228Seric
108168228Seric case 452: /* Req action not taken: insufficient sys storage */
108268228Seric return "4.3.1";
108368228Seric
108468228Seric case 500: /* Syntax error, command unrecognized */
108568228Seric return "5.5.2";
108668228Seric
108768228Seric case 501: /* Syntax error in parameters or arguments */
108868228Seric return "5.5.4";
108968228Seric
109068228Seric case 502: /* Command not implemented */
109168228Seric return "5.5.1";
109268228Seric
109368228Seric case 503: /* Bad sequence of commands */
109468228Seric return "5.5.1";
109568228Seric
109668228Seric case 504: /* Command parameter not implemented */
109768228Seric return "5.5.4";
109868228Seric
109968228Seric case 550: /* Req mail action not taken: mailbox unavailable */
110068228Seric return "5.2.0";
110168228Seric
110268228Seric case 551: /* User not local; please try <...> */
110368228Seric return "5.1.6";
110468228Seric
110568228Seric case 552: /* Req mail action aborted: exceeded storage alloc */
110668228Seric return "5.2.2";
110768228Seric
110868228Seric case 553: /* Req action not taken: mailbox name not allowed */
110968228Seric return "5.1.3";
111068228Seric
111168228Seric case 554: /* Transaction failed */
111268228Seric return "5.0.0";
111368228Seric }
111468228Seric
111568228Seric if ((smtpstat / 100) == 2)
111668228Seric return "2.0.0";
111768228Seric if ((smtpstat / 100) == 4)
111868228Seric return "4.0.0";
111968228Seric return "5.0.0";
112068228Seric }
112168228Seric /*
112268228Seric ** XTEXTIFY -- take regular text and turn it into DSN-style xtext
112368228Seric **
112468228Seric ** Parameters:
112568228Seric ** t -- the text to convert.
112668228Seric **
112768228Seric ** Returns:
112868228Seric ** The xtext-ified version of the same string.
112968228Seric */
113068228Seric
113168228Seric char *
xtextify(t)113268228Seric xtextify(t)
113368228Seric register char *t;
113468228Seric {
113568228Seric register char *p;
113668228Seric int l;
113768228Seric int nbogus;
113868228Seric static char *bp = NULL;
113968228Seric static int bplen = 0;
114068228Seric
114168228Seric /* figure out how long this xtext will have to be */
114268228Seric nbogus = l = 0;
114368228Seric for (p = t; *p != '\0'; p++)
114468228Seric {
114568228Seric register int c = (*p & 0xff);
114668228Seric
114768228Seric /* ASCII dependence here -- this is the way the spec words it */
114868868Seric if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(')
114968228Seric nbogus++;
115068228Seric l++;
115168228Seric }
115268228Seric if (nbogus == 0)
115368228Seric return t;
115468228Seric l += nbogus * 2 + 1;
115568228Seric
115668228Seric /* now allocate space if necessary for the new string */
115768228Seric if (l > bplen)
115868228Seric {
115968228Seric if (bp != NULL)
116068228Seric free(bp);
116168228Seric bp = xalloc(l);
116268228Seric bplen = l;
116368228Seric }
116468228Seric
116568228Seric /* ok, copy the text with byte expansion */
116668228Seric for (p = bp; *t != '\0'; )
116768228Seric {
116868228Seric register int c = (*t++ & 0xff);
116968228Seric
117068228Seric /* ASCII dependence here -- this is the way the spec words it */
117168228Seric if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(')
117268228Seric {
117368228Seric *p++ = '+';
117468228Seric *p++ = "0123456789abcdef"[c >> 4];
117568228Seric *p++ = "0123456789abcdef"[c & 0xf];
117668228Seric }
117768228Seric else
117868228Seric *p++ = c;
117968228Seric }
118068228Seric *p = '\0';
118168228Seric return bp;
118268228Seric }
118368228Seric /*
118469858Seric ** XUNTEXTIFY -- take xtext and turn it into plain text
118569858Seric **
118669858Seric ** Parameters:
118769858Seric ** t -- the xtextified text.
118869858Seric **
118969858Seric ** Returns:
119069858Seric ** The decoded text. No attempt is made to deal with
119169858Seric ** null strings in the resulting text.
119269858Seric */
119369858Seric
119469858Seric char *
xuntextify(t)119569858Seric xuntextify(t)
119669858Seric register char *t;
119769858Seric {
119869858Seric register char *p;
119969858Seric int l;
120069858Seric static char *bp = NULL;
120169858Seric static int bplen = 0;
120269858Seric
120369858Seric /* heuristic -- if no plus sign, just return the input */
120469858Seric if (strchr(t, '+') == NULL)
120569858Seric return t;
120669858Seric
120769858Seric /* xtext is always longer than decoded text */
120869858Seric l = strlen(t);
120969858Seric if (l > bplen)
121069858Seric {
121169858Seric if (bp != NULL)
121269858Seric free(bp);
121369858Seric bp = xalloc(l);
121469858Seric bplen = l;
121569858Seric }
121669858Seric
121769858Seric /* ok, copy the text with byte compression */
121869858Seric for (p = bp; *t != '\0'; t++)
121969858Seric {
122069858Seric register int c = *t & 0xff;
122169858Seric
122269858Seric if (c != '+')
122369858Seric {
122469858Seric *p++ = c;
122569858Seric continue;
122669858Seric }
122769858Seric
122869858Seric c = *++t & 0xff;
122969858Seric if (!isascii(c) || !isxdigit(c))
123069858Seric {
123169858Seric /* error -- first digit is not hex */
123269858Seric usrerr("bogus xtext: +%c", c);
123369858Seric t--;
123469858Seric continue;
123569858Seric }
123669858Seric if (isdigit(c))
123769858Seric c -= '0';
123869858Seric else if (isupper(c))
123969858Seric c -= 'A' - 10;
124069858Seric else
124169858Seric c -= 'a' - 10;
124269858Seric *p = c << 4;
124369858Seric
124469858Seric c = *++t & 0xff;
124569858Seric if (!isascii(c) || !isxdigit(c))
124669858Seric {
124769858Seric /* error -- second digit is not hex */
124869858Seric usrerr("bogus xtext: +%x%c", *p >> 4, c);
124969858Seric t--;
125069858Seric continue;
125169858Seric }
125269858Seric if (isdigit(c))
125369858Seric c -= '0';
125469858Seric else if (isupper(c))
125569858Seric c -= 'A' - 10;
125669858Seric else
125769858Seric c -= 'a' - 10;
125869858Seric *p++ |= c;
125969858Seric }
126069858Seric return bp;
126169858Seric }
126269858Seric /*
126368583Seric ** XTEXTOK -- check if a string is legal xtext
126468583Seric **
126568583Seric ** Xtext is used in Delivery Status Notifications. The spec was
126668583Seric ** taken from draft-ietf-notary-mime-delivery-04.txt.
126768583Seric **
126868583Seric ** Parameters:
126968583Seric ** s -- the string to check.
127068583Seric **
127168583Seric ** Returns:
127268583Seric ** TRUE -- if 's' is legal xtext.
127368583Seric ** FALSE -- if it has any illegal characters in it.
127468583Seric */
127568583Seric
127668583Seric bool
xtextok(s)127768583Seric xtextok(s)
127868583Seric char *s;
127968583Seric {
128068583Seric int c;
128168583Seric
128268583Seric while ((c = *s++) != '\0')
128368583Seric {
128468583Seric if (c == '+')
128568583Seric {
128668583Seric c = *s++;
128768583Seric if (!isascii(c) || !isxdigit(c))
128868583Seric return FALSE;
128968583Seric c = *s++;
129068583Seric if (!isascii(c) || !isxdigit(c))
129168583Seric return FALSE;
129268583Seric }
129369888Seric else if (c < '!' || c > '~' || c == '=')
129468583Seric return FALSE;
129568583Seric }
129668583Seric return TRUE;
129768583Seric }
129868583Seric /*
129958144Seric ** PRUNEROUTE -- prune an RFC-822 source route
130058144Seric **
130158144Seric ** Trims down a source route to the last internet-registered hop.
130258144Seric ** This is encouraged by RFC 1123 section 5.3.3.
130358144Seric **
130458144Seric ** Parameters:
130558144Seric ** addr -- the address
130658144Seric **
130758144Seric ** Returns:
130858144Seric ** TRUE -- address was modified
130958144Seric ** FALSE -- address could not be pruned
131058144Seric **
131158144Seric ** Side Effects:
131258144Seric ** modifies addr in-place
131358144Seric */
131458144Seric
131569748Seric bool
pruneroute(addr)131658144Seric pruneroute(addr)
131758144Seric char *addr;
131858144Seric {
131966334Seric #if NAMED_BIND
132058144Seric char *start, *at, *comma;
132158144Seric char c;
132258144Seric int rcode;
132358144Seric char hostbuf[BUFSIZ];
132458144Seric char *mxhosts[MAXMXHOSTS + 1];
132558144Seric
132658144Seric /* check to see if this is really a route-addr */
132758144Seric if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
132858144Seric return FALSE;
132958144Seric start = strchr(addr, ':');
133058144Seric at = strrchr(addr, '@');
133158144Seric if (start == NULL || at == NULL || at < start)
133258144Seric return FALSE;
133358144Seric
133458144Seric /* slice off the angle brackets */
133558144Seric strcpy(hostbuf, at + 1);
133658144Seric hostbuf[strlen(hostbuf) - 1] = '\0';
133758144Seric
133858144Seric while (start)
133958144Seric {
134059273Seric if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
134158144Seric {
134258144Seric strcpy(addr + 1, start + 1);
134358144Seric return TRUE;
134458144Seric }
134558144Seric c = *start;
134658144Seric *start = '\0';
134758144Seric comma = strrchr(addr, ',');
134858144Seric if (comma && comma[1] == '@')
134958144Seric strcpy(hostbuf, comma + 2);
135058144Seric else
135158144Seric comma = 0;
135258144Seric *start = c;
135358144Seric start = comma;
135458144Seric }
135558144Seric #endif
135658144Seric return FALSE;
135758144Seric }
1358