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