xref: /freebsd/contrib/sendmail/src/savemail.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
1 /*
2  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * By using this file, you agree to the terms and conditions set
8  * forth in the LICENSE file which can be found at the top level of
9  * the sendmail distribution.
10  *
11  */
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)savemail.c	8.138 (Berkeley) 6/17/98";
15 #endif /* not lint */
16 
17 # include "sendmail.h"
18 
19 /*
20 **  SAVEMAIL -- Save mail on error
21 **
22 **	If mailing back errors, mail it back to the originator
23 **	together with an error message; otherwise, just put it in
24 **	dead.letter in the user's home directory (if he exists on
25 **	this machine).
26 **
27 **	Parameters:
28 **		e -- the envelope containing the message in error.
29 **		sendbody -- if TRUE, also send back the body of the
30 **			message; otherwise just send the header.
31 **
32 **	Returns:
33 **		none
34 **
35 **	Side Effects:
36 **		Saves the letter, by writing or mailing it back to the
37 **		sender, or by putting it in dead.letter in her home
38 **		directory.
39 */
40 
41 /* defines for state machine */
42 # define ESM_REPORT	0	/* report to sender's terminal */
43 # define ESM_MAIL	1	/* mail back to sender */
44 # define ESM_QUIET	2	/* messages have already been returned */
45 # define ESM_DEADLETTER	3	/* save in ~/dead.letter */
46 # define ESM_POSTMASTER	4	/* return to postmaster */
47 # define ESM_USRTMP	5	/* save in /usr/tmp/dead.letter */
48 # define ESM_PANIC	6	/* leave the locked queue/transcript files */
49 # define ESM_DONE	7	/* the message is successfully delivered */
50 
51 
52 void
53 savemail(e, sendbody)
54 	register ENVELOPE *e;
55 	bool sendbody;
56 {
57 	register struct passwd *pw;
58 	register FILE *fp;
59 	int state;
60 	auto ADDRESS *q = NULL;
61 	register char *p;
62 	MCI mcibuf;
63 	int flags;
64 	char buf[MAXLINE+1];
65 	extern char *ttypath __P((void));
66 	extern bool writable __P((char *, ADDRESS *, int));
67 
68 	if (tTd(6, 1))
69 	{
70 		printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n  e_from=",
71 			e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
72 			ExitStat);
73 		printaddr(&e->e_from, FALSE);
74 	}
75 
76 	if (e->e_id == NULL)
77 	{
78 		/* can't return a message with no id */
79 		return;
80 	}
81 
82 	/*
83 	**  In the unhappy event we don't know who to return the mail
84 	**  to, make someone up.
85 	*/
86 
87 	if (e->e_from.q_paddr == NULL)
88 	{
89 		e->e_sender = "Postmaster";
90 		if (parseaddr(e->e_sender, &e->e_from,
91 			      RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
92 		{
93 			syserr("553 Cannot parse Postmaster!");
94 			ExitStat = EX_SOFTWARE;
95 			finis();
96 		}
97 	}
98 	e->e_to = NULL;
99 
100 	/*
101 	**  Basic state machine.
102 	**
103 	**	This machine runs through the following states:
104 	**
105 	**	ESM_QUIET	Errors have already been printed iff the
106 	**			sender is local.
107 	**	ESM_REPORT	Report directly to the sender's terminal.
108 	**	ESM_MAIL	Mail response to the sender.
109 	**	ESM_DEADLETTER	Save response in ~/dead.letter.
110 	**	ESM_POSTMASTER	Mail response to the postmaster.
111 	**	ESM_PANIC	Save response anywhere possible.
112 	*/
113 
114 	/* determine starting state */
115 	switch (e->e_errormode)
116 	{
117 	  case EM_WRITE:
118 		state = ESM_REPORT;
119 		break;
120 
121 	  case EM_BERKNET:
122 	  case EM_MAIL:
123 		state = ESM_MAIL;
124 		break;
125 
126 	  case EM_PRINT:
127 	  case '\0':
128 		state = ESM_QUIET;
129 		break;
130 
131 	  case EM_QUIET:
132 		/* no need to return anything at all */
133 		return;
134 
135 	  default:
136 		syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
137 		state = ESM_MAIL;
138 		break;
139 	}
140 
141 	/* if this is already an error response, send to postmaster */
142 	if (bitset(EF_RESPONSE, e->e_flags))
143 	{
144 		if (e->e_parent != NULL &&
145 		    bitset(EF_RESPONSE, e->e_parent->e_flags))
146 		{
147 			/* got an error sending a response -- can it */
148 			return;
149 		}
150 		state = ESM_POSTMASTER;
151 	}
152 
153 	while (state != ESM_DONE)
154 	{
155 		if (tTd(6, 5))
156 			printf("  state %d\n", state);
157 
158 		switch (state)
159 		{
160 		  case ESM_QUIET:
161 			if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
162 				state = ESM_DEADLETTER;
163 			else
164 				state = ESM_MAIL;
165 			break;
166 
167 		  case ESM_REPORT:
168 
169 			/*
170 			**  If the user is still logged in on the same terminal,
171 			**  then write the error messages back to hir (sic).
172 			*/
173 
174 			p = ttypath();
175 			if (p == NULL || freopen(p, "w", stdout) == NULL)
176 			{
177 				state = ESM_MAIL;
178 				break;
179 			}
180 
181 			expand("\201n", buf, sizeof buf, e);
182 			printf("\r\nMessage from %s...\r\n", buf);
183 			printf("Errors occurred while sending mail.\r\n");
184 			if (e->e_xfp != NULL)
185 			{
186 				(void) fflush(e->e_xfp);
187 				fp = fopen(queuename(e, 'x'), "r");
188 			}
189 			else
190 				fp = NULL;
191 			if (fp == NULL)
192 			{
193 				syserr("Cannot open %s", queuename(e, 'x'));
194 				printf("Transcript of session is unavailable.\r\n");
195 			}
196 			else
197 			{
198 				printf("Transcript follows:\r\n");
199 				while (fgets(buf, sizeof buf, fp) != NULL &&
200 				       !ferror(stdout))
201 					fputs(buf, stdout);
202 				(void) xfclose(fp, "savemail transcript", e->e_id);
203 			}
204 			printf("Original message will be saved in dead.letter.\r\n");
205 			state = ESM_DEADLETTER;
206 			break;
207 
208 		  case ESM_MAIL:
209 			/*
210 			**  If mailing back, do it.
211 			**	Throw away all further output.  Don't alias,
212 			**	since this could cause loops, e.g., if joe
213 			**	mails to joe@x, and for some reason the network
214 			**	for @x is down, then the response gets sent to
215 			**	joe@x, which gives a response, etc.  Also force
216 			**	the mail to be delivered even if a version of
217 			**	it has already been sent to the sender.
218 			**
219 			**  If this is a configuration or local software
220 			**	error, send to the local postmaster as well,
221 			**	since the originator can't do anything
222 			**	about it anyway.  Note that this is a full
223 			**	copy of the message (intentionally) so that
224 			**	the Postmaster can forward things along.
225 			*/
226 
227 			if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
228 			{
229 				(void) sendtolist("postmaster",
230 					  NULLADDR, &e->e_errorqueue, 0, e);
231 			}
232 			if (!emptyaddr(&e->e_from))
233 			{
234 				char from[TOBUFSIZE];
235 				extern bool pruneroute __P((char *));
236 
237 				if (strlen(e->e_from.q_paddr) + 1 > sizeof from)
238 				{
239 					state = ESM_POSTMASTER;
240 					break;
241 				}
242 				strcpy(from, e->e_from.q_paddr);
243 
244 				if (!DontPruneRoutes && pruneroute(from))
245 				{
246 					ADDRESS *a;
247 
248 					for (a = e->e_errorqueue; a != NULL;
249 					     a = a->q_next)
250 					{
251 						if (sameaddr(a, &e->e_from))
252 							a->q_flags |= QDONTSEND;
253 					}
254 				}
255 				(void) sendtolist(from, NULLADDR,
256 						  &e->e_errorqueue, 0, e);
257 			}
258 
259 			/*
260 			**  Deliver a non-delivery report to the
261 			**  Postmaster-designate (not necessarily
262 			**  Postmaster).  This does not include the
263 			**  body of the message, for privacy reasons.
264 			**  You really shouldn't need this.
265 			*/
266 
267 			e->e_flags |= EF_PM_NOTIFY;
268 
269 			/* check to see if there are any good addresses */
270 			for (q = e->e_errorqueue; q != NULL; q = q->q_next)
271 				if (!bitset(QBADADDR|QDONTSEND, q->q_flags))
272 					break;
273 			if (q == NULL)
274 			{
275 				/* this is an error-error */
276 				state = ESM_POSTMASTER;
277 				break;
278 			}
279 			if (returntosender(e->e_message, e->e_errorqueue,
280 					   sendbody ? RTSF_SEND_BODY
281 						    : RTSF_NO_BODY,
282 					   e) == 0)
283 			{
284 				state = ESM_DONE;
285 				break;
286 			}
287 
288 			/* didn't work -- return to postmaster */
289 			state = ESM_POSTMASTER;
290 			break;
291 
292 		  case ESM_POSTMASTER:
293 			/*
294 			**  Similar to previous case, but to system postmaster.
295 			*/
296 
297 			q = NULL;
298 			if (sendtolist(DoubleBounceAddr,
299 				NULLADDR, &q, 0, e) <= 0)
300 			{
301 				syserr("553 cannot parse %s!", DoubleBounceAddr);
302 				ExitStat = EX_SOFTWARE;
303 				state = ESM_USRTMP;
304 				break;
305 			}
306 			flags = RTSF_PM_BOUNCE;
307 			if (sendbody)
308 				flags |= RTSF_SEND_BODY;
309 			if (returntosender(e->e_message, q, flags, e) == 0)
310 			{
311 				state = ESM_DONE;
312 				break;
313 			}
314 
315 			/* didn't work -- last resort */
316 			state = ESM_USRTMP;
317 			break;
318 
319 		  case ESM_DEADLETTER:
320 			/*
321 			**  Save the message in dead.letter.
322 			**	If we weren't mailing back, and the user is
323 			**	local, we should save the message in
324 			**	~/dead.letter so that the poor person doesn't
325 			**	have to type it over again -- and we all know
326 			**	what poor typists UNIX users are.
327 			*/
328 
329 			p = NULL;
330 			if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
331 			{
332 				if (e->e_from.q_home != NULL)
333 					p = e->e_from.q_home;
334 				else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
335 					p = pw->pw_dir;
336 			}
337 			if (p == NULL || e->e_dfp == NULL)
338 			{
339 				/* no local directory or no data file */
340 				state = ESM_MAIL;
341 				break;
342 			}
343 
344 			/* we have a home directory; write dead.letter */
345 			define('z', p, e);
346 			expand("\201z/dead.letter", buf, sizeof buf, e);
347 			flags = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
348 			if (RealUid == 0)
349 				flags |= SFF_ROOTOK;
350 			e->e_to = buf;
351 			if (mailfile(buf, FileMailer, NULL, flags, e) == EX_OK)
352 			{
353 				int oldverb = Verbose;
354 
355 				Verbose = 1;
356 				message("Saved message in %s", buf);
357 				Verbose = oldverb;
358 				state = ESM_DONE;
359 				break;
360 			}
361 			state = ESM_MAIL;
362 			break;
363 
364 		  case ESM_USRTMP:
365 			/*
366 			**  Log the mail in /usr/tmp/dead.letter.
367 			*/
368 
369 			if (e->e_class < 0)
370 			{
371 				state = ESM_DONE;
372 				break;
373 			}
374 
375 			if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
376 			    DeadLetterDrop == NULL || DeadLetterDrop[0] == '\0')
377 			{
378 				state = ESM_PANIC;
379 				break;
380 			}
381 
382 			flags = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
383 			if (!writable(DeadLetterDrop, NULL, flags) ||
384 			    (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
385 					    FileMode, flags)) == NULL)
386 			{
387 				state = ESM_PANIC;
388 				break;
389 			}
390 
391 			bzero(&mcibuf, sizeof mcibuf);
392 			mcibuf.mci_out = fp;
393 			mcibuf.mci_mailer = FileMailer;
394 			if (bitnset(M_7BITS, FileMailer->m_flags))
395 				mcibuf.mci_flags |= MCIF_7BIT;
396 			mcibuf.mci_contentlen = 0;
397 
398 			putfromline(&mcibuf, e);
399 			(*e->e_puthdr)(&mcibuf, e->e_header, e);
400 			(*e->e_putbody)(&mcibuf, e, NULL);
401 			putline("\n", &mcibuf);
402 			(void) fflush(fp);
403 			if (ferror(fp))
404 				state = ESM_PANIC;
405 			else
406 			{
407 				int oldverb = Verbose;
408 
409 				Verbose = 1;
410 				message("Saved message in %s", DeadLetterDrop);
411 				Verbose = oldverb;
412 				if (LogLevel > 3)
413 					sm_syslog(LOG_NOTICE, e->e_id,
414 						"Saved message in %s",
415 						DeadLetterDrop);
416 				state = ESM_DONE;
417 			}
418 			(void) xfclose(fp, "savemail", DeadLetterDrop);
419 			break;
420 
421 		  default:
422 			syserr("554 savemail: unknown state %d", state);
423 
424 			/* fall through ... */
425 
426 		  case ESM_PANIC:
427 			/* leave the locked queue & transcript files around */
428 			loseqfile(e, "savemail panic");
429 			syserr("!554 savemail: cannot save rejected email anywhere");
430 		}
431 	}
432 }
433 /*
434 **  RETURNTOSENDER -- return a message to the sender with an error.
435 **
436 **	Parameters:
437 **		msg -- the explanatory message.
438 **		returnq -- the queue of people to send the message to.
439 **		flags -- flags tweaking the operation:
440 **			RTSF_SENDBODY -- include body of message (otherwise
441 **				just send the header).
442 **			RTSF_PMBOUNCE -- this is a postmaster bounce.
443 **		e -- the current envelope.
444 **
445 **	Returns:
446 **		zero -- if everything went ok.
447 **		else -- some error.
448 **
449 **	Side Effects:
450 **		Returns the current message to the sender via
451 **		mail.
452 */
453 
454 #define MAXRETURNS	6	/* max depth of returning messages */
455 #define ERRORFUDGE	100	/* nominal size of error message text */
456 
457 int
458 returntosender(msg, returnq, flags, e)
459 	char *msg;
460 	ADDRESS *returnq;
461 	int flags;
462 	register ENVELOPE *e;
463 {
464 	register ENVELOPE *ee;
465 	ENVELOPE *oldcur = CurEnv;
466 	ENVELOPE errenvelope;
467 	static int returndepth = 0;
468 	register ADDRESS *q;
469 	char *p;
470 	char buf[MAXNAME + 1];
471 	extern void errbody __P((MCI *, ENVELOPE *, char *));
472 
473 	if (returnq == NULL)
474 		return (-1);
475 
476 	if (msg == NULL)
477 		msg = "Unable to deliver mail";
478 
479 	if (tTd(6, 1))
480 	{
481 		printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=",
482 		       msg, returndepth, (u_long) e);
483 		printaddr(returnq, TRUE);
484 		if (tTd(6, 20))
485 		{
486 			printf("Sendq=");
487 			printaddr(e->e_sendqueue, TRUE);
488 		}
489 	}
490 
491 	if (++returndepth >= MAXRETURNS)
492 	{
493 		if (returndepth != MAXRETURNS)
494 			syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
495 		/* don't "unrecurse" and fake a clean exit */
496 		/* returndepth--; */
497 		return (0);
498 	}
499 
500 	define('g', e->e_from.q_paddr, e);
501 	define('u', NULL, e);
502 
503 	/* initialize error envelope */
504 	ee = newenvelope(&errenvelope, e);
505 	define('a', "\201b", ee);
506 	define('r', "internal", ee);
507 	define('s', "localhost", ee);
508 	define('_', "localhost", ee);
509 	ee->e_puthdr = putheader;
510 	ee->e_putbody = errbody;
511 	ee->e_flags |= EF_RESPONSE|EF_METOO;
512 	if (!bitset(EF_OLDSTYLE, e->e_flags))
513 		ee->e_flags &= ~EF_OLDSTYLE;
514 	ee->e_sendqueue = returnq;
515 	ee->e_msgsize = ERRORFUDGE;
516 	if (bitset(RTSF_SEND_BODY, flags))
517 		ee->e_msgsize += e->e_msgsize;
518 	else
519 		ee->e_flags |= EF_NO_BODY_RETN;
520 	initsys(ee);
521 	for (q = returnq; q != NULL; q = q->q_next)
522 	{
523 		if (bitset(QBADADDR, q->q_flags))
524 			continue;
525 
526 		q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
527 		q->q_flags |= QPINGONFAILURE;
528 
529 		if (!bitset(QDONTSEND, q->q_flags))
530 			ee->e_nrcpts++;
531 
532 		if (q->q_alias == NULL)
533 			addheader("To", q->q_paddr, &ee->e_header);
534 	}
535 
536 	if (LogLevel > 5)
537 	{
538 		if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags))
539 			p = "return to sender";
540 		else if (bitset(RTSF_PM_BOUNCE, flags))
541 			p = "postmaster notify";
542 		else
543 			p = "DSN";
544 		sm_syslog(LOG_INFO, e->e_id,
545 			"%s: %s: %s",
546 			ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
547 	}
548 
549 	if (SendMIMEErrors)
550 	{
551 		addheader("MIME-Version", "1.0", &ee->e_header);
552 
553 		(void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
554 			ee->e_id, curtime(), MyHostName);
555 		ee->e_msgboundary = newstr(buf);
556 		(void) snprintf(buf, sizeof buf,
557 #if DSN
558 			"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
559 #else
560 			"multipart/mixed; boundary=\"%s\"",
561 #endif
562 			ee->e_msgboundary);
563 		addheader("Content-Type", buf, &ee->e_header);
564 
565 		p = hvalue("Content-Transfer-Encoding", e->e_header);
566 		if (p != NULL && strcasecmp(p, "binary") != 0)
567 			p = NULL;
568 		if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
569 			p = "8bit";
570 		if (p != NULL)
571 			addheader("Content-Transfer-Encoding", p, &ee->e_header);
572 	}
573 	if (strncmp(msg, "Warning:", 8) == 0)
574 	{
575 		addheader("Subject", msg, &ee->e_header);
576 		p = "warning-timeout";
577 	}
578 	else if (strncmp(msg, "Postmaster warning:", 19) == 0)
579 	{
580 		addheader("Subject", msg, &ee->e_header);
581 		p = "postmaster-warning";
582 	}
583 	else if (strcmp(msg, "Return receipt") == 0)
584 	{
585 		addheader("Subject", msg, &ee->e_header);
586 		p = "return-receipt";
587 	}
588 	else if (bitset(RTSF_PM_BOUNCE, flags))
589 	{
590 		snprintf(buf, sizeof buf, "Postmaster notify: %.*s",
591 			sizeof buf - 20, msg);
592 		addheader("Subject", buf, &ee->e_header);
593 		p = "postmaster-notification";
594 	}
595 	else
596 	{
597 		snprintf(buf, sizeof buf, "Returned mail: %.*s",
598 			sizeof buf - 20, msg);
599 		addheader("Subject", buf, &ee->e_header);
600 		p = "failure";
601 	}
602 	(void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
603 	addheader("Auto-Submitted", buf, &ee->e_header);
604 
605 	/* fake up an address header for the from person */
606 	expand("\201n", buf, sizeof buf, e);
607 	if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
608 	{
609 		syserr("553 Can't parse myself!");
610 		ExitStat = EX_SOFTWARE;
611 		returndepth--;
612 		return (-1);
613 	}
614 	ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
615 	ee->e_from.q_flags |= QPINGONFAILURE;
616 	ee->e_sender = ee->e_from.q_paddr;
617 
618 	/* push state into submessage */
619 	CurEnv = ee;
620 	define('f', "\201n", ee);
621 	define('x', "Mail Delivery Subsystem", ee);
622 	eatheader(ee, TRUE);
623 
624 	/* mark statistics */
625 	markstats(ee, NULLADDR, FALSE);
626 
627 	/* actually deliver the error message */
628 	sendall(ee, SM_DELIVER);
629 
630 	/* restore state */
631 	dropenvelope(ee, TRUE);
632 	CurEnv = oldcur;
633 	returndepth--;
634 
635 	/* check for delivery errors */
636 	if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags))
637 		return 0;
638 	for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
639 	{
640 		if (bitset(QQUEUEUP|QSENT, q->q_flags))
641 			return 0;
642 	}
643 	return -1;
644 }
645 /*
646 **  ERRBODY -- output the body of an error message.
647 **
648 **	Typically this is a copy of the transcript plus a copy of the
649 **	original offending message.
650 **
651 **	Parameters:
652 **		mci -- the mailer connection information.
653 **		e -- the envelope we are working in.
654 **		separator -- any possible MIME separator.
655 **
656 **	Returns:
657 **		none
658 **
659 **	Side Effects:
660 **		Outputs the body of an error message.
661 */
662 
663 void
664 errbody(mci, e, separator)
665 	register MCI *mci;
666 	register ENVELOPE *e;
667 	char *separator;
668 {
669 	register FILE *xfile;
670 	char *p;
671 	register ADDRESS *q = NULL;
672 	bool printheader;
673 	bool sendbody;
674 	bool pm_notify;
675 	char buf[MAXLINE];
676 
677 	if (bitset(MCIF_INHEADER, mci->mci_flags))
678 	{
679 		putline("", mci);
680 		mci->mci_flags &= ~MCIF_INHEADER;
681 	}
682 	if (e->e_parent == NULL)
683 	{
684 		syserr("errbody: null parent");
685 		putline("   ----- Original message lost -----\n", mci);
686 		return;
687 	}
688 
689 	/*
690 	**  Output MIME header.
691 	*/
692 
693 	if (e->e_msgboundary != NULL)
694 	{
695 		putline("This is a MIME-encapsulated message", mci);
696 		putline("", mci);
697 		(void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
698 		putline(buf, mci);
699 		putline("", mci);
700 	}
701 
702 	/*
703 	**  Output introductory information.
704 	*/
705 
706 	pm_notify = FALSE;
707 	p = hvalue("subject", e->e_header);
708 	if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
709 		pm_notify = TRUE;
710 	else
711 	{
712 		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
713 			if (bitset(QBADADDR, q->q_flags))
714 				break;
715 	}
716 	if (!pm_notify && q == NULL &&
717 	    !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
718 	{
719 		putline("    **********************************************",
720 			mci);
721 		putline("    **      THIS IS A WARNING MESSAGE ONLY      **",
722 			mci);
723 		putline("    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **",
724 			mci);
725 		putline("    **********************************************",
726 			mci);
727 		putline("", mci);
728 	}
729 	snprintf(buf, sizeof buf, "The original message was received at %s",
730 		arpadate(ctime(&e->e_parent->e_ctime)));
731 	putline(buf, mci);
732 	expand("from \201_", buf, sizeof buf, e->e_parent);
733 	putline(buf, mci);
734 	putline("", mci);
735 
736 	/*
737 	**  Output error message header (if specified and available).
738 	*/
739 
740 	if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
741 	{
742 		if (*ErrMsgFile == '/')
743 		{
744 			int sff = SFF_ROOTOK|SFF_REGONLY;
745 
746 			if (DontLockReadFiles)
747 				sff |= SFF_NOLOCK;
748 			if (!bitset(DBS_ERRORHEADERINUNSAFEDIRPATH, DontBlameSendmail))
749 				sff |= SFF_SAFEDIRPATH;
750 			xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
751 			if (xfile != NULL)
752 			{
753 				while (fgets(buf, sizeof buf, xfile) != NULL)
754 				{
755 					extern void translate_dollars __P((char *));
756 
757 					translate_dollars(buf);
758 					expand(buf, buf, sizeof buf, e);
759 					putline(buf, mci);
760 				}
761 				(void) fclose(xfile);
762 				putline("\n", mci);
763 			}
764 		}
765 		else
766 		{
767 			expand(ErrMsgFile, buf, sizeof buf, e);
768 			putline(buf, mci);
769 			putline("", mci);
770 		}
771 	}
772 
773 	/*
774 	**  Output message introduction
775 	*/
776 
777 	printheader = TRUE;
778 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
779 	{
780 		if (!bitset(QBADADDR, q->q_flags) ||
781 		    !bitset(QPINGONFAILURE, q->q_flags))
782 			continue;
783 
784 		if (printheader)
785 		{
786 			putline("   ----- The following addresses had permanent fatal errors -----",
787 				mci);
788 			printheader = FALSE;
789 		}
790 
791 		snprintf(buf, sizeof buf, "%s",
792 			 shortenstring(q->q_paddr, MAXSHORTSTR));
793 		putline(buf, mci);
794 		if (q->q_alias != NULL)
795 		{
796 			snprintf(buf, sizeof buf, "    (expanded from: %s)",
797 				shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
798 			putline(buf, mci);
799 		}
800 	}
801 	if (!printheader)
802 		putline("", mci);
803 
804 	printheader = TRUE;
805 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
806 	{
807 		if (bitset(QBADADDR, q->q_flags) ||
808 		    !bitset(QPRIMARY, q->q_flags) ||
809 		    !bitset(QDELAYED, q->q_flags))
810 			continue;
811 
812 		if (printheader)
813 		{
814 			putline("   ----- The following addresses had transient non-fatal errors -----",
815 				mci);
816 			printheader = FALSE;
817 		}
818 
819 		snprintf(buf, sizeof buf, "%s",
820 			 shortenstring(q->q_paddr, MAXSHORTSTR));
821 		putline(buf, mci);
822 		if (q->q_alias != NULL)
823 		{
824 			snprintf(buf, sizeof buf, "    (expanded from: %s)",
825 				shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
826 			putline(buf, mci);
827 		}
828 	}
829 	if (!printheader)
830 		putline("", mci);
831 
832 	printheader = TRUE;
833 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
834 	{
835 		if (bitset(QBADADDR, q->q_flags) ||
836 		    !bitset(QPRIMARY, q->q_flags) ||
837 		    bitset(QDELAYED, q->q_flags))
838 			continue;
839 		else if (!bitset(QPINGONSUCCESS, q->q_flags))
840 			continue;
841 		else if (bitset(QRELAYED, q->q_flags))
842 			p = "relayed to non-DSN-aware mailer";
843 		else if (bitset(QDELIVERED, q->q_flags))
844 		{
845 			if (bitset(QEXPANDED, q->q_flags))
846 				p = "successfully delivered to mailing list";
847 			else
848 				p = "successfully delivered to mailbox";
849 		}
850 		else if (bitset(QEXPANDED, q->q_flags))
851 			p = "expanded by alias";
852 		else
853 			continue;
854 
855 		if (printheader)
856 		{
857 			putline("   ----- The following addresses had successful delivery notifications -----",
858 				mci);
859 			printheader = FALSE;
860 		}
861 
862 		snprintf(buf, sizeof buf, "%s  (%s)",
863 			shortenstring(q->q_paddr, MAXSHORTSTR), p);
864 		putline(buf, mci);
865 		if (q->q_alias != NULL)
866 		{
867 			snprintf(buf, sizeof buf, "    (expanded from: %s)",
868 				shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
869 			putline(buf, mci);
870 		}
871 	}
872 	if (!printheader)
873 		putline("", mci);
874 
875 	/*
876 	**  Output transcript of errors
877 	*/
878 
879 	(void) fflush(stdout);
880 	p = queuename(e->e_parent, 'x');
881 	if ((xfile = fopen(p, "r")) == NULL)
882 	{
883 		syserr("Cannot open %s", p);
884 		putline("   ----- Transcript of session is unavailable -----\n", mci);
885 	}
886 	else
887 	{
888 		printheader = TRUE;
889 		if (e->e_xfp != NULL)
890 			(void) fflush(e->e_xfp);
891 		while (fgets(buf, sizeof buf, xfile) != NULL)
892 		{
893 			if (printheader)
894 				putline("   ----- Transcript of session follows -----\n", mci);
895 			printheader = FALSE;
896 			putline(buf, mci);
897 		}
898 		(void) xfclose(xfile, "errbody xscript", p);
899 	}
900 	errno = 0;
901 
902 #if DSN
903 	/*
904 	**  Output machine-readable version.
905 	*/
906 
907 	if (e->e_msgboundary != NULL)
908 	{
909 		putline("", mci);
910 		(void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
911 		putline(buf, mci);
912 		putline("Content-Type: message/delivery-status", mci);
913 		putline("", mci);
914 
915 		/*
916 		**  Output per-message information.
917 		*/
918 
919 		/* original envelope id from MAIL FROM: line */
920 		if (e->e_parent->e_envid != NULL)
921 		{
922 			(void) snprintf(buf, sizeof buf, "Original-Envelope-Id: %.800s",
923 				xuntextify(e->e_parent->e_envid));
924 			putline(buf, mci);
925 		}
926 
927 		/* Reporting-MTA: is us (required) */
928 		(void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName);
929 		putline(buf, mci);
930 
931 		/* DSN-Gateway: not relevant since we are not translating */
932 
933 		/* Received-From-MTA: shows where we got this message from */
934 		if (RealHostName != NULL)
935 		{
936 			/* XXX use $s for type? */
937 			if (e->e_parent->e_from.q_mailer == NULL ||
938 			    (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
939 				p = "dns";
940 			(void) snprintf(buf, sizeof buf, "Received-From-MTA: %s; %.800s",
941 				p, RealHostName);
942 			putline(buf, mci);
943 		}
944 
945 		/* Arrival-Date: -- when it arrived here */
946 		(void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
947 			arpadate(ctime(&e->e_parent->e_ctime)));
948 		putline(buf, mci);
949 
950 		/*
951 		**  Output per-address information.
952 		*/
953 
954 		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
955 		{
956 			register ADDRESS *r;
957 			char *action;
958 
959 			if (bitset(QBADADDR, q->q_flags))
960 				action = "failed";
961 			else if (!bitset(QPRIMARY, q->q_flags))
962 				continue;
963 			else if (bitset(QDELIVERED, q->q_flags))
964 			{
965 				if (bitset(QEXPANDED, q->q_flags))
966 					action = "delivered (to mailing list)";
967 				else
968 					action = "delivered (to mailbox)";
969 			}
970 			else if (bitset(QRELAYED, q->q_flags))
971 				action = "relayed (to non-DSN-aware mailer)";
972 			else if (bitset(QEXPANDED, q->q_flags))
973 				action = "expanded (to multi-recipient alias)";
974 			else if (bitset(QDELAYED, q->q_flags))
975 				action = "delayed";
976 			else
977 				continue;
978 
979 			putline("", mci);
980 
981 			/* Original-Recipient: -- passed from on high */
982 			if (q->q_orcpt != NULL)
983 			{
984 				(void) snprintf(buf, sizeof buf, "Original-Recipient: %.800s",
985 					q->q_orcpt);
986 				putline(buf, mci);
987 			}
988 
989 			/* Final-Recipient: -- the name from the RCPT command */
990 			p = e->e_parent->e_from.q_mailer->m_addrtype;
991 			if (p == NULL)
992 				p = "rfc822";
993 			for (r = q; r->q_alias != NULL; r = r->q_alias)
994 				continue;
995 			if (strchr(r->q_user, '@') != NULL)
996 			{
997 				(void) snprintf(buf, sizeof buf,
998 					"Final-Recipient: %s; %.800s",
999 					p, r->q_user);
1000 			}
1001 			else if (strchr(r->q_paddr, '@') != NULL)
1002 			{
1003 				(void) snprintf(buf, sizeof buf,
1004 					"Final-Recipient: %s; %.800s",
1005 					p, r->q_paddr);
1006 			}
1007 			else
1008 			{
1009 				(void) snprintf(buf, sizeof buf,
1010 					"Final-Recipient: %s; %.700s@%.100s",
1011 					p, r->q_user, MyHostName);
1012 			}
1013 			putline(buf, mci);
1014 
1015 			/* X-Actual-Recipient: -- the real problem address */
1016 			if (r != q && q->q_user[0] != '\0')
1017 			{
1018 				if (strchr(q->q_user, '@') == NULL)
1019 				{
1020 					(void) snprintf(buf, sizeof buf,
1021 						"X-Actual-Recipient: %s; %.700s@%.100s",
1022 						p, q->q_user, MyHostName);
1023 				}
1024 				else
1025 				{
1026 					(void) snprintf(buf, sizeof buf,
1027 						"X-Actual-Recipient: %s; %.800s",
1028 						p, q->q_user);
1029 				}
1030 				putline(buf, mci);
1031 			}
1032 
1033 			/* Action: -- what happened? */
1034 			snprintf(buf, sizeof buf, "Action: %s", action);
1035 			putline(buf, mci);
1036 
1037 			/* Status: -- what _really_ happened? */
1038 			if (q->q_status != NULL)
1039 				p = q->q_status;
1040 			else if (bitset(QBADADDR, q->q_flags))
1041 				p = "5.0.0";
1042 			else if (bitset(QQUEUEUP, q->q_flags))
1043 				p = "4.0.0";
1044 			else
1045 				p = "2.0.0";
1046 			snprintf(buf, sizeof buf, "Status: %s", p);
1047 			putline(buf, mci);
1048 
1049 			/* Remote-MTA: -- who was I talking to? */
1050 			if (q->q_statmta != NULL)
1051 			{
1052 				if (q->q_mailer == NULL ||
1053 				    (p = q->q_mailer->m_mtatype) == NULL)
1054 					p = "dns";
1055 				(void) snprintf(buf, sizeof buf,
1056 					"Remote-MTA: %s; %.800s",
1057 					p, q->q_statmta);
1058 				p = &buf[strlen(buf) - 1];
1059 				if (*p == '.')
1060 					*p = '\0';
1061 				putline(buf, mci);
1062 			}
1063 
1064 			/* Diagnostic-Code: -- actual result from other end */
1065 			if (q->q_rstatus != NULL)
1066 			{
1067 				p = q->q_mailer->m_diagtype;
1068 				if (p == NULL)
1069 					p = "smtp";
1070 				(void) snprintf(buf, sizeof buf,
1071 					"Diagnostic-Code: %s; %.800s",
1072 					p, q->q_rstatus);
1073 				putline(buf, mci);
1074 			}
1075 
1076 			/* Last-Attempt-Date: -- fine granularity */
1077 			if (q->q_statdate == (time_t) 0L)
1078 				q->q_statdate = curtime();
1079 			(void) snprintf(buf, sizeof buf,
1080 				"Last-Attempt-Date: %s",
1081 				arpadate(ctime(&q->q_statdate)));
1082 			putline(buf, mci);
1083 
1084 			/* Will-Retry-Until: -- for delayed messages only */
1085 			if (bitset(QQUEUEUP, q->q_flags) &&
1086 			    !bitset(QBADADDR, q->q_flags))
1087 			{
1088 				time_t xdate;
1089 
1090 				xdate = e->e_parent->e_ctime +
1091 					TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1092 				snprintf(buf, sizeof buf,
1093 					"Will-Retry-Until: %s",
1094 					arpadate(ctime(&xdate)));
1095 				putline(buf, mci);
1096 			}
1097 		}
1098 	}
1099 #endif
1100 
1101 	/*
1102 	**  Output text of original message
1103 	*/
1104 
1105 	putline("", mci);
1106 	if (bitset(EF_HAS_DF, e->e_parent->e_flags))
1107 	{
1108 		sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
1109 			   !bitset(EF_NO_BODY_RETN, e->e_flags);
1110 
1111 		if (e->e_msgboundary == NULL)
1112 		{
1113 			if (sendbody)
1114 				putline("   ----- Original message follows -----\n", mci);
1115 			else
1116 				putline("   ----- Message header follows -----\n", mci);
1117 			(void) fflush(mci->mci_out);
1118 		}
1119 		else
1120 		{
1121 			(void) snprintf(buf, sizeof buf, "--%s",
1122 				e->e_msgboundary);
1123 
1124 			putline(buf, mci);
1125 			(void) snprintf(buf, sizeof buf, "Content-Type: %s",
1126 				sendbody ? "message/rfc822"
1127 					 : "text/rfc822-headers");
1128 			putline(buf, mci);
1129 
1130 			p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header);
1131 			if (p != NULL && strcasecmp(p, "binary") != 0)
1132 				p = NULL;
1133 			if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags))
1134 				p = "8bit";
1135 			if (p != NULL)
1136 			{
1137 				(void) snprintf(buf, sizeof buf, "Content-Transfer-Encoding: %s",
1138 					p);
1139 				putline(buf, mci);
1140 			}
1141 		}
1142 		putline("", mci);
1143 		putheader(mci, e->e_parent->e_header, e->e_parent);
1144 		if (sendbody)
1145 			putbody(mci, e->e_parent, e->e_msgboundary);
1146 		else if (e->e_msgboundary == NULL)
1147 		{
1148 			putline("", mci);
1149 			putline("   ----- Message body suppressed -----", mci);
1150 		}
1151 	}
1152 	else if (e->e_msgboundary == NULL)
1153 	{
1154 		putline("  ----- No message was collected -----\n", mci);
1155 	}
1156 
1157 	if (e->e_msgboundary != NULL)
1158 	{
1159 		putline("", mci);
1160 		(void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
1161 		putline(buf, mci);
1162 	}
1163 	putline("", mci);
1164 
1165 	/*
1166 	**  Cleanup and exit
1167 	*/
1168 
1169 	if (errno != 0)
1170 		syserr("errbody: I/O error");
1171 }
1172 /*
1173 **  SMTPTODSN -- convert SMTP to DSN status code
1174 **
1175 **	Parameters:
1176 **		smtpstat -- the smtp status code (e.g., 550).
1177 **
1178 **	Returns:
1179 **		The DSN version of the status code.
1180 */
1181 
1182 char *
1183 smtptodsn(smtpstat)
1184 	int smtpstat;
1185 {
1186 	if (smtpstat < 0)
1187 		return "4.4.2";
1188 
1189 	switch (smtpstat)
1190 	{
1191 	  case 450:	/* Req mail action not taken: mailbox unavailable */
1192 		return "4.2.0";
1193 
1194 	  case 451:	/* Req action aborted: local error in processing */
1195 		return "4.3.0";
1196 
1197 	  case 452:	/* Req action not taken: insufficient sys storage */
1198 		return "4.3.1";
1199 
1200 	  case 500:	/* Syntax error, command unrecognized */
1201 		return "5.5.2";
1202 
1203 	  case 501:	/* Syntax error in parameters or arguments */
1204 		return "5.5.4";
1205 
1206 	  case 502:	/* Command not implemented */
1207 		return "5.5.1";
1208 
1209 	  case 503:	/* Bad sequence of commands */
1210 		return "5.5.1";
1211 
1212 	  case 504:	/* Command parameter not implemented */
1213 		return "5.5.4";
1214 
1215 	  case 550:	/* Req mail action not taken: mailbox unavailable */
1216 		return "5.2.0";
1217 
1218 	  case 551:	/* User not local; please try <...> */
1219 		return "5.1.6";
1220 
1221 	  case 552:	/* Req mail action aborted: exceeded storage alloc */
1222 		return "5.2.2";
1223 
1224 	  case 553:	/* Req action not taken: mailbox name not allowed */
1225 		return "5.1.0";
1226 
1227 	  case 554:	/* Transaction failed */
1228 		return "5.0.0";
1229 	}
1230 
1231 	if ((smtpstat / 100) == 2)
1232 		return "2.0.0";
1233 	if ((smtpstat / 100) == 4)
1234 		return "4.0.0";
1235 	return "5.0.0";
1236 }
1237 /*
1238 **  XTEXTIFY -- take regular text and turn it into DSN-style xtext
1239 **
1240 **	Parameters:
1241 **		t -- the text to convert.
1242 **		taboo -- additional characters that must be encoded.
1243 **
1244 **	Returns:
1245 **		The xtext-ified version of the same string.
1246 */
1247 
1248 char *
1249 xtextify(t, taboo)
1250 	register char *t;
1251 	char *taboo;
1252 {
1253 	register char *p;
1254 	int l;
1255 	int nbogus;
1256 	static char *bp = NULL;
1257 	static int bplen = 0;
1258 
1259 	if (taboo == NULL)
1260 		taboo = "";
1261 
1262 	/* figure out how long this xtext will have to be */
1263 	nbogus = l = 0;
1264 	for (p = t; *p != '\0'; p++)
1265 	{
1266 		register int c = (*p & 0xff);
1267 
1268 		/* ASCII dependence here -- this is the way the spec words it */
1269 		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1270 		    strchr(taboo, c) != NULL)
1271 			nbogus++;
1272 		l++;
1273 	}
1274 	if (nbogus == 0)
1275 		return t;
1276 	l += nbogus * 2 + 1;
1277 
1278 	/* now allocate space if necessary for the new string */
1279 	if (l > bplen)
1280 	{
1281 		if (bp != NULL)
1282 			free(bp);
1283 		bp = xalloc(l);
1284 		bplen = l;
1285 	}
1286 
1287 	/* ok, copy the text with byte expansion */
1288 	for (p = bp; *t != '\0'; )
1289 	{
1290 		register int c = (*t++ & 0xff);
1291 
1292 		/* ASCII dependence here -- this is the way the spec words it */
1293 		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1294 		    strchr(taboo, c) != NULL)
1295 		{
1296 			*p++ = '+';
1297 			*p++ = "0123456789abcdef"[c >> 4];
1298 			*p++ = "0123456789abcdef"[c & 0xf];
1299 		}
1300 		else
1301 			*p++ = c;
1302 	}
1303 	*p = '\0';
1304 	return bp;
1305 }
1306 /*
1307 **  XUNTEXTIFY -- take xtext and turn it into plain text
1308 **
1309 **	Parameters:
1310 **		t -- the xtextified text.
1311 **
1312 **	Returns:
1313 **		The decoded text.  No attempt is made to deal with
1314 **		null strings in the resulting text.
1315 */
1316 
1317 char *
1318 xuntextify(t)
1319 	register char *t;
1320 {
1321 	register char *p;
1322 	int l;
1323 	static char *bp = NULL;
1324 	static int bplen = 0;
1325 
1326 	/* heuristic -- if no plus sign, just return the input */
1327 	if (strchr(t, '+') == NULL)
1328 		return t;
1329 
1330 	/* xtext is always longer than decoded text */
1331 	l = strlen(t);
1332 	if (l > bplen)
1333 	{
1334 		if (bp != NULL)
1335 			free(bp);
1336 		bp = xalloc(l);
1337 		bplen = l;
1338 	}
1339 
1340 	/* ok, copy the text with byte compression */
1341 	for (p = bp; *t != '\0'; t++)
1342 	{
1343 		register int c = *t & 0xff;
1344 
1345 		if (c != '+')
1346 		{
1347 			*p++ = c;
1348 			continue;
1349 		}
1350 
1351 		c = *++t & 0xff;
1352 		if (!isascii(c) || !isxdigit(c))
1353 		{
1354 			/* error -- first digit is not hex */
1355 			usrerr("bogus xtext: +%c", c);
1356 			t--;
1357 			continue;
1358 		}
1359 		if (isdigit(c))
1360 			c -= '0';
1361 		else if (isupper(c))
1362 			c -= 'A' - 10;
1363 		else
1364 			c -= 'a' - 10;
1365 		*p = c << 4;
1366 
1367 		c = *++t & 0xff;
1368 		if (!isascii(c) || !isxdigit(c))
1369 		{
1370 			/* error -- second digit is not hex */
1371 			usrerr("bogus xtext: +%x%c", *p >> 4, c);
1372 			t--;
1373 			continue;
1374 		}
1375 		if (isdigit(c))
1376 			c -= '0';
1377 		else if (isupper(c))
1378 			c -= 'A' - 10;
1379 		else
1380 			c -= 'a' - 10;
1381 		*p++ |= c;
1382 	}
1383 	*p = '\0';
1384 	return bp;
1385 }
1386 /*
1387 **  XTEXTOK -- check if a string is legal xtext
1388 **
1389 **	Xtext is used in Delivery Status Notifications.  The spec was
1390 **	taken from RFC 1891, ``SMTP Service Extension for Delivery
1391 **	Status Notifications''.
1392 **
1393 **	Parameters:
1394 **		s -- the string to check.
1395 **
1396 **	Returns:
1397 **		TRUE -- if 's' is legal xtext.
1398 **		FALSE -- if it has any illegal characters in it.
1399 */
1400 
1401 bool
1402 xtextok(s)
1403 	char *s;
1404 {
1405 	int c;
1406 
1407 	while ((c = *s++) != '\0')
1408 	{
1409 		if (c == '+')
1410 		{
1411 			c = *s++;
1412 			if (!isascii(c) || !isxdigit(c))
1413 				return FALSE;
1414 			c = *s++;
1415 			if (!isascii(c) || !isxdigit(c))
1416 				return FALSE;
1417 		}
1418 		else if (c < '!' || c > '~' || c == '=')
1419 			return FALSE;
1420 	}
1421 	return TRUE;
1422 }
1423 /*
1424 **  PRUNEROUTE -- prune an RFC-822 source route
1425 **
1426 **	Trims down a source route to the last internet-registered hop.
1427 **	This is encouraged by RFC 1123 section 5.3.3.
1428 **
1429 **	Parameters:
1430 **		addr -- the address
1431 **
1432 **	Returns:
1433 **		TRUE -- address was modified
1434 **		FALSE -- address could not be pruned
1435 **
1436 **	Side Effects:
1437 **		modifies addr in-place
1438 */
1439 
1440 bool
1441 pruneroute(addr)
1442 	char *addr;
1443 {
1444 #if NAMED_BIND
1445 	char *start, *at, *comma;
1446 	char c;
1447 	int rcode;
1448 	int i;
1449 	char hostbuf[BUFSIZ];
1450 	char *mxhosts[MAXMXHOSTS + 1];
1451 
1452 	/* check to see if this is really a route-addr */
1453 	if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
1454 		return FALSE;
1455 	start = strchr(addr, ':');
1456 	at = strrchr(addr, '@');
1457 	if (start == NULL || at == NULL || at < start)
1458 		return FALSE;
1459 
1460 	/* slice off the angle brackets */
1461 	i = strlen(at + 1);
1462 	if (i >= (SIZE_T) sizeof hostbuf)
1463 		return FALSE;
1464 	strcpy(hostbuf, at + 1);
1465 	hostbuf[i - 1] = '\0';
1466 
1467 	while (start)
1468 	{
1469 		if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
1470 		{
1471 			strcpy(addr + 1, start + 1);
1472 			return TRUE;
1473 		}
1474 		c = *start;
1475 		*start = '\0';
1476 		comma = strrchr(addr, ',');
1477 		if (comma != NULL && comma[1] == '@' &&
1478 		    strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
1479 			strcpy(hostbuf, comma + 2);
1480 		else
1481 			comma = NULL;
1482 		*start = c;
1483 		start = comma;
1484 	}
1485 #endif
1486 	return FALSE;
1487 }
1488