savemail.c revision 73191
1/*
2 * Copyright (c) 1998-2001 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.12 2001/01/07 19:31:05 gshapiro Exp $";
16#endif /* ! lint */
17
18/* $FreeBSD: head/contrib/sendmail/src/savemail.c 73191 2001-02-28 00:22:47Z 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		time_t now = curtime();
999
1000		putline("", mci);
1001		(void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
1002		putline(buf, mci);
1003		putline("Content-Type: message/delivery-status", mci);
1004		putline("", mci);
1005
1006		/*
1007		**  Output per-message information.
1008		*/
1009
1010		/* original envelope id from MAIL FROM: line */
1011		if (e->e_parent->e_envid != NULL)
1012		{
1013			(void) snprintf(buf, sizeof buf,
1014					"Original-Envelope-Id: %.800s",
1015					xuntextify(e->e_parent->e_envid));
1016			putline(buf, mci);
1017		}
1018
1019		/* Reporting-MTA: is us (required) */
1020		(void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s",
1021				MyHostName);
1022		putline(buf, mci);
1023
1024		/* DSN-Gateway: not relevant since we are not translating */
1025
1026		/* Received-From-MTA: shows where we got this message from */
1027		if (RealHostName != NULL)
1028		{
1029			/* XXX use $s for type? */
1030			if (e->e_parent->e_from.q_mailer == NULL ||
1031			    (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
1032				p = "dns";
1033			(void) snprintf(buf, sizeof buf,
1034					"Received-From-MTA: %s; %.800s",
1035					p, RealHostName);
1036			putline(buf, mci);
1037		}
1038
1039		/* Arrival-Date: -- when it arrived here */
1040		(void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
1041				arpadate(ctime(&e->e_parent->e_ctime)));
1042		putline(buf, mci);
1043
1044		/*
1045		**  Output per-address information.
1046		*/
1047
1048		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1049		{
1050			register ADDRESS *r;
1051			char *action;
1052
1053			if (QS_IS_BADADDR(q->q_state))
1054			{
1055				/* RFC 1891, 6.2.6 (b) */
1056				if (bitset(QHASNOTIFY, q->q_flags) &&
1057				    !bitset(QPINGONFAILURE, q->q_flags))
1058					continue;
1059				action = "failed";
1060			}
1061			else if (!bitset(QPRIMARY, q->q_flags))
1062				continue;
1063			else if (bitset(QDELIVERED, q->q_flags))
1064			{
1065				if (bitset(QEXPANDED, q->q_flags))
1066					action = "delivered (to mailing list)";
1067				else
1068					action = "delivered (to mailbox)";
1069			}
1070			else if (bitset(QRELAYED, q->q_flags))
1071				action = "relayed (to non-DSN-aware mailer)";
1072			else if (bitset(QEXPANDED, q->q_flags))
1073				action = "expanded (to multi-recipient alias)";
1074			else if (bitset(QDELAYED, q->q_flags))
1075				action = "delayed";
1076			else
1077				continue;
1078
1079			putline("", mci);
1080
1081			/* Original-Recipient: -- passed from on high */
1082			if (q->q_orcpt != NULL)
1083			{
1084				(void) snprintf(buf, sizeof buf,
1085						"Original-Recipient: %.800s",
1086						q->q_orcpt);
1087				putline(buf, mci);
1088			}
1089
1090			/* Final-Recipient: -- the name from the RCPT command */
1091			p = e->e_parent->e_from.q_mailer->m_addrtype;
1092			if (p == NULL)
1093				p = "rfc822";
1094			for (r = q; r->q_alias != NULL; r = r->q_alias)
1095				continue;
1096			if (strcasecmp(p, "rfc822") != 0)
1097			{
1098				(void) snprintf(buf, sizeof buf,
1099						"Final-Recipient: %s; %.800s",
1100						r->q_mailer->m_addrtype,
1101						r->q_user);
1102			}
1103			else if (strchr(r->q_user, '@') != NULL)
1104			{
1105				(void) snprintf(buf, sizeof buf,
1106						"Final-Recipient: %s; %.800s",
1107						p, r->q_user);
1108			}
1109			else if (strchr(r->q_paddr, '@') != NULL)
1110			{
1111				char *qp;
1112				bool b;
1113
1114				qp = r->q_paddr;
1115				/* strip brackets from address */
1116				b = FALSE;
1117				if (*qp == '<')
1118				{
1119					b = qp[strlen(qp) - 1]  == '>';
1120					if (b)
1121						qp[strlen(qp) - 1] = '\0';
1122					qp++;
1123				}
1124				(void) snprintf(buf, sizeof buf,
1125						"Final-Recipient: %s; %.800s",
1126						p, qp);
1127				/* undo damage */
1128				if (b)
1129					qp[strlen(qp)] = '>';
1130			}
1131			else
1132			{
1133				(void) snprintf(buf, sizeof buf,
1134						"Final-Recipient: %s; %.700s@%.100s",
1135						p, r->q_user, MyHostName);
1136			}
1137			putline(buf, mci);
1138
1139			/* X-Actual-Recipient: -- the real problem address */
1140			if (r != q && q->q_user[0] != '\0')
1141			{
1142				if (q->q_mailer != NULL &&
1143				    q->q_mailer->m_addrtype != NULL)
1144					p = q->q_mailer->m_addrtype;
1145				else
1146					p = "rfc822";
1147
1148				if (strcasecmp(p, "rfc822") == 0 &&
1149				    strchr(q->q_user, '@') == NULL)
1150				{
1151					(void) snprintf(buf, sizeof buf,
1152							"X-Actual-Recipient: %s; %.700s@%.100s",
1153							p, q->q_user,
1154							MyHostName);
1155				}
1156				else
1157				{
1158					(void) snprintf(buf, sizeof buf,
1159							"X-Actual-Recipient: %s; %.800s",
1160							p, q->q_user);
1161				}
1162				putline(buf, mci);
1163			}
1164
1165			/* Action: -- what happened? */
1166			snprintf(buf, sizeof buf, "Action: %s", action);
1167			putline(buf, mci);
1168
1169			/* Status: -- what _really_ happened? */
1170			if (q->q_status != NULL)
1171				p = q->q_status;
1172			else if (QS_IS_BADADDR(q->q_state))
1173				p = "5.0.0";
1174			else if (QS_IS_QUEUEUP(q->q_state))
1175				p = "4.0.0";
1176			else
1177				p = "2.0.0";
1178			snprintf(buf, sizeof buf, "Status: %s", p);
1179			putline(buf, mci);
1180
1181			/* Remote-MTA: -- who was I talking to? */
1182			if (q->q_statmta != NULL)
1183			{
1184				if (q->q_mailer == NULL ||
1185				    (p = q->q_mailer->m_mtatype) == NULL)
1186					p = "dns";
1187				(void) snprintf(buf, sizeof buf,
1188						"Remote-MTA: %s; %.800s",
1189						p, q->q_statmta);
1190				p = &buf[strlen(buf) - 1];
1191				if (*p == '.')
1192					*p = '\0';
1193				putline(buf, mci);
1194			}
1195
1196			/* Diagnostic-Code: -- actual result from other end */
1197			if (q->q_rstatus != NULL)
1198			{
1199				p = q->q_mailer->m_diagtype;
1200				if (p == NULL)
1201					p = "smtp";
1202				(void) snprintf(buf, sizeof buf,
1203						"Diagnostic-Code: %s; %.800s",
1204						p, q->q_rstatus);
1205				putline(buf, mci);
1206			}
1207
1208			/* Last-Attempt-Date: -- fine granularity */
1209			if (q->q_statdate == (time_t) 0L)
1210				q->q_statdate = now;
1211			(void) snprintf(buf, sizeof buf,
1212					"Last-Attempt-Date: %s",
1213					arpadate(ctime(&q->q_statdate)));
1214			putline(buf, mci);
1215
1216			/* Will-Retry-Until: -- for delayed messages only */
1217			if (QS_IS_QUEUEUP(q->q_state))
1218			{
1219				time_t xdate;
1220
1221				xdate = e->e_parent->e_ctime +
1222					TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1223				snprintf(buf, sizeof buf,
1224					 "Will-Retry-Until: %s",
1225					 arpadate(ctime(&xdate)));
1226				putline(buf, mci);
1227			}
1228		}
1229	}
1230#endif /* DSN */
1231
1232	/*
1233	**  Output text of original message
1234	*/
1235
1236	putline("", mci);
1237	if (bitset(EF_HAS_DF, e->e_parent->e_flags))
1238	{
1239		sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
1240			   !bitset(EF_NO_BODY_RETN, e->e_flags);
1241
1242		if (e->e_msgboundary == NULL)
1243		{
1244			if (sendbody)
1245				putline("   ----- Original message follows -----\n", mci);
1246			else
1247				putline("   ----- Message header follows -----\n", mci);
1248		}
1249		else
1250		{
1251			(void) snprintf(buf, sizeof buf, "--%s",
1252					e->e_msgboundary);
1253
1254			putline(buf, mci);
1255			(void) snprintf(buf, sizeof buf, "Content-Type: %s",
1256					sendbody ? "message/rfc822"
1257						 : "text/rfc822-headers");
1258			putline(buf, mci);
1259
1260			p = hvalue("Content-Transfer-Encoding",
1261				   e->e_parent->e_header);
1262			if (p != NULL && strcasecmp(p, "binary") != 0)
1263				p = NULL;
1264			if (p == NULL &&
1265			    bitset(EF_HAS8BIT, e->e_parent->e_flags))
1266				p = "8bit";
1267			if (p != NULL)
1268			{
1269				(void) snprintf(buf, sizeof buf,
1270						"Content-Transfer-Encoding: %s",
1271						p);
1272				putline(buf, mci);
1273			}
1274		}
1275		putline("", mci);
1276		save_errno = errno;
1277		putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
1278		errno = save_errno;
1279		if (sendbody)
1280			putbody(mci, e->e_parent, e->e_msgboundary);
1281		else if (e->e_msgboundary == NULL)
1282		{
1283			putline("", mci);
1284			putline("   ----- Message body suppressed -----", mci);
1285		}
1286	}
1287	else if (e->e_msgboundary == NULL)
1288	{
1289		putline("  ----- No message was collected -----\n", mci);
1290	}
1291
1292	if (e->e_msgboundary != NULL)
1293	{
1294		putline("", mci);
1295		(void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
1296		putline(buf, mci);
1297	}
1298	putline("", mci);
1299	(void) fflush(mci->mci_out);
1300
1301	/*
1302	**  Cleanup and exit
1303	*/
1304
1305	if (errno != 0)
1306		syserr("errbody: I/O error");
1307}
1308/*
1309**  SMTPTODSN -- convert SMTP to DSN status code
1310**
1311**	Parameters:
1312**		smtpstat -- the smtp status code (e.g., 550).
1313**
1314**	Returns:
1315**		The DSN version of the status code.
1316*/
1317
1318char *
1319smtptodsn(smtpstat)
1320	int smtpstat;
1321{
1322	if (smtpstat < 0)
1323		return "4.4.2";
1324
1325	switch (smtpstat)
1326	{
1327	  case 450:	/* Req mail action not taken: mailbox unavailable */
1328		return "4.2.0";
1329
1330	  case 451:	/* Req action aborted: local error in processing */
1331		return "4.3.0";
1332
1333	  case 452:	/* Req action not taken: insufficient sys storage */
1334		return "4.3.1";
1335
1336	  case 500:	/* Syntax error, command unrecognized */
1337		return "5.5.2";
1338
1339	  case 501:	/* Syntax error in parameters or arguments */
1340		return "5.5.4";
1341
1342	  case 502:	/* Command not implemented */
1343		return "5.5.1";
1344
1345	  case 503:	/* Bad sequence of commands */
1346		return "5.5.1";
1347
1348	  case 504:	/* Command parameter not implemented */
1349		return "5.5.4";
1350
1351	  case 550:	/* Req mail action not taken: mailbox unavailable */
1352		return "5.2.0";
1353
1354	  case 551:	/* User not local; please try <...> */
1355		return "5.1.6";
1356
1357	  case 552:	/* Req mail action aborted: exceeded storage alloc */
1358		return "5.2.2";
1359
1360	  case 553:	/* Req action not taken: mailbox name not allowed */
1361		return "5.1.0";
1362
1363	  case 554:	/* Transaction failed */
1364		return "5.0.0";
1365	}
1366
1367	if ((smtpstat / 100) == 2)
1368		return "2.0.0";
1369	if ((smtpstat / 100) == 4)
1370		return "4.0.0";
1371	return "5.0.0";
1372}
1373/*
1374**  XTEXTIFY -- take regular text and turn it into DSN-style xtext
1375**
1376**	Parameters:
1377**		t -- the text to convert.
1378**		taboo -- additional characters that must be encoded.
1379**
1380**	Returns:
1381**		The xtext-ified version of the same string.
1382*/
1383
1384char *
1385xtextify(t, taboo)
1386	register char *t;
1387	char *taboo;
1388{
1389	register char *p;
1390	int l;
1391	int nbogus;
1392	static char *bp = NULL;
1393	static int bplen = 0;
1394
1395	if (taboo == NULL)
1396		taboo = "";
1397
1398	/* figure out how long this xtext will have to be */
1399	nbogus = l = 0;
1400	for (p = t; *p != '\0'; p++)
1401	{
1402		register int c = (*p & 0xff);
1403
1404		/* ASCII dependence here -- this is the way the spec words it */
1405		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1406		    strchr(taboo, c) != NULL)
1407			nbogus++;
1408		l++;
1409	}
1410	if (nbogus == 0)
1411		return t;
1412	l += nbogus * 2 + 1;
1413
1414	/* now allocate space if necessary for the new string */
1415	if (l > bplen)
1416	{
1417		if (bp != NULL)
1418			free(bp);
1419		bp = xalloc(l);
1420		bplen = l;
1421	}
1422
1423	/* ok, copy the text with byte expansion */
1424	for (p = bp; *t != '\0'; )
1425	{
1426		register int c = (*t++ & 0xff);
1427
1428		/* ASCII dependence here -- this is the way the spec words it */
1429		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1430		    strchr(taboo, c) != NULL)
1431		{
1432			*p++ = '+';
1433			*p++ = "0123456789ABCDEF"[c >> 4];
1434			*p++ = "0123456789ABCDEF"[c & 0xf];
1435		}
1436		else
1437			*p++ = c;
1438	}
1439	*p = '\0';
1440	return bp;
1441}
1442/*
1443**  XUNTEXTIFY -- take xtext and turn it into plain text
1444**
1445**	Parameters:
1446**		t -- the xtextified text.
1447**
1448**	Returns:
1449**		The decoded text.  No attempt is made to deal with
1450**		null strings in the resulting text.
1451*/
1452
1453char *
1454xuntextify(t)
1455	register char *t;
1456{
1457	register char *p;
1458	int l;
1459	static char *bp = NULL;
1460	static int bplen = 0;
1461
1462	/* heuristic -- if no plus sign, just return the input */
1463	if (strchr(t, '+') == NULL)
1464		return t;
1465
1466	/* xtext is always longer than decoded text */
1467	l = strlen(t);
1468	if (l > bplen)
1469	{
1470		if (bp != NULL)
1471			free(bp);
1472		bp = xalloc(l);
1473		bplen = l;
1474	}
1475
1476	/* ok, copy the text with byte compression */
1477	for (p = bp; *t != '\0'; t++)
1478	{
1479		register int c = *t & 0xff;
1480
1481		if (c != '+')
1482		{
1483			*p++ = c;
1484			continue;
1485		}
1486
1487		c = *++t & 0xff;
1488		if (!isascii(c) || !isxdigit(c))
1489		{
1490			/* error -- first digit is not hex */
1491			usrerr("bogus xtext: +%c", c);
1492			t--;
1493			continue;
1494		}
1495		if (isdigit(c))
1496			c -= '0';
1497		else if (isupper(c))
1498			c -= 'A' - 10;
1499		else
1500			c -= 'a' - 10;
1501		*p = c << 4;
1502
1503		c = *++t & 0xff;
1504		if (!isascii(c) || !isxdigit(c))
1505		{
1506			/* error -- second digit is not hex */
1507			usrerr("bogus xtext: +%x%c", *p >> 4, c);
1508			t--;
1509			continue;
1510		}
1511		if (isdigit(c))
1512			c -= '0';
1513		else if (isupper(c))
1514			c -= 'A' - 10;
1515		else
1516			c -= 'a' - 10;
1517		*p++ |= c;
1518	}
1519	*p = '\0';
1520	return bp;
1521}
1522/*
1523**  XTEXTOK -- check if a string is legal xtext
1524**
1525**	Xtext is used in Delivery Status Notifications.  The spec was
1526**	taken from RFC 1891, ``SMTP Service Extension for Delivery
1527**	Status Notifications''.
1528**
1529**	Parameters:
1530**		s -- the string to check.
1531**
1532**	Returns:
1533**		TRUE -- if 's' is legal xtext.
1534**		FALSE -- if it has any illegal characters in it.
1535*/
1536
1537bool
1538xtextok(s)
1539	char *s;
1540{
1541	int c;
1542
1543	while ((c = *s++) != '\0')
1544	{
1545		if (c == '+')
1546		{
1547			c = *s++;
1548			if (!isascii(c) || !isxdigit(c))
1549				return FALSE;
1550			c = *s++;
1551			if (!isascii(c) || !isxdigit(c))
1552				return FALSE;
1553		}
1554		else if (c < '!' || c > '~' || c == '=')
1555			return FALSE;
1556	}
1557	return TRUE;
1558}
1559/*
1560**  PRUNEROUTE -- prune an RFC-822 source route
1561**
1562**	Trims down a source route to the last internet-registered hop.
1563**	This is encouraged by RFC 1123 section 5.3.3.
1564**
1565**	Parameters:
1566**		addr -- the address
1567**
1568**	Returns:
1569**		TRUE -- address was modified
1570**		FALSE -- address could not be pruned
1571**
1572**	Side Effects:
1573**		modifies addr in-place
1574*/
1575
1576static bool
1577pruneroute(addr)
1578	char *addr;
1579{
1580#if NAMED_BIND
1581	char *start, *at, *comma;
1582	char c;
1583	int rcode;
1584	int i;
1585	char hostbuf[BUFSIZ];
1586	char *mxhosts[MAXMXHOSTS + 1];
1587
1588	/* check to see if this is really a route-addr */
1589	if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
1590		return FALSE;
1591	start = strchr(addr, ':');
1592	at = strrchr(addr, '@');
1593	if (start == NULL || at == NULL || at < start)
1594		return FALSE;
1595
1596	/* slice off the angle brackets */
1597	i = strlen(at + 1);
1598	if (i >= (SIZE_T) sizeof hostbuf)
1599		return FALSE;
1600	(void) strlcpy(hostbuf, at + 1, sizeof hostbuf);
1601	hostbuf[i - 1] = '\0';
1602
1603	while (start)
1604	{
1605		if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0)
1606		{
1607			(void) strlcpy(addr + 1, start + 1, strlen(addr) - 1);
1608			return TRUE;
1609		}
1610		c = *start;
1611		*start = '\0';
1612		comma = strrchr(addr, ',');
1613		if (comma != NULL && comma[1] == '@' &&
1614		    strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
1615			(void) strlcpy(hostbuf, comma + 2, sizeof hostbuf);
1616		else
1617			comma = NULL;
1618		*start = c;
1619		start = comma;
1620	}
1621#endif /* NAMED_BIND */
1622	return FALSE;
1623}
1624