122711Sdist /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642829Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822711Sdist 
922711Sdist #ifndef lint
10*59987Seric static char sccsid[] = "@(#)savemail.c	6.41 (Berkeley) 05/13/93";
1133731Sbostic #endif /* not lint */
1222711Sdist 
13297Seric # include <pwd.h>
143313Seric # include "sendmail.h"
15297Seric 
16297Seric /*
17297Seric **  SAVEMAIL -- Save mail on error
18297Seric **
199375Seric **	If mailing back errors, mail it back to the originator
20297Seric **	together with an error message; otherwise, just put it in
21297Seric **	dead.letter in the user's home directory (if he exists on
22297Seric **	this machine).
23297Seric **
24297Seric **	Parameters:
259337Seric **		e -- the envelope containing the message in error.
26297Seric **
27297Seric **	Returns:
28297Seric **		none
29297Seric **
30297Seric **	Side Effects:
31297Seric **		Saves the letter, by writing or mailing it back to the
32297Seric **		sender, or by putting it in dead.letter in her home
33297Seric **		directory.
34297Seric */
35297Seric 
3624942Seric /* defines for state machine */
3724942Seric # define ESM_REPORT	0	/* report to sender's terminal */
3824942Seric # define ESM_MAIL	1	/* mail back to sender */
3924942Seric # define ESM_QUIET	2	/* messages have already been returned */
4024942Seric # define ESM_DEADLETTER	3	/* save in ~/dead.letter */
4124942Seric # define ESM_POSTMASTER	4	/* return to postmaster */
4224942Seric # define ESM_USRTMP	5	/* save in /usr/tmp/dead.letter */
4324942Seric # define ESM_PANIC	6	/* leave the locked queue/transcript files */
4424942Seric # define ESM_DONE	7	/* the message is successfully delivered */
4524942Seric 
4624942Seric 
479337Seric savemail(e)
489337Seric 	register ENVELOPE *e;
49297Seric {
50297Seric 	register struct passwd *pw;
5124942Seric 	register FILE *fp;
5224942Seric 	int state;
5359290Seric 	auto ADDRESS *q = NULL;
54297Seric 	char buf[MAXLINE+1];
55297Seric 	extern struct passwd *getpwnam();
56297Seric 	register char *p;
57297Seric 	extern char *ttypath();
585846Seric 	typedef int (*fnptr)();
59297Seric 
607676Seric 	if (tTd(6, 1))
6158680Seric 	{
6259101Seric 		printf("\nsavemail, errormode = %c, id = %s\n  e_from=",
6359101Seric 			e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id);
6458680Seric 		printaddr(&e->e_from, FALSE);
6558680Seric 	}
667361Seric 
6759101Seric 	if (e->e_id == NULL)
6859101Seric 	{
6959101Seric 		/* can't return a message with no id */
7059101Seric 		return;
7159101Seric 	}
7259101Seric 
739337Seric 	e->e_flags &= ~EF_FATALERRS;
74297Seric 
75297Seric 	/*
76297Seric 	**  In the unhappy event we don't know who to return the mail
77297Seric 	**  to, make someone up.
78297Seric 	*/
79297Seric 
809337Seric 	if (e->e_from.q_paddr == NULL)
81297Seric 	{
8258733Seric 		e->e_sender = "Postmaster";
8358704Seric 		if (parseaddr(e->e_sender, &e->e_from, 0, '\0', NULL, e) == NULL)
84297Seric 		{
8558733Seric 			syserr("553 Cannot parse Postmaster!");
86297Seric 			ExitStat = EX_SOFTWARE;
87297Seric 			finis();
88297Seric 		}
89297Seric 	}
909337Seric 	e->e_to = NULL;
91297Seric 
92297Seric 	/*
9324942Seric 	**  Basic state machine.
9424942Seric 	**
9524942Seric 	**	This machine runs through the following states:
9624942Seric 	**
9724942Seric 	**	ESM_QUIET	Errors have already been printed iff the
9824942Seric 	**			sender is local.
9924942Seric 	**	ESM_REPORT	Report directly to the sender's terminal.
10024942Seric 	**	ESM_MAIL	Mail response to the sender.
10124942Seric 	**	ESM_DEADLETTER	Save response in ~/dead.letter.
10224942Seric 	**	ESM_POSTMASTER	Mail response to the postmaster.
10324942Seric 	**	ESM_PANIC	Save response anywhere possible.
104297Seric 	*/
105297Seric 
10624942Seric 	/* determine starting state */
10758734Seric 	switch (e->e_errormode)
108297Seric 	{
10924942Seric 	  case EM_WRITE:
11024942Seric 		state = ESM_REPORT;
11124942Seric 		break;
11224942Seric 
11324942Seric 	  case EM_BERKNET:
11424942Seric 		/* mail back, but return o.k. exit status */
115401Seric 		ExitStat = EX_OK;
11624942Seric 
11724942Seric 		/* fall through.... */
11824942Seric 
11924942Seric 	  case EM_MAIL:
12024942Seric 		state = ESM_MAIL;
12124942Seric 		break;
12224942Seric 
12324942Seric 	  case EM_PRINT:
12424979Seric 	  case '\0':
12524942Seric 		state = ESM_QUIET;
12624942Seric 		break;
12724942Seric 
12824942Seric 	  case EM_QUIET:
12924942Seric 		/* no need to return anything at all */
13024942Seric 		return;
13124979Seric 
13224979Seric 	  default:
13358734Seric 		syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
13424979Seric 		state = ESM_MAIL;
13524979Seric 		break;
136297Seric 	}
137297Seric 
13859094Seric 	/* if this is already an error response, send to postmaster */
13959094Seric 	if (bitset(EF_RESPONSE, e->e_flags))
14059094Seric 	{
14159094Seric 		if (e->e_parent != NULL &&
14259094Seric 		    bitset(EF_RESPONSE, e->e_parent->e_flags))
14359094Seric 		{
14459094Seric 			/* got an error sending a response -- can it */
14559094Seric 			return;
14659094Seric 		}
14759094Seric 		state = ESM_POSTMASTER;
14859094Seric 	}
14959094Seric 
15024942Seric 	while (state != ESM_DONE)
151297Seric 	{
15224979Seric 		if (tTd(6, 5))
15324979Seric 			printf("  state %d\n", state);
15424979Seric 
15524942Seric 		switch (state)
156297Seric 		{
15724979Seric 		  case ESM_QUIET:
15824979Seric 			if (e->e_from.q_mailer == LocalMailer)
15924979Seric 				state = ESM_DEADLETTER;
16024979Seric 			else
16124979Seric 				state = ESM_MAIL;
16224979Seric 			break;
16324979Seric 
16424942Seric 		  case ESM_REPORT:
16524942Seric 
16624942Seric 			/*
16724942Seric 			**  If the user is still logged in on the same terminal,
16824942Seric 			**  then write the error messages back to hir (sic).
16924942Seric 			*/
17024942Seric 
17124942Seric 			p = ttypath();
17224942Seric 			if (p == NULL || freopen(p, "w", stdout) == NULL)
17324942Seric 			{
17424942Seric 				state = ESM_MAIL;
17524942Seric 				break;
17624942Seric 			}
17724942Seric 
17858050Seric 			expand("\201n", buf, &buf[sizeof buf - 1], e);
1799375Seric 			printf("\r\nMessage from %s...\r\n", buf);
1809375Seric 			printf("Errors occurred while sending mail.\r\n");
1819542Seric 			if (e->e_xfp != NULL)
1829375Seric 			{
1839542Seric 				(void) fflush(e->e_xfp);
18424942Seric 				fp = fopen(queuename(e, 'x'), "r");
1859375Seric 			}
1869375Seric 			else
18724942Seric 				fp = NULL;
18824942Seric 			if (fp == NULL)
1899375Seric 			{
1909337Seric 				syserr("Cannot open %s", queuename(e, 'x'));
1919375Seric 				printf("Transcript of session is unavailable.\r\n");
1929375Seric 			}
1939375Seric 			else
1949375Seric 			{
1959375Seric 				printf("Transcript follows:\r\n");
19624942Seric 				while (fgets(buf, sizeof buf, fp) != NULL &&
1979375Seric 				       !ferror(stdout))
1989375Seric 					fputs(buf, stdout);
19958680Seric 				(void) xfclose(fp, "savemail transcript", e->e_id);
2009375Seric 			}
20124942Seric 			printf("Original message will be saved in dead.letter.\r\n");
20224942Seric 			state = ESM_DEADLETTER;
20324942Seric 			break;
204297Seric 
20524942Seric 		  case ESM_MAIL:
20624942Seric 			/*
20724942Seric 			**  If mailing back, do it.
20824942Seric 			**	Throw away all further output.  Don't alias,
20924942Seric 			**	since this could cause loops, e.g., if joe
21024942Seric 			**	mails to joe@x, and for some reason the network
21124942Seric 			**	for @x is down, then the response gets sent to
21224942Seric 			**	joe@x, which gives a response, etc.  Also force
21324942Seric 			**	the mail to be delivered even if a version of
21424942Seric 			**	it has already been sent to the sender.
21524942Seric 			*/
216297Seric 
21758680Seric 			if (strcmp(e->e_from.q_paddr, "<>") != 0)
21858680Seric 				(void) sendtolist(e->e_from.q_paddr,
21958680Seric 					  (ADDRESS *) NULL,
22058680Seric 					  &e->e_errorqueue, e);
22158680Seric 
22258680Seric 			/* deliver a cc: to the postmaster if desired */
22358680Seric 			if (PostMasterCopy != NULL)
22424942Seric 			{
22558680Seric 				auto ADDRESS *rlist = NULL;
22658178Seric 
22758680Seric 				(void) sendtolist(PostMasterCopy,
22858304Seric 						  (ADDRESS *) NULL,
22958680Seric 						  &rlist, e);
23058680Seric 				(void) returntosender(e->e_message,
23158680Seric 						      rlist, FALSE, e);
23258680Seric 			}
23358680Seric 			q = e->e_errorqueue;
23458680Seric 			if (q == NULL)
23558680Seric 			{
23658680Seric 				/* this is an error-error */
23758680Seric 				state = ESM_POSTMASTER;
23858680Seric 				break;
23958680Seric 			}
24058966Seric 			if (returntosender(e->e_message,
24158680Seric 					   q, (e->e_class >= 0), e) == 0)
24258680Seric 			{
24358680Seric 				state = ESM_DONE;
24458680Seric 				break;
24558680Seric 			}
24624981Seric 
24758680Seric 			/* didn't work -- return to postmaster */
24858680Seric 			state = ESM_POSTMASTER;
24958680Seric 			break;
25058306Seric 
25158680Seric 		  case ESM_POSTMASTER:
25258680Seric 			/*
25358680Seric 			**  Similar to previous case, but to system postmaster.
25458680Seric 			*/
25558680Seric 
25659432Seric 			q = NULL;
25759432Seric 			if (sendtolist("postmaster", NULL, &q, e) <= 0)
25824942Seric 			{
25958680Seric 				syserr("553 cannot parse postmaster!");
26058680Seric 				ExitStat = EX_SOFTWARE;
26158680Seric 				state = ESM_USRTMP;
26258680Seric 				break;
26324942Seric 			}
26458966Seric 			if (returntosender(e->e_message,
26557438Seric 					   q, (e->e_class >= 0), e) == 0)
26624942Seric 			{
26724942Seric 				state = ESM_DONE;
26824942Seric 				break;
26924942Seric 			}
270297Seric 
27158680Seric 			/* didn't work -- last resort */
27258680Seric 			state = ESM_USRTMP;
27324942Seric 			break;
274297Seric 
27524942Seric 		  case ESM_DEADLETTER:
27624942Seric 			/*
27724942Seric 			**  Save the message in dead.letter.
27824942Seric 			**	If we weren't mailing back, and the user is
27924942Seric 			**	local, we should save the message in
28024942Seric 			**	~/dead.letter so that the poor person doesn't
28124942Seric 			**	have to type it over again -- and we all know
28224942Seric 			**	what poor typists UNIX users are.
28324942Seric 			*/
2845315Seric 
28524942Seric 			p = NULL;
28624942Seric 			if (e->e_from.q_mailer == LocalMailer)
28724942Seric 			{
28824942Seric 				if (e->e_from.q_home != NULL)
28924942Seric 					p = e->e_from.q_home;
29024942Seric 				else if ((pw = getpwnam(e->e_from.q_user)) != NULL)
29124942Seric 					p = pw->pw_dir;
29224942Seric 			}
29324942Seric 			if (p == NULL)
29424942Seric 			{
29558865Seric 				/* no local directory */
29624942Seric 				state = ESM_MAIL;
29724942Seric 				break;
29824942Seric 			}
29924942Seric 			if (e->e_dfp != NULL)
30024942Seric 			{
30124942Seric 				bool oldverb = Verbose;
30224942Seric 
30324942Seric 				/* we have a home directory; open dead.letter */
30424942Seric 				define('z', p, e);
30558050Seric 				expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e);
30624942Seric 				Verbose = TRUE;
30758151Seric 				message("Saving message in %s", buf);
30824942Seric 				Verbose = oldverb;
30924942Seric 				e->e_to = buf;
31024942Seric 				q = NULL;
31158082Seric 				(void) sendtolist(buf, &e->e_from, &q, e);
31224942Seric 				if (deliver(e, q) == 0)
31324942Seric 					state = ESM_DONE;
31424942Seric 				else
31524942Seric 					state = ESM_MAIL;
31624942Seric 			}
31725569Seric 			else
31825569Seric 			{
31925569Seric 				/* no data file -- try mailing back */
32025569Seric 				state = ESM_MAIL;
32125569Seric 			}
32224942Seric 			break;
32324942Seric 
32424942Seric 		  case ESM_USRTMP:
32524942Seric 			/*
32624942Seric 			**  Log the mail in /usr/tmp/dead.letter.
32724942Seric 			*/
32824942Seric 
32957438Seric 			if (e->e_class < 0)
33057438Seric 			{
33157438Seric 				state = ESM_DONE;
33257438Seric 				break;
33357438Seric 			}
33457438Seric 
33559745Seric 			fp = dfopen("/usr/tmp/dead.letter",
33659745Seric 				    O_WRONLY|O_CREAT|O_APPEND, FileMode);
33724942Seric 			if (fp == NULL)
33824942Seric 			{
33924942Seric 				state = ESM_PANIC;
34024942Seric 				break;
34124942Seric 			}
34224942Seric 
34358010Seric 			putfromline(fp, FileMailer, e);
34458010Seric 			(*e->e_puthdr)(fp, FileMailer, e);
34558010Seric 			putline("\n", fp, FileMailer);
34659730Seric 			(*e->e_putbody)(fp, FileMailer, e, NULL);
34758010Seric 			putline("\n", fp, FileMailer);
34824942Seric 			(void) fflush(fp);
34924942Seric 			state = ferror(fp) ? ESM_PANIC : ESM_DONE;
35058680Seric 			(void) xfclose(fp, "savemail", "/usr/tmp/dead.letter");
35124942Seric 			break;
35224942Seric 
35324942Seric 		  default:
35458151Seric 			syserr("554 savemail: unknown state %d", state);
35524942Seric 
35624942Seric 			/* fall through ... */
35724942Seric 
35824942Seric 		  case ESM_PANIC:
35924942Seric 			/* leave the locked queue & transcript files around */
36058151Seric 			syserr("554 savemail: cannot save rejected email anywhere");
36124942Seric 			exit(EX_SOFTWARE);
36224942Seric 		}
363297Seric 	}
364297Seric }
365297Seric /*
3664633Seric **  RETURNTOSENDER -- return a message to the sender with an error.
3674633Seric **
3684633Seric **	Parameters:
3694633Seric **		msg -- the explanatory message.
37016479Seric **		returnq -- the queue of people to send the message to.
3715984Seric **		sendbody -- if TRUE, also send back the body of the
3725984Seric **			message; otherwise just send the header.
37355012Seric **		e -- the current envelope.
3744633Seric **
3754633Seric **	Returns:
3764633Seric **		zero -- if everything went ok.
3774633Seric **		else -- some error.
3784633Seric **
3794633Seric **	Side Effects:
3804633Seric **		Returns the current message to the sender via
3814633Seric **		mail.
3824633Seric */
3834633Seric 
3845984Seric static bool	SendBody;
3854633Seric 
3867045Seric #define MAXRETURNS	6	/* max depth of returning messages */
38758559Seric #define ERRORFUDGE	100	/* nominal size of error message text */
3887045Seric 
38955012Seric returntosender(msg, returnq, sendbody, e)
3904633Seric 	char *msg;
39116479Seric 	ADDRESS *returnq;
3925984Seric 	bool sendbody;
39355012Seric 	register ENVELOPE *e;
3944633Seric {
3954633Seric 	char buf[MAXNAME];
3966978Seric 	extern putheader(), errbody();
3976978Seric 	register ENVELOPE *ee;
39858680Seric 	ENVELOPE *oldcur = CurEnv;
3996978Seric 	extern ENVELOPE *newenvelope();
4006978Seric 	ENVELOPE errenvelope;
4017045Seric 	static int returndepth;
4029375Seric 	register ADDRESS *q;
4034633Seric 
40458966Seric 	if (msg == NULL)
40558966Seric 		msg = "Unable to deliver mail";
40658966Seric 
4077676Seric 	if (tTd(6, 1))
4087287Seric 	{
40958680Seric 		printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
41055012Seric 		       msg, returndepth, e);
41116479Seric 		printaddr(returnq, TRUE);
4127287Seric 	}
4137287Seric 
4147045Seric 	if (++returndepth >= MAXRETURNS)
4157045Seric 	{
4167045Seric 		if (returndepth != MAXRETURNS)
41758151Seric 			syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
4187045Seric 		/* don't "unrecurse" and fake a clean exit */
4197045Seric 		/* returndepth--; */
4207045Seric 		return (0);
4217045Seric 	}
4227045Seric 
4235984Seric 	SendBody = sendbody;
42458680Seric 	define('g', e->e_from.q_paddr, e);
42558179Seric 	ee = newenvelope(&errenvelope, e);
42658050Seric 	define('a', "\201b", ee);
42759057Seric 	define('r', "internal", ee);
42859057Seric 	define('s', "localhost", ee);
42959057Seric 	define('_', "localhost", ee);
4306978Seric 	ee->e_puthdr = putheader;
4316978Seric 	ee->e_putbody = errbody;
4329375Seric 	ee->e_flags |= EF_RESPONSE;
43355012Seric 	if (!bitset(EF_OLDSTYLE, e->e_flags))
43445155Seric 		ee->e_flags &= ~EF_OLDSTYLE;
43516479Seric 	ee->e_sendqueue = returnq;
43658559Seric 	ee->e_msgsize = e->e_msgsize + ERRORFUDGE;
4379542Seric 	openxscript(ee);
43816479Seric 	for (q = returnq; q != NULL; q = q->q_next)
4399375Seric 	{
44058559Seric 		if (bitset(QDONTSEND, q->q_flags))
44158559Seric 			continue;
44258559Seric 
44358559Seric 		ee->e_nrcpts++;
44458559Seric 
44558144Seric 		if (!DontPruneRoutes && pruneroute(q->q_paddr))
44658333Seric 			parseaddr(q->q_paddr, q, 0, '\0', NULL, e);
44758144Seric 
4489375Seric 		if (q->q_alias == NULL)
44959580Seric 			addheader("To", q->q_paddr, ee);
4509375Seric 	}
45124942Seric 
45257642Seric # ifdef LOG
45358020Seric 	if (LogLevel > 5)
45457642Seric 		syslog(LOG_INFO, "%s: %s: return to sender: %s",
45557642Seric 			e->e_id, ee->e_id, msg);
45657642Seric # endif
45757642Seric 
45810845Seric 	(void) sprintf(buf, "Returned mail: %s", msg);
45959580Seric 	addheader("Subject", buf, ee);
46059730Seric 	if (SendMIMEErrors)
46159730Seric 	{
462*59987Seric 		addheader("MIME-Version", "1.0", ee);
46359730Seric 		(void) sprintf(buf, "%s.%ld/%s",
46459730Seric 			ee->e_id, curtime(), MyHostName);
46559730Seric 		ee->e_msgboundary = newstr(buf);
46659730Seric 		(void) sprintf(buf, "multipart/mixed; boundary=\"%s\"",
46759730Seric 					ee->e_msgboundary);
46859730Seric 		addheader("Content-Type", buf, ee);
46959730Seric 	}
4704633Seric 
4714633Seric 	/* fake up an address header for the from person */
47258050Seric 	expand("\201n", buf, &buf[sizeof buf - 1], e);
47358680Seric 	if (parseaddr(buf, &ee->e_from, 1, '\0', NULL, e) == NULL)
4744633Seric 	{
47558151Seric 		syserr("553 Can't parse myself!");
4764633Seric 		ExitStat = EX_SOFTWARE;
4777045Seric 		returndepth--;
4784633Seric 		return (-1);
4794633Seric 	}
48058704Seric 	ee->e_sender = ee->e_from.q_paddr;
4815984Seric 
4826978Seric 	/* push state into submessage */
4836978Seric 	CurEnv = ee;
48458050Seric 	define('f', "\201n", ee);
4859375Seric 	define('x', "Mail Delivery Subsystem", ee);
48658929Seric 	eatheader(ee, TRUE);
4875984Seric 
4886978Seric 	/* actually deliver the error message */
48914876Seric 	sendall(ee, SM_DEFAULT);
4906978Seric 
4916978Seric 	/* restore state */
4927811Seric 	dropenvelope(ee);
49358680Seric 	CurEnv = oldcur;
4947045Seric 	returndepth--;
4956978Seric 
4967045Seric 	/* should check for delivery errors here */
4974633Seric 	return (0);
4984633Seric }
4994633Seric /*
5006978Seric **  ERRBODY -- output the body of an error message.
5016978Seric **
5026978Seric **	Typically this is a copy of the transcript plus a copy of the
5036978Seric **	original offending message.
5046978Seric **
505297Seric **	Parameters:
506297Seric **		fp -- the output file.
50710170Seric **		m -- the mailer to output to.
5089542Seric **		e -- the envelope we are working in.
509297Seric **
510297Seric **	Returns:
511297Seric **		none
512297Seric **
513297Seric **	Side Effects:
5146978Seric **		Outputs the body of an error message.
515297Seric */
516297Seric 
51710170Seric errbody(fp, m, e)
518297Seric 	register FILE *fp;
5194318Seric 	register struct mailer *m;
5209542Seric 	register ENVELOPE *e;
521297Seric {
5226978Seric 	register FILE *xfile;
52359082Seric 	char *p;
52459082Seric 	register ADDRESS *q;
52559082Seric 	bool printheader;
5263189Seric 	char buf[MAXLINE];
527297Seric 
52858680Seric 	if (e->e_parent == NULL)
52958680Seric 	{
53058680Seric 		syserr("errbody: null parent");
53158680Seric 		putline("   ----- Original message lost -----\n", fp, m);
53258680Seric 		return;
53358680Seric 	}
53458680Seric 
5359057Seric 	/*
53659730Seric 	**  Output MIME header.
53759730Seric 	*/
53859730Seric 
53959730Seric 	if (e->e_msgboundary != NULL)
54059730Seric 	{
54159730Seric 		putline("This is a MIME-encapsulated message", fp, m);
54259730Seric 		putline("", fp, m);
54359730Seric 		(void) sprintf(buf, "--%s", e->e_msgboundary);
54459730Seric 		putline(buf, fp, m);
54559730Seric 		putline("", fp, m);
54659730Seric 	}
54759730Seric 
54859730Seric 	/*
54955372Seric 	**  Output error message header (if specified and available).
55055372Seric 	*/
55155372Seric 
55255372Seric 	if (ErrMsgFile != NULL)
55355372Seric 	{
55455372Seric 		if (*ErrMsgFile == '/')
55555372Seric 		{
55655372Seric 			xfile = fopen(ErrMsgFile, "r");
55755372Seric 			if (xfile != NULL)
55855372Seric 			{
55955372Seric 				while (fgets(buf, sizeof buf, xfile) != NULL)
56055425Seric 				{
56155425Seric 					expand(buf, buf, &buf[sizeof buf - 1], e);
56255372Seric 					putline(buf, fp, m);
56355425Seric 				}
56455372Seric 				(void) fclose(xfile);
56559082Seric 				putline("\n", fp, m);
56655372Seric 			}
56755372Seric 		}
56855372Seric 		else
56955372Seric 		{
57055425Seric 			expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e);
57155425Seric 			putline(buf, fp, m);
57259730Seric 			putline("", fp, m);
57355372Seric 		}
57455372Seric 	}
57555372Seric 
57655372Seric 	/*
57759082Seric 	**  Output message introduction
57859082Seric 	*/
57959082Seric 
58059082Seric 	printheader = TRUE;
58159082Seric 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
58259082Seric 	{
58359082Seric 		if (bitset(QBADADDR, q->q_flags))
58459082Seric 		{
58559082Seric 			if (printheader)
58659082Seric 			{
58759730Seric 				putline("   ----- The following addresses failed -----",
58859082Seric 					fp, m);
58959082Seric 				printheader = FALSE;
59059082Seric 			}
59159113Seric 			if (q->q_alias != NULL)
59259730Seric 				putline(q->q_alias->q_paddr, fp, m);
59359113Seric 			else
59459730Seric 				putline(q->q_paddr, fp, m);
59559082Seric 		}
59659082Seric 	}
59759082Seric 	if (!printheader)
59859082Seric 		putline("\n", fp, m);
59959082Seric 
60059082Seric 	/*
6019057Seric 	**  Output transcript of errors
6029057Seric 	*/
6039057Seric 
6044086Seric 	(void) fflush(stdout);
6059542Seric 	p = queuename(e->e_parent, 'x');
6069337Seric 	if ((xfile = fopen(p, "r")) == NULL)
6079057Seric 	{
6089337Seric 		syserr("Cannot open %s", p);
60959082Seric 		putline("   ----- Transcript of session is unavailable -----\n", fp, m);
6109057Seric 	}
6119057Seric 	else
6129057Seric 	{
61358680Seric 		putline("   ----- Transcript of session follows -----\n", fp, m);
6149542Seric 		if (e->e_xfp != NULL)
6159542Seric 			(void) fflush(e->e_xfp);
6169057Seric 		while (fgets(buf, sizeof buf, xfile) != NULL)
61710170Seric 			putline(buf, fp, m);
61858680Seric 		(void) xfclose(xfile, "errbody xscript", p);
6199057Seric 	}
620297Seric 	errno = 0;
6214318Seric 
6224318Seric 	/*
6234318Seric 	**  Output text of original message
6244318Seric 	*/
6254318Seric 
6264289Seric 	if (NoReturn)
62758665Seric 		SendBody = FALSE;
62859730Seric 	putline("", fp, m);
62958680Seric 	if (e->e_parent->e_df != NULL)
6304199Seric 	{
6315984Seric 		if (SendBody)
63210170Seric 			putline("   ----- Unsent message follows -----\n", fp, m);
6335984Seric 		else
634*59987Seric 			putline("   ----- Message header follows -----\n", fp, m);
63559730Seric 		(void) fflush(fp);
63659730Seric 
63759730Seric 		if (e->e_msgboundary != NULL)
6385984Seric 		{
63959730Seric 			putline("", fp, m);
64059730Seric 			(void) sprintf(buf, "--%s", e->e_msgboundary);
64159730Seric 			putline(buf, fp, m);
642*59987Seric 			putline("Content-Type: message/rfc822", fp, m);
64359730Seric 			putline("", fp, m);
6445984Seric 		}
64559730Seric 		putheader(fp, m, e->e_parent);
64659730Seric 		putline("", fp, m);
64759730Seric 		if (SendBody)
64859730Seric 			putbody(fp, m, e->e_parent, e->e_msgboundary);
649*59987Seric 		else
650*59987Seric 			putline("", fp, m);
65159730Seric 		if (e->e_msgboundary != NULL)
65259730Seric 		{
653*59987Seric 			putline("", fp, m);
65459730Seric 			(void) sprintf(buf, "--%s--", e->e_msgboundary);
65559730Seric 			putline(buf, fp, m);
65659730Seric 		}
6574199Seric 	}
6584199Seric 	else
65910170Seric 	{
66010170Seric 		putline("  ----- No message was collected -----\n", fp, m);
66110170Seric 	}
6624318Seric 
66359730Seric 	putline("", fp, m);
66459730Seric 
6654318Seric 	/*
6664318Seric 	**  Cleanup and exit
6674318Seric 	*/
6684318Seric 
669297Seric 	if (errno != 0)
6706978Seric 		syserr("errbody: I/O error");
671297Seric }
67258144Seric /*
67358144Seric **  PRUNEROUTE -- prune an RFC-822 source route
67458144Seric **
67558144Seric **	Trims down a source route to the last internet-registered hop.
67658144Seric **	This is encouraged by RFC 1123 section 5.3.3.
67758144Seric **
67858144Seric **	Parameters:
67958144Seric **		addr -- the address
68058144Seric **
68158144Seric **	Returns:
68258144Seric **		TRUE -- address was modified
68358144Seric **		FALSE -- address could not be pruned
68458144Seric **
68558144Seric **	Side Effects:
68658144Seric **		modifies addr in-place
68758144Seric */
68858144Seric 
68958144Seric pruneroute(addr)
69058144Seric 	char *addr;
69158144Seric {
69258144Seric #ifdef NAMED_BIND
69358144Seric 	char *start, *at, *comma;
69458144Seric 	char c;
69558144Seric 	int rcode;
69658144Seric 	char hostbuf[BUFSIZ];
69758144Seric 	char *mxhosts[MAXMXHOSTS + 1];
69858144Seric 
69958144Seric 	/* check to see if this is really a route-addr */
70058144Seric 	if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
70158144Seric 		return FALSE;
70258144Seric 	start = strchr(addr, ':');
70358144Seric 	at = strrchr(addr, '@');
70458144Seric 	if (start == NULL || at == NULL || at < start)
70558144Seric 		return FALSE;
70658144Seric 
70758144Seric 	/* slice off the angle brackets */
70858144Seric 	strcpy(hostbuf, at + 1);
70958144Seric 	hostbuf[strlen(hostbuf) - 1] = '\0';
71058144Seric 
71158144Seric 	while (start)
71258144Seric 	{
71359273Seric 		if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
71458144Seric 		{
71558144Seric 			strcpy(addr + 1, start + 1);
71658144Seric 			return TRUE;
71758144Seric 		}
71858144Seric 		c = *start;
71958144Seric 		*start = '\0';
72058144Seric 		comma = strrchr(addr, ',');
72158144Seric 		if (comma && comma[1] == '@')
72258144Seric 			strcpy(hostbuf, comma + 2);
72358144Seric 		else
72458144Seric 			comma = 0;
72558144Seric 		*start = c;
72658144Seric 		start = comma;
72758144Seric 	}
72858144Seric #endif
72958144Seric 	return FALSE;
73058144Seric }
731