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