xref: /illumos-gate/usr/src/cmd/sendmail/src/savemail.c (revision 48bbca81)
17c478bd9Sstevel@tonic-gate /*
23ee0e492Sjbeck  * Copyright (c) 1998-2003, 2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate  * the sendmail distribution.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
13*48bbca81SDaniel Hoffman /*
14*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
15*48bbca81SDaniel Hoffman  */
167c478bd9Sstevel@tonic-gate #include <sendmail.h>
177c478bd9Sstevel@tonic-gate 
18e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: savemail.c,v 8.314 2009/12/18 17:08:01 ca Exp $")
197c478bd9Sstevel@tonic-gate 
20445f2479Sjbeck static bool	errbody __P((MCI *, ENVELOPE *, char *));
217c478bd9Sstevel@tonic-gate static bool	pruneroute __P((char *));
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate **  SAVEMAIL -- Save mail on error
257c478bd9Sstevel@tonic-gate **
267c478bd9Sstevel@tonic-gate **	If mailing back errors, mail it back to the originator
277c478bd9Sstevel@tonic-gate **	together with an error message; otherwise, just put it in
28*48bbca81SDaniel Hoffman **	dead.letter in the user's home directory (if they exist on
297c478bd9Sstevel@tonic-gate **	this machine).
307c478bd9Sstevel@tonic-gate **
317c478bd9Sstevel@tonic-gate **	Parameters:
327c478bd9Sstevel@tonic-gate **		e -- the envelope containing the message in error.
337c478bd9Sstevel@tonic-gate **		sendbody -- if true, also send back the body of the
347c478bd9Sstevel@tonic-gate **			message; otherwise just send the header.
357c478bd9Sstevel@tonic-gate **
367c478bd9Sstevel@tonic-gate **	Returns:
377c478bd9Sstevel@tonic-gate **		true if savemail panic'ed, (i.e., the data file should
387c478bd9Sstevel@tonic-gate **		be preserved by dropenvelope())
397c478bd9Sstevel@tonic-gate **
407c478bd9Sstevel@tonic-gate **	Side Effects:
417c478bd9Sstevel@tonic-gate **		Saves the letter, by writing or mailing it back to the
42*48bbca81SDaniel Hoffman **		sender, or by putting it in dead.letter in their home
437c478bd9Sstevel@tonic-gate **		directory.
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /* defines for state machine */
477c478bd9Sstevel@tonic-gate #define ESM_REPORT		0	/* report to sender's terminal */
487c478bd9Sstevel@tonic-gate #define ESM_MAIL		1	/* mail back to sender */
497c478bd9Sstevel@tonic-gate #define ESM_QUIET		2	/* mail has already been returned */
507c478bd9Sstevel@tonic-gate #define ESM_DEADLETTER		3	/* save in ~/dead.letter */
517c478bd9Sstevel@tonic-gate #define ESM_POSTMASTER		4	/* return to postmaster */
527c478bd9Sstevel@tonic-gate #define ESM_DEADLETTERDROP	5	/* save in DeadLetterDrop */
537c478bd9Sstevel@tonic-gate #define ESM_PANIC		6	/* call loseqfile() */
547c478bd9Sstevel@tonic-gate #define ESM_DONE		7	/* message is successfully delivered */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate bool
savemail(e,sendbody)577c478bd9Sstevel@tonic-gate savemail(e, sendbody)
587c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
597c478bd9Sstevel@tonic-gate 	bool sendbody;
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
627c478bd9Sstevel@tonic-gate 	bool panic = false;
637c478bd9Sstevel@tonic-gate 	int state;
647c478bd9Sstevel@tonic-gate 	auto ADDRESS *q = NULL;
657c478bd9Sstevel@tonic-gate 	register char *p;
667c478bd9Sstevel@tonic-gate 	MCI mcibuf;
677c478bd9Sstevel@tonic-gate 	int flags;
687c478bd9Sstevel@tonic-gate 	long sff;
697c478bd9Sstevel@tonic-gate 	char buf[MAXLINE + 1];
707c478bd9Sstevel@tonic-gate 	char dlbuf[MAXPATHLEN];
717c478bd9Sstevel@tonic-gate 	SM_MBDB_T user;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	if (tTd(6, 1))
757c478bd9Sstevel@tonic-gate 	{
767c478bd9Sstevel@tonic-gate 		sm_dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n  e_from=",
777c478bd9Sstevel@tonic-gate 			e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
787c478bd9Sstevel@tonic-gate 			ExitStat);
797c478bd9Sstevel@tonic-gate 		printaddr(sm_debug_file(), &e->e_from, false);
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	if (e->e_id == NULL)
837c478bd9Sstevel@tonic-gate 	{
847c478bd9Sstevel@tonic-gate 		/* can't return a message with no id */
857c478bd9Sstevel@tonic-gate 		return panic;
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/*
897c478bd9Sstevel@tonic-gate 	**  In the unhappy event we don't know who to return the mail
907c478bd9Sstevel@tonic-gate 	**  to, make someone up.
917c478bd9Sstevel@tonic-gate 	*/
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (e->e_from.q_paddr == NULL)
947c478bd9Sstevel@tonic-gate 	{
957c478bd9Sstevel@tonic-gate 		e->e_sender = "Postmaster";
967c478bd9Sstevel@tonic-gate 		if (parseaddr(e->e_sender, &e->e_from,
977c478bd9Sstevel@tonic-gate 			      RF_COPYPARSE|RF_SENDERADDR,
987c478bd9Sstevel@tonic-gate 			      '\0', NULL, e, false) == NULL)
997c478bd9Sstevel@tonic-gate 		{
1007c478bd9Sstevel@tonic-gate 			syserr("553 5.3.5 Cannot parse Postmaster!");
1017c478bd9Sstevel@tonic-gate 			finis(true, true, EX_SOFTWARE);
1027c478bd9Sstevel@tonic-gate 		}
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	e->e_to = NULL;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/*
1077c478bd9Sstevel@tonic-gate 	**  Basic state machine.
1087c478bd9Sstevel@tonic-gate 	**
1097c478bd9Sstevel@tonic-gate 	**	This machine runs through the following states:
1107c478bd9Sstevel@tonic-gate 	**
1117c478bd9Sstevel@tonic-gate 	**	ESM_QUIET	Errors have already been printed iff the
1127c478bd9Sstevel@tonic-gate 	**			sender is local.
1137c478bd9Sstevel@tonic-gate 	**	ESM_REPORT	Report directly to the sender's terminal.
1147c478bd9Sstevel@tonic-gate 	**	ESM_MAIL	Mail response to the sender.
1157c478bd9Sstevel@tonic-gate 	**	ESM_DEADLETTER	Save response in ~/dead.letter.
1167c478bd9Sstevel@tonic-gate 	**	ESM_POSTMASTER	Mail response to the postmaster.
1177c478bd9Sstevel@tonic-gate 	**	ESM_DEADLETTERDROP
1187c478bd9Sstevel@tonic-gate 	**			If DeadLetterDrop set, save it there.
1197c478bd9Sstevel@tonic-gate 	**	ESM_PANIC	Save response anywhere possible.
1207c478bd9Sstevel@tonic-gate 	*/
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/* determine starting state */
1237c478bd9Sstevel@tonic-gate 	switch (e->e_errormode)
1247c478bd9Sstevel@tonic-gate 	{
1257c478bd9Sstevel@tonic-gate 	  case EM_WRITE:
1267c478bd9Sstevel@tonic-gate 		state = ESM_REPORT;
1277c478bd9Sstevel@tonic-gate 		break;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	  case EM_BERKNET:
1307c478bd9Sstevel@tonic-gate 	  case EM_MAIL:
1317c478bd9Sstevel@tonic-gate 		state = ESM_MAIL;
1327c478bd9Sstevel@tonic-gate 		break;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	  case EM_PRINT:
1357c478bd9Sstevel@tonic-gate 	  case '\0':
1367c478bd9Sstevel@tonic-gate 		state = ESM_QUIET;
1377c478bd9Sstevel@tonic-gate 		break;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	  case EM_QUIET:
1407c478bd9Sstevel@tonic-gate 		/* no need to return anything at all */
1417c478bd9Sstevel@tonic-gate 		return panic;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	  default:
1447c478bd9Sstevel@tonic-gate 		syserr("554 5.3.0 savemail: bogus errormode x%x",
1457c478bd9Sstevel@tonic-gate 		       e->e_errormode);
1467c478bd9Sstevel@tonic-gate 		state = ESM_MAIL;
1477c478bd9Sstevel@tonic-gate 		break;
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* if this is already an error response, send to postmaster */
1517c478bd9Sstevel@tonic-gate 	if (bitset(EF_RESPONSE, e->e_flags))
1527c478bd9Sstevel@tonic-gate 	{
1537c478bd9Sstevel@tonic-gate 		if (e->e_parent != NULL &&
1547c478bd9Sstevel@tonic-gate 		    bitset(EF_RESPONSE, e->e_parent->e_flags))
1557c478bd9Sstevel@tonic-gate 		{
1567c478bd9Sstevel@tonic-gate 			/* got an error sending a response -- can it */
1577c478bd9Sstevel@tonic-gate 			return panic;
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 		state = ESM_POSTMASTER;
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	while (state != ESM_DONE)
1637c478bd9Sstevel@tonic-gate 	{
1647c478bd9Sstevel@tonic-gate 		if (tTd(6, 5))
1657c478bd9Sstevel@tonic-gate 			sm_dprintf("  state %d\n", state);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		switch (state)
1687c478bd9Sstevel@tonic-gate 		{
1697c478bd9Sstevel@tonic-gate 		  case ESM_QUIET:
1707c478bd9Sstevel@tonic-gate 			if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
1717c478bd9Sstevel@tonic-gate 				state = ESM_DEADLETTER;
1727c478bd9Sstevel@tonic-gate 			else
1737c478bd9Sstevel@tonic-gate 				state = ESM_MAIL;
1747c478bd9Sstevel@tonic-gate 			break;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		  case ESM_REPORT:
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 			/*
1797c478bd9Sstevel@tonic-gate 			**  If the user is still logged in on the same terminal,
1807c478bd9Sstevel@tonic-gate 			**  then write the error messages back to hir (sic).
1817c478bd9Sstevel@tonic-gate 			*/
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate #if USE_TTYPATH
1847c478bd9Sstevel@tonic-gate 			p = ttypath();
1857c478bd9Sstevel@tonic-gate #else /* USE_TTYPATH */
1867c478bd9Sstevel@tonic-gate 			p = NULL;
1877c478bd9Sstevel@tonic-gate #endif /* USE_TTYPATH */
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 			if (p == NULL || sm_io_reopen(SmFtStdio,
1907c478bd9Sstevel@tonic-gate 						      SM_TIME_DEFAULT,
1917c478bd9Sstevel@tonic-gate 						      p, SM_IO_WRONLY, NULL,
1927c478bd9Sstevel@tonic-gate 						      smioout) == NULL)
1937c478bd9Sstevel@tonic-gate 			{
1947c478bd9Sstevel@tonic-gate 				state = ESM_MAIL;
1957c478bd9Sstevel@tonic-gate 				break;
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 
198058561cbSjbeck 			expand("\201n", buf, sizeof(buf), e);
1997c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2007c478bd9Sstevel@tonic-gate 					     "\r\nMessage from %s...\r\n", buf);
2017c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2027c478bd9Sstevel@tonic-gate 					     "Errors occurred while sending mail.\r\n");
2037c478bd9Sstevel@tonic-gate 			if (e->e_xfp != NULL)
2047c478bd9Sstevel@tonic-gate 			{
2057c478bd9Sstevel@tonic-gate 				(void) bfrewind(e->e_xfp);
2067c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2077c478bd9Sstevel@tonic-gate 						     "Transcript follows:\r\n");
2087c478bd9Sstevel@tonic-gate 				while (sm_io_fgets(e->e_xfp, SM_TIME_DEFAULT,
209058561cbSjbeck 						   buf, sizeof(buf)) != NULL &&
2107c478bd9Sstevel@tonic-gate 				       !sm_io_error(smioout))
2117c478bd9Sstevel@tonic-gate 					(void) sm_io_fputs(smioout,
2127c478bd9Sstevel@tonic-gate 							   SM_TIME_DEFAULT,
2137c478bd9Sstevel@tonic-gate 							   buf);
2147c478bd9Sstevel@tonic-gate 			}
2157c478bd9Sstevel@tonic-gate 			else
2167c478bd9Sstevel@tonic-gate 			{
2177c478bd9Sstevel@tonic-gate 				syserr("Cannot open %s",
2187c478bd9Sstevel@tonic-gate 				       queuename(e, XSCRPT_LETTER));
2197c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2207c478bd9Sstevel@tonic-gate 						     "Transcript of session is unavailable.\r\n");
2217c478bd9Sstevel@tonic-gate 			}
2227c478bd9Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2237c478bd9Sstevel@tonic-gate 					     "Original message will be saved in dead.letter.\r\n");
2247c478bd9Sstevel@tonic-gate 			state = ESM_DEADLETTER;
2257c478bd9Sstevel@tonic-gate 			break;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		  case ESM_MAIL:
2287c478bd9Sstevel@tonic-gate 			/*
2297c478bd9Sstevel@tonic-gate 			**  If mailing back, do it.
2307c478bd9Sstevel@tonic-gate 			**	Throw away all further output.  Don't alias,
2317c478bd9Sstevel@tonic-gate 			**	since this could cause loops, e.g., if joe
2327c478bd9Sstevel@tonic-gate 			**	mails to joe@x, and for some reason the network
2337c478bd9Sstevel@tonic-gate 			**	for @x is down, then the response gets sent to
2347c478bd9Sstevel@tonic-gate 			**	joe@x, which gives a response, etc.  Also force
2357c478bd9Sstevel@tonic-gate 			**	the mail to be delivered even if a version of
2367c478bd9Sstevel@tonic-gate 			**	it has already been sent to the sender.
2377c478bd9Sstevel@tonic-gate 			**
2387c478bd9Sstevel@tonic-gate 			**  If this is a configuration or local software
2397c478bd9Sstevel@tonic-gate 			**	error, send to the local postmaster as well,
2407c478bd9Sstevel@tonic-gate 			**	since the originator can't do anything
2417c478bd9Sstevel@tonic-gate 			**	about it anyway.  Note that this is a full
2427c478bd9Sstevel@tonic-gate 			**	copy of the message (intentionally) so that
2437c478bd9Sstevel@tonic-gate 			**	the Postmaster can forward things along.
2447c478bd9Sstevel@tonic-gate 			*/
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 			if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
2477c478bd9Sstevel@tonic-gate 			{
2487c478bd9Sstevel@tonic-gate 				(void) sendtolist("postmaster", NULLADDR,
2497c478bd9Sstevel@tonic-gate 						  &e->e_errorqueue, 0, e);
2507c478bd9Sstevel@tonic-gate 			}
2517c478bd9Sstevel@tonic-gate 			if (!emptyaddr(&e->e_from))
2527c478bd9Sstevel@tonic-gate 			{
2537c478bd9Sstevel@tonic-gate 				char from[TOBUFSIZE];
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 				if (sm_strlcpy(from, e->e_from.q_paddr,
256058561cbSjbeck 						sizeof(from)) >= sizeof(from))
2577c478bd9Sstevel@tonic-gate 				{
2587c478bd9Sstevel@tonic-gate 					state = ESM_POSTMASTER;
2597c478bd9Sstevel@tonic-gate 					break;
2607c478bd9Sstevel@tonic-gate 				}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 				if (!DontPruneRoutes)
2637c478bd9Sstevel@tonic-gate 					(void) pruneroute(from);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 				(void) sendtolist(from, NULLADDR,
2667c478bd9Sstevel@tonic-gate 						  &e->e_errorqueue, 0, e);
2677c478bd9Sstevel@tonic-gate 			}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 			/*
2707c478bd9Sstevel@tonic-gate 			**  Deliver a non-delivery report to the
2717c478bd9Sstevel@tonic-gate 			**  Postmaster-designate (not necessarily
2727c478bd9Sstevel@tonic-gate 			**  Postmaster).  This does not include the
2737c478bd9Sstevel@tonic-gate 			**  body of the message, for privacy reasons.
2747c478bd9Sstevel@tonic-gate 			**  You really shouldn't need this.
2757c478bd9Sstevel@tonic-gate 			*/
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 			e->e_flags |= EF_PM_NOTIFY;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 			/* check to see if there are any good addresses */
2807c478bd9Sstevel@tonic-gate 			for (q = e->e_errorqueue; q != NULL; q = q->q_next)
2817c478bd9Sstevel@tonic-gate 			{
2827c478bd9Sstevel@tonic-gate 				if (QS_IS_SENDABLE(q->q_state))
2837c478bd9Sstevel@tonic-gate 					break;
2847c478bd9Sstevel@tonic-gate 			}
2857c478bd9Sstevel@tonic-gate 			if (q == NULL)
2867c478bd9Sstevel@tonic-gate 			{
2877c478bd9Sstevel@tonic-gate 				/* this is an error-error */
2887c478bd9Sstevel@tonic-gate 				state = ESM_POSTMASTER;
2897c478bd9Sstevel@tonic-gate 				break;
2907c478bd9Sstevel@tonic-gate 			}
2917c478bd9Sstevel@tonic-gate 			if (returntosender(e->e_message, e->e_errorqueue,
2927c478bd9Sstevel@tonic-gate 					   sendbody ? RTSF_SEND_BODY
2937c478bd9Sstevel@tonic-gate 						    : RTSF_NO_BODY,
2947c478bd9Sstevel@tonic-gate 					   e) == 0)
2957c478bd9Sstevel@tonic-gate 			{
2967c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
2977c478bd9Sstevel@tonic-gate 				break;
2987c478bd9Sstevel@tonic-gate 			}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 			/* didn't work -- return to postmaster */
3017c478bd9Sstevel@tonic-gate 			state = ESM_POSTMASTER;
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 		  case ESM_POSTMASTER:
3057c478bd9Sstevel@tonic-gate 			/*
3067c478bd9Sstevel@tonic-gate 			**  Similar to previous case, but to system postmaster.
3077c478bd9Sstevel@tonic-gate 			*/
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 			q = NULL;
310058561cbSjbeck 			expand(DoubleBounceAddr, buf, sizeof(buf), e);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 			/*
3137c478bd9Sstevel@tonic-gate 			**  Just drop it on the floor if DoubleBounceAddr
3147c478bd9Sstevel@tonic-gate 			**  expands to an empty string.
3157c478bd9Sstevel@tonic-gate 			*/
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 			if (*buf == '\0')
3187c478bd9Sstevel@tonic-gate 			{
3197c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
3207c478bd9Sstevel@tonic-gate 				break;
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 			if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
3237c478bd9Sstevel@tonic-gate 			{
3247c478bd9Sstevel@tonic-gate 				syserr("553 5.3.0 cannot parse %s!", buf);
3257c478bd9Sstevel@tonic-gate 				ExitStat = EX_SOFTWARE;
3267c478bd9Sstevel@tonic-gate 				state = ESM_DEADLETTERDROP;
3277c478bd9Sstevel@tonic-gate 				break;
3287c478bd9Sstevel@tonic-gate 			}
3297c478bd9Sstevel@tonic-gate 			flags = RTSF_PM_BOUNCE;
3307c478bd9Sstevel@tonic-gate 			if (sendbody)
3317c478bd9Sstevel@tonic-gate 				flags |= RTSF_SEND_BODY;
3327c478bd9Sstevel@tonic-gate 			if (returntosender(e->e_message, q, flags, e) == 0)
3337c478bd9Sstevel@tonic-gate 			{
3347c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
3357c478bd9Sstevel@tonic-gate 				break;
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			/* didn't work -- last resort */
3397c478bd9Sstevel@tonic-gate 			state = ESM_DEADLETTERDROP;
3407c478bd9Sstevel@tonic-gate 			break;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		  case ESM_DEADLETTER:
3437c478bd9Sstevel@tonic-gate 			/*
3447c478bd9Sstevel@tonic-gate 			**  Save the message in dead.letter.
3457c478bd9Sstevel@tonic-gate 			**	If we weren't mailing back, and the user is
3467c478bd9Sstevel@tonic-gate 			**	local, we should save the message in
3477c478bd9Sstevel@tonic-gate 			**	~/dead.letter so that the poor person doesn't
3487c478bd9Sstevel@tonic-gate 			**	have to type it over again -- and we all know
3497c478bd9Sstevel@tonic-gate 			**	what poor typists UNIX users are.
3507c478bd9Sstevel@tonic-gate 			*/
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 			p = NULL;
3537c478bd9Sstevel@tonic-gate 			if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
3547c478bd9Sstevel@tonic-gate 			{
3557c478bd9Sstevel@tonic-gate 				if (e->e_from.q_home != NULL)
3567c478bd9Sstevel@tonic-gate 					p = e->e_from.q_home;
3577c478bd9Sstevel@tonic-gate 				else if (sm_mbdb_lookup(e->e_from.q_user, &user)
3587c478bd9Sstevel@tonic-gate 					 == EX_OK &&
3597c478bd9Sstevel@tonic-gate 					 *user.mbdb_homedir != '\0')
3607c478bd9Sstevel@tonic-gate 					p = user.mbdb_homedir;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 			if (p == NULL || e->e_dfp == NULL)
3637c478bd9Sstevel@tonic-gate 			{
3647c478bd9Sstevel@tonic-gate 				/* no local directory or no data file */
3657c478bd9Sstevel@tonic-gate 				state = ESM_MAIL;
3667c478bd9Sstevel@tonic-gate 				break;
3677c478bd9Sstevel@tonic-gate 			}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 			/* we have a home directory; write dead.letter */
3707c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_TEMP, 'z', p);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 			/* get the sender for the UnixFromLine */
3737c478bd9Sstevel@tonic-gate 			p = macvalue('g', e);
3747c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
3757c478bd9Sstevel@tonic-gate 
376058561cbSjbeck 			expand("\201z/dead.letter", dlbuf, sizeof(dlbuf), e);
3777c478bd9Sstevel@tonic-gate 			sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
3787c478bd9Sstevel@tonic-gate 			if (RealUid == 0)
3797c478bd9Sstevel@tonic-gate 				sff |= SFF_ROOTOK;
3807c478bd9Sstevel@tonic-gate 			e->e_to = dlbuf;
3817c478bd9Sstevel@tonic-gate 			if (writable(dlbuf, NULL, sff) &&
3827c478bd9Sstevel@tonic-gate 			    mailfile(dlbuf, FileMailer, NULL, sff, e) == EX_OK)
3837c478bd9Sstevel@tonic-gate 			{
3847c478bd9Sstevel@tonic-gate 				int oldverb = Verbose;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 				if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
3877c478bd9Sstevel@tonic-gate 					Verbose = 1;
3887c478bd9Sstevel@tonic-gate 				if (Verbose > 0)
3897c478bd9Sstevel@tonic-gate 					message("Saved message in %s", dlbuf);
3907c478bd9Sstevel@tonic-gate 				Verbose = oldverb;
3917c478bd9Sstevel@tonic-gate 				macdefine(&e->e_macro, A_PERM, 'g', p);
3927c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
3937c478bd9Sstevel@tonic-gate 				break;
3947c478bd9Sstevel@tonic-gate 			}
3957c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'g', p);
3967c478bd9Sstevel@tonic-gate 			state = ESM_MAIL;
3977c478bd9Sstevel@tonic-gate 			break;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		  case ESM_DEADLETTERDROP:
4007c478bd9Sstevel@tonic-gate 			/*
4017c478bd9Sstevel@tonic-gate 			**  Log the mail in DeadLetterDrop file.
4027c478bd9Sstevel@tonic-gate 			*/
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 			if (e->e_class < 0)
4057c478bd9Sstevel@tonic-gate 			{
4067c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
4077c478bd9Sstevel@tonic-gate 				break;
4087c478bd9Sstevel@tonic-gate 			}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
4117c478bd9Sstevel@tonic-gate 			    DeadLetterDrop == NULL ||
4127c478bd9Sstevel@tonic-gate 			    DeadLetterDrop[0] == '\0')
4137c478bd9Sstevel@tonic-gate 			{
4147c478bd9Sstevel@tonic-gate 				state = ESM_PANIC;
4157c478bd9Sstevel@tonic-gate 				break;
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 			sff = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
4197c478bd9Sstevel@tonic-gate 			if (!writable(DeadLetterDrop, NULL, sff) ||
4207c478bd9Sstevel@tonic-gate 			    (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
4217c478bd9Sstevel@tonic-gate 					    FileMode, sff)) == NULL)
4227c478bd9Sstevel@tonic-gate 			{
4237c478bd9Sstevel@tonic-gate 				state = ESM_PANIC;
4247c478bd9Sstevel@tonic-gate 				break;
4257c478bd9Sstevel@tonic-gate 			}
4267c478bd9Sstevel@tonic-gate 
427058561cbSjbeck 			memset(&mcibuf, '\0', sizeof(mcibuf));
4287c478bd9Sstevel@tonic-gate 			mcibuf.mci_out = fp;
4297c478bd9Sstevel@tonic-gate 			mcibuf.mci_mailer = FileMailer;
4307c478bd9Sstevel@tonic-gate 			if (bitnset(M_7BITS, FileMailer->m_flags))
4317c478bd9Sstevel@tonic-gate 				mcibuf.mci_flags |= MCIF_7BIT;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 			/* get the sender for the UnixFromLine */
4347c478bd9Sstevel@tonic-gate 			p = macvalue('g', e);
4357c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
4367c478bd9Sstevel@tonic-gate 
437445f2479Sjbeck 			if (!putfromline(&mcibuf, e) ||
438445f2479Sjbeck 			    !(*e->e_puthdr)(&mcibuf, e->e_header, e,
439445f2479Sjbeck 					M87F_OUTER) ||
440445f2479Sjbeck 			    !(*e->e_putbody)(&mcibuf, e, NULL) ||
441445f2479Sjbeck 			    !putline("\n", &mcibuf) ||
442445f2479Sjbeck 			    sm_io_flush(fp, SM_TIME_DEFAULT) == SM_IO_EOF ||
443445f2479Sjbeck 			    sm_io_error(fp) ||
4447c478bd9Sstevel@tonic-gate 			    sm_io_close(fp, SM_TIME_DEFAULT) < 0)
4457c478bd9Sstevel@tonic-gate 				state = ESM_PANIC;
4467c478bd9Sstevel@tonic-gate 			else
4477c478bd9Sstevel@tonic-gate 			{
4487c478bd9Sstevel@tonic-gate 				int oldverb = Verbose;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 				if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
4517c478bd9Sstevel@tonic-gate 					Verbose = 1;
4527c478bd9Sstevel@tonic-gate 				if (Verbose > 0)
4537c478bd9Sstevel@tonic-gate 					message("Saved message in %s",
4547c478bd9Sstevel@tonic-gate 						DeadLetterDrop);
4557c478bd9Sstevel@tonic-gate 				Verbose = oldverb;
4567c478bd9Sstevel@tonic-gate 				if (LogLevel > 3)
4577c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_NOTICE, e->e_id,
4587c478bd9Sstevel@tonic-gate 						  "Saved message in %s",
4597c478bd9Sstevel@tonic-gate 						  DeadLetterDrop);
4607c478bd9Sstevel@tonic-gate 				state = ESM_DONE;
4617c478bd9Sstevel@tonic-gate 			}
4627c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, 'g', p);
4637c478bd9Sstevel@tonic-gate 			break;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 		  default:
4667c478bd9Sstevel@tonic-gate 			syserr("554 5.3.5 savemail: unknown state %d", state);
4677c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		  case ESM_PANIC:
4707c478bd9Sstevel@tonic-gate 			/* leave the locked queue & transcript files around */
4717c478bd9Sstevel@tonic-gate 			loseqfile(e, "savemail panic");
4727c478bd9Sstevel@tonic-gate 			panic = true;
4737c478bd9Sstevel@tonic-gate 			errno = 0;
4747c478bd9Sstevel@tonic-gate 			syserr("554 savemail: cannot save rejected email anywhere");
4757c478bd9Sstevel@tonic-gate 			state = ESM_DONE;
4767c478bd9Sstevel@tonic-gate 			break;
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 	return panic;
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate **  RETURNTOSENDER -- return a message to the sender with an error.
4837c478bd9Sstevel@tonic-gate **
4847c478bd9Sstevel@tonic-gate **	Parameters:
4857c478bd9Sstevel@tonic-gate **		msg -- the explanatory message.
4867c478bd9Sstevel@tonic-gate **		returnq -- the queue of people to send the message to.
4877c478bd9Sstevel@tonic-gate **		flags -- flags tweaking the operation:
4887c478bd9Sstevel@tonic-gate **			RTSF_SENDBODY -- include body of message (otherwise
4897c478bd9Sstevel@tonic-gate **				just send the header).
4907c478bd9Sstevel@tonic-gate **			RTSF_PMBOUNCE -- this is a postmaster bounce.
4917c478bd9Sstevel@tonic-gate **		e -- the current envelope.
4927c478bd9Sstevel@tonic-gate **
4937c478bd9Sstevel@tonic-gate **	Returns:
4947c478bd9Sstevel@tonic-gate **		zero -- if everything went ok.
4957c478bd9Sstevel@tonic-gate **		else -- some error.
4967c478bd9Sstevel@tonic-gate **
4977c478bd9Sstevel@tonic-gate **	Side Effects:
4987c478bd9Sstevel@tonic-gate **		Returns the current message to the sender via mail.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate #define MAXRETURNS	6	/* max depth of returning messages */
5027c478bd9Sstevel@tonic-gate #define ERRORFUDGE	1024	/* nominal size of error message text */
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate int
returntosender(msg,returnq,flags,e)5057c478bd9Sstevel@tonic-gate returntosender(msg, returnq, flags, e)
5067c478bd9Sstevel@tonic-gate 	char *msg;
5077c478bd9Sstevel@tonic-gate 	ADDRESS *returnq;
5087c478bd9Sstevel@tonic-gate 	int flags;
5097c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	register ENVELOPE *ee;
5127c478bd9Sstevel@tonic-gate 	ENVELOPE *oldcur = CurEnv;
5137c478bd9Sstevel@tonic-gate 	ENVELOPE errenvelope;
5147c478bd9Sstevel@tonic-gate 	static int returndepth = 0;
5157c478bd9Sstevel@tonic-gate 	register ADDRESS *q;
5167c478bd9Sstevel@tonic-gate 	char *p;
5177c478bd9Sstevel@tonic-gate 	char buf[MAXNAME + 1];
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	if (returnq == NULL)
5207c478bd9Sstevel@tonic-gate 		return -1;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (msg == NULL)
5237c478bd9Sstevel@tonic-gate 		msg = "Unable to deliver mail";
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (tTd(6, 1))
5267c478bd9Sstevel@tonic-gate 	{
5277c478bd9Sstevel@tonic-gate 		sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=",
5287c478bd9Sstevel@tonic-gate 			msg, returndepth, e);
5297c478bd9Sstevel@tonic-gate 		printaddr(sm_debug_file(), returnq, true);
5307c478bd9Sstevel@tonic-gate 		if (tTd(6, 20))
5317c478bd9Sstevel@tonic-gate 		{
5327c478bd9Sstevel@tonic-gate 			sm_dprintf("Sendq=");
5337c478bd9Sstevel@tonic-gate 			printaddr(sm_debug_file(), e->e_sendqueue, true);
5347c478bd9Sstevel@tonic-gate 		}
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	if (++returndepth >= MAXRETURNS)
5387c478bd9Sstevel@tonic-gate 	{
5397c478bd9Sstevel@tonic-gate 		if (returndepth != MAXRETURNS)
5407c478bd9Sstevel@tonic-gate 			syserr("554 5.3.0 returntosender: infinite recursion on %s",
5417c478bd9Sstevel@tonic-gate 			       returnq->q_paddr);
5427c478bd9Sstevel@tonic-gate 		/* don't "unrecurse" and fake a clean exit */
5437c478bd9Sstevel@tonic-gate 		/* returndepth--; */
5447c478bd9Sstevel@tonic-gate 		return 0;
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
5487c478bd9Sstevel@tonic-gate 	macdefine(&e->e_macro, A_PERM, 'u', NULL);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/* initialize error envelope */
5517c478bd9Sstevel@tonic-gate 	ee = newenvelope(&errenvelope, e, sm_rpool_new_x(NULL));
5527c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, 'a', "\201b");
5537c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, 'r', "");
5547c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, 's', "localhost");
5557c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, '_', "localhost");
5567c478bd9Sstevel@tonic-gate 	clrsessenvelope(ee);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	ee->e_puthdr = putheader;
5597c478bd9Sstevel@tonic-gate 	ee->e_putbody = errbody;
5607c478bd9Sstevel@tonic-gate 	ee->e_flags |= EF_RESPONSE|EF_METOO;
5617c478bd9Sstevel@tonic-gate 	if (!bitset(EF_OLDSTYLE, e->e_flags))
5627c478bd9Sstevel@tonic-gate 		ee->e_flags &= ~EF_OLDSTYLE;
5637c478bd9Sstevel@tonic-gate 	if (bitset(EF_DONT_MIME, e->e_flags))
5647c478bd9Sstevel@tonic-gate 	{
5657c478bd9Sstevel@tonic-gate 		ee->e_flags |= EF_DONT_MIME;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		/*
5687c478bd9Sstevel@tonic-gate 		**  If we can't convert to MIME and we don't pass
5697c478bd9Sstevel@tonic-gate 		**  8-bit, we can't send the body.
5707c478bd9Sstevel@tonic-gate 		*/
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		if (bitset(EF_HAS8BIT, e->e_flags) &&
5737c478bd9Sstevel@tonic-gate 		    !bitset(MM_PASS8BIT, MimeMode))
5747c478bd9Sstevel@tonic-gate 			flags &= ~RTSF_SEND_BODY;
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	ee->e_sendqueue = returnq;
5787c478bd9Sstevel@tonic-gate 	ee->e_msgsize = 0;
5797c478bd9Sstevel@tonic-gate 	if (bitset(RTSF_SEND_BODY, flags) &&
5807c478bd9Sstevel@tonic-gate 	    !bitset(PRIV_NOBODYRETN, PrivacyFlags))
5817c478bd9Sstevel@tonic-gate 		ee->e_msgsize = ERRORFUDGE + e->e_msgsize;
5827c478bd9Sstevel@tonic-gate 	else
5837c478bd9Sstevel@tonic-gate 		ee->e_flags |= EF_NO_BODY_RETN;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (!setnewqueue(ee))
5867c478bd9Sstevel@tonic-gate 	{
5877c478bd9Sstevel@tonic-gate 		syserr("554 5.3.0 returntosender: cannot select queue for %s",
5887c478bd9Sstevel@tonic-gate 			       returnq->q_paddr);
5897c478bd9Sstevel@tonic-gate 		ExitStat = EX_UNAVAILABLE;
5907c478bd9Sstevel@tonic-gate 		returndepth--;
5917c478bd9Sstevel@tonic-gate 		return -1;
5927c478bd9Sstevel@tonic-gate 	}
5937c478bd9Sstevel@tonic-gate 	initsys(ee);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate #if NAMED_BIND
5967c478bd9Sstevel@tonic-gate 	_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
5977c478bd9Sstevel@tonic-gate 	_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
5987c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
5997c478bd9Sstevel@tonic-gate 	for (q = returnq; q != NULL; q = q->q_next)
6007c478bd9Sstevel@tonic-gate 	{
6017c478bd9Sstevel@tonic-gate 		if (QS_IS_BADADDR(q->q_state))
6027c478bd9Sstevel@tonic-gate 			continue;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
6057c478bd9Sstevel@tonic-gate 		q->q_flags |= QPINGONFAILURE;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 		if (!QS_IS_DEAD(q->q_state))
6087c478bd9Sstevel@tonic-gate 			ee->e_nrcpts++;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 		if (q->q_alias == NULL)
611058561cbSjbeck 			addheader("To", q->q_paddr, 0, ee, true);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if (LogLevel > 5)
6157c478bd9Sstevel@tonic-gate 	{
6167c478bd9Sstevel@tonic-gate 		if (bitset(EF_RESPONSE, e->e_flags))
6177c478bd9Sstevel@tonic-gate 			p = "return to sender";
6187c478bd9Sstevel@tonic-gate 		else if (bitset(EF_WARNING, e->e_flags))
6197c478bd9Sstevel@tonic-gate 			p = "sender notify";
6207c478bd9Sstevel@tonic-gate 		else if (bitset(RTSF_PM_BOUNCE, flags))
6217c478bd9Sstevel@tonic-gate 			p = "postmaster notify";
6227c478bd9Sstevel@tonic-gate 		else
6237c478bd9Sstevel@tonic-gate 			p = "DSN";
6247c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "%s: %s: %s",
6257c478bd9Sstevel@tonic-gate 			  ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (SendMIMEErrors)
6297c478bd9Sstevel@tonic-gate 	{
630058561cbSjbeck 		addheader("MIME-Version", "1.0", 0, ee, true);
631058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf), "%s.%ld/%.100s",
6327c478bd9Sstevel@tonic-gate 				ee->e_id, (long)curtime(), MyHostName);
6337c478bd9Sstevel@tonic-gate 		ee->e_msgboundary = sm_rpool_strdup_x(ee->e_rpool, buf);
634058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf),
6357c478bd9Sstevel@tonic-gate #if DSN
6367c478bd9Sstevel@tonic-gate 				"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
6377c478bd9Sstevel@tonic-gate #else /* DSN */
6387c478bd9Sstevel@tonic-gate 				"multipart/mixed; boundary=\"%s\"",
6397c478bd9Sstevel@tonic-gate #endif /* DSN */
6407c478bd9Sstevel@tonic-gate 				ee->e_msgboundary);
641058561cbSjbeck 		addheader("Content-Type", buf, 0, ee, true);
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		p = hvalue("Content-Transfer-Encoding", e->e_header);
6447c478bd9Sstevel@tonic-gate 		if (p != NULL && sm_strcasecmp(p, "binary") != 0)
6457c478bd9Sstevel@tonic-gate 			p = NULL;
6467c478bd9Sstevel@tonic-gate 		if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
6477c478bd9Sstevel@tonic-gate 			p = "8bit";
6487c478bd9Sstevel@tonic-gate 		if (p != NULL)
649058561cbSjbeck 			addheader("Content-Transfer-Encoding", p, 0, ee, true);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	if (strncmp(msg, "Warning:", 8) == 0)
6527c478bd9Sstevel@tonic-gate 	{
653058561cbSjbeck 		addheader("Subject", msg, 0, ee, true);
6547c478bd9Sstevel@tonic-gate 		p = "warning-timeout";
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 	else if (strncmp(msg, "Postmaster warning:", 19) == 0)
6577c478bd9Sstevel@tonic-gate 	{
658058561cbSjbeck 		addheader("Subject", msg, 0, ee, true);
6597c478bd9Sstevel@tonic-gate 		p = "postmaster-warning";
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 	else if (strcmp(msg, "Return receipt") == 0)
6627c478bd9Sstevel@tonic-gate 	{
663058561cbSjbeck 		addheader("Subject", msg, 0, ee, true);
6647c478bd9Sstevel@tonic-gate 		p = "return-receipt";
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 	else if (bitset(RTSF_PM_BOUNCE, flags))
6677c478bd9Sstevel@tonic-gate 	{
668058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf),
6697c478bd9Sstevel@tonic-gate 			 "Postmaster notify: see transcript for details");
670058561cbSjbeck 		addheader("Subject", buf, 0, ee, true);
6717c478bd9Sstevel@tonic-gate 		p = "postmaster-notification";
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	else
6747c478bd9Sstevel@tonic-gate 	{
675058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf),
6767c478bd9Sstevel@tonic-gate 			 "Returned mail: see transcript for details");
677058561cbSjbeck 		addheader("Subject", buf, 0, ee, true);
6787c478bd9Sstevel@tonic-gate 		p = "failure";
6797c478bd9Sstevel@tonic-gate 	}
680058561cbSjbeck 	(void) sm_snprintf(buf, sizeof(buf), "auto-generated (%s)", p);
681058561cbSjbeck 	addheader("Auto-Submitted", buf, 0, ee, true);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/* fake up an address header for the from person */
684058561cbSjbeck 	expand("\201n", buf, sizeof(buf), e);
6857c478bd9Sstevel@tonic-gate 	if (parseaddr(buf, &ee->e_from,
6867c478bd9Sstevel@tonic-gate 		      RF_COPYALL|RF_SENDERADDR, '\0', NULL, e, false) == NULL)
6877c478bd9Sstevel@tonic-gate 	{
6887c478bd9Sstevel@tonic-gate 		syserr("553 5.3.5 Can't parse myself!");
6897c478bd9Sstevel@tonic-gate 		ExitStat = EX_SOFTWARE;
6907c478bd9Sstevel@tonic-gate 		returndepth--;
6917c478bd9Sstevel@tonic-gate 		return -1;
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate 	ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
6947c478bd9Sstevel@tonic-gate 	ee->e_from.q_flags |= QPINGONFAILURE;
6957c478bd9Sstevel@tonic-gate 	ee->e_sender = ee->e_from.q_paddr;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	/* push state into submessage */
6987c478bd9Sstevel@tonic-gate 	CurEnv = ee;
6997c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, 'f', "\201n");
7007c478bd9Sstevel@tonic-gate 	macdefine(&ee->e_macro, A_PERM, 'x', "Mail Delivery Subsystem");
7017c478bd9Sstevel@tonic-gate 	eatheader(ee, true, true);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	/* mark statistics */
7047c478bd9Sstevel@tonic-gate 	markstats(ee, NULLADDR, STATS_NORMAL);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/* actually deliver the error message */
7077c478bd9Sstevel@tonic-gate 	sendall(ee, SM_DELIVER);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/* restore state */
710e9af4bc0SJohn Beck 	(void) dropenvelope(ee, true, false);
7117c478bd9Sstevel@tonic-gate 	sm_rpool_free(ee->e_rpool);
7127c478bd9Sstevel@tonic-gate 	CurEnv = oldcur;
7137c478bd9Sstevel@tonic-gate 	returndepth--;
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/* check for delivery errors */
7167c478bd9Sstevel@tonic-gate 	if (ee->e_parent == NULL ||
7177c478bd9Sstevel@tonic-gate 	    !bitset(EF_RESPONSE, ee->e_parent->e_flags))
7187c478bd9Sstevel@tonic-gate 		return 0;
7197c478bd9Sstevel@tonic-gate 	for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
7207c478bd9Sstevel@tonic-gate 	{
7217c478bd9Sstevel@tonic-gate 		if (QS_IS_ATTEMPTED(q->q_state))
7227c478bd9Sstevel@tonic-gate 			return 0;
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 	return -1;
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate /*
7277c478bd9Sstevel@tonic-gate **  ERRBODY -- output the body of an error message.
7287c478bd9Sstevel@tonic-gate **
7297c478bd9Sstevel@tonic-gate **	Typically this is a copy of the transcript plus a copy of the
7307c478bd9Sstevel@tonic-gate **	original offending message.
7317c478bd9Sstevel@tonic-gate **
7327c478bd9Sstevel@tonic-gate **	Parameters:
7337c478bd9Sstevel@tonic-gate **		mci -- the mailer connection information.
7347c478bd9Sstevel@tonic-gate **		e -- the envelope we are working in.
7357c478bd9Sstevel@tonic-gate **		separator -- any possible MIME separator (unused).
7367c478bd9Sstevel@tonic-gate **
7377c478bd9Sstevel@tonic-gate **	Returns:
7383ee0e492Sjbeck **		true iff body was written successfully
7397c478bd9Sstevel@tonic-gate **
7407c478bd9Sstevel@tonic-gate **	Side Effects:
7417c478bd9Sstevel@tonic-gate **		Outputs the body of an error message.
7427c478bd9Sstevel@tonic-gate */
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
745445f2479Sjbeck static bool
errbody(mci,e,separator)7467c478bd9Sstevel@tonic-gate errbody(mci, e, separator)
7477c478bd9Sstevel@tonic-gate 	register MCI *mci;
7487c478bd9Sstevel@tonic-gate 	register ENVELOPE *e;
7497c478bd9Sstevel@tonic-gate 	char *separator;
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	bool printheader;
7527c478bd9Sstevel@tonic-gate 	bool sendbody;
7537c478bd9Sstevel@tonic-gate 	bool pm_notify;
7547c478bd9Sstevel@tonic-gate 	int save_errno;
7557c478bd9Sstevel@tonic-gate 	register SM_FILE_T *xfile;
7567c478bd9Sstevel@tonic-gate 	char *p;
7577c478bd9Sstevel@tonic-gate 	register ADDRESS *q = NULL;
7587c478bd9Sstevel@tonic-gate 	char actual[MAXLINE];
7597c478bd9Sstevel@tonic-gate 	char buf[MAXLINE];
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (bitset(MCIF_INHEADER, mci->mci_flags))
7627c478bd9Sstevel@tonic-gate 	{
763445f2479Sjbeck 		if (!putline("", mci))
764445f2479Sjbeck 			goto writeerr;
7657c478bd9Sstevel@tonic-gate 		mci->mci_flags &= ~MCIF_INHEADER;
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 	if (e->e_parent == NULL)
7687c478bd9Sstevel@tonic-gate 	{
7697c478bd9Sstevel@tonic-gate 		syserr("errbody: null parent");
770445f2479Sjbeck 		if (!putline("   ----- Original message lost -----\n", mci))
771445f2479Sjbeck 			goto writeerr;
772445f2479Sjbeck 		return true;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	/*
7767c478bd9Sstevel@tonic-gate 	**  Output MIME header.
7777c478bd9Sstevel@tonic-gate 	*/
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	if (e->e_msgboundary != NULL)
7807c478bd9Sstevel@tonic-gate 	{
781058561cbSjbeck 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
782445f2479Sjbeck 		if (!putline("This is a MIME-encapsulated message", mci) ||
783445f2479Sjbeck 		    !putline("", mci) ||
784445f2479Sjbeck 		    !putline(buf, mci) ||
785445f2479Sjbeck 		    !putline("", mci))
786445f2479Sjbeck 			goto writeerr;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/*
7907c478bd9Sstevel@tonic-gate 	**  Output introductory information.
7917c478bd9Sstevel@tonic-gate 	*/
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	pm_notify = false;
7947c478bd9Sstevel@tonic-gate 	p = hvalue("subject", e->e_header);
7957c478bd9Sstevel@tonic-gate 	if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
7967c478bd9Sstevel@tonic-gate 		pm_notify = true;
7977c478bd9Sstevel@tonic-gate 	else
7987c478bd9Sstevel@tonic-gate 	{
7997c478bd9Sstevel@tonic-gate 		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
8007c478bd9Sstevel@tonic-gate 		{
8017c478bd9Sstevel@tonic-gate 			if (QS_IS_BADADDR(q->q_state))
8027c478bd9Sstevel@tonic-gate 				break;
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 	if (!pm_notify && q == NULL &&
8067c478bd9Sstevel@tonic-gate 	    !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
8077c478bd9Sstevel@tonic-gate 	{
808445f2479Sjbeck 		if (!putline("    **********************************************",
809445f2479Sjbeck 			mci) ||
810445f2479Sjbeck 		    !putline("    **      THIS IS A WARNING MESSAGE ONLY      **",
811445f2479Sjbeck 			mci) ||
812445f2479Sjbeck 		    !putline("    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **",
813445f2479Sjbeck 			mci) ||
814445f2479Sjbeck 		    !putline("    **********************************************",
815445f2479Sjbeck 			mci) ||
816445f2479Sjbeck 		    !putline("", mci))
817445f2479Sjbeck 			goto writeerr;
8187c478bd9Sstevel@tonic-gate 	}
819058561cbSjbeck 	(void) sm_snprintf(buf, sizeof(buf),
8207c478bd9Sstevel@tonic-gate 		"The original message was received at %s",
8217c478bd9Sstevel@tonic-gate 		arpadate(ctime(&e->e_parent->e_ctime)));
822445f2479Sjbeck 	if (!putline(buf, mci))
823445f2479Sjbeck 		goto writeerr;
824058561cbSjbeck 	expand("from \201_", buf, sizeof(buf), e->e_parent);
825445f2479Sjbeck 	if (!putline(buf, mci))
826445f2479Sjbeck 		goto writeerr;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	/* include id in postmaster copies */
8297c478bd9Sstevel@tonic-gate 	if (pm_notify && e->e_parent->e_id != NULL)
8307c478bd9Sstevel@tonic-gate 	{
831058561cbSjbeck 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "with id ",
8327c478bd9Sstevel@tonic-gate 			e->e_parent->e_id);
833445f2479Sjbeck 		if (!putline(buf, mci))
834445f2479Sjbeck 			goto writeerr;
8357c478bd9Sstevel@tonic-gate 	}
836445f2479Sjbeck 	if (!putline("", mci))
837445f2479Sjbeck 		goto writeerr;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/*
8407c478bd9Sstevel@tonic-gate 	**  Output error message header (if specified and available).
8417c478bd9Sstevel@tonic-gate 	*/
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	if (ErrMsgFile != NULL &&
8447c478bd9Sstevel@tonic-gate 	    !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
8457c478bd9Sstevel@tonic-gate 	{
8467c478bd9Sstevel@tonic-gate 		if (*ErrMsgFile == '/')
8477c478bd9Sstevel@tonic-gate 		{
8487c478bd9Sstevel@tonic-gate 			long sff = SFF_ROOTOK|SFF_REGONLY;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 			if (DontLockReadFiles)
8517c478bd9Sstevel@tonic-gate 				sff |= SFF_NOLOCK;
8527c478bd9Sstevel@tonic-gate 			if (!bitnset(DBS_ERRORHEADERINUNSAFEDIRPATH,
8537c478bd9Sstevel@tonic-gate 				     DontBlameSendmail))
8547c478bd9Sstevel@tonic-gate 				sff |= SFF_SAFEDIRPATH;
8557c478bd9Sstevel@tonic-gate 			xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
8567c478bd9Sstevel@tonic-gate 			if (xfile != NULL)
8577c478bd9Sstevel@tonic-gate 			{
8587c478bd9Sstevel@tonic-gate 				while (sm_io_fgets(xfile, SM_TIME_DEFAULT, buf,
859058561cbSjbeck 						   sizeof(buf)) != NULL)
8607c478bd9Sstevel@tonic-gate 				{
861058561cbSjbeck 					int lbs;
862058561cbSjbeck 					bool putok;
863058561cbSjbeck 					char *lbp;
864058561cbSjbeck 
865058561cbSjbeck 					lbs = sizeof(buf);
866058561cbSjbeck 					lbp = translate_dollars(buf, buf, &lbs);
867058561cbSjbeck 					expand(lbp, lbp, lbs, e);
868058561cbSjbeck 					putok = putline(lbp, mci);
869058561cbSjbeck 					if (lbp != buf)
870058561cbSjbeck 						sm_free(lbp);
871058561cbSjbeck 					if (!putok)
872445f2479Sjbeck 						goto writeerr;
8737c478bd9Sstevel@tonic-gate 				}
8747c478bd9Sstevel@tonic-gate 				(void) sm_io_close(xfile, SM_TIME_DEFAULT);
875445f2479Sjbeck 				if (!putline("\n", mci))
876445f2479Sjbeck 					goto writeerr;
8777c478bd9Sstevel@tonic-gate 			}
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 		else
8807c478bd9Sstevel@tonic-gate 		{
881058561cbSjbeck 			expand(ErrMsgFile, buf, sizeof(buf), e);
882445f2479Sjbeck 			if (!putline(buf, mci) || !putline("", mci))
883445f2479Sjbeck 				goto writeerr;
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 	}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/*
8887c478bd9Sstevel@tonic-gate 	**  Output message introduction
8897c478bd9Sstevel@tonic-gate 	*/
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	/* permanent fatal errors */
8927c478bd9Sstevel@tonic-gate 	printheader = true;
8937c478bd9Sstevel@tonic-gate 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
8947c478bd9Sstevel@tonic-gate 	{
8957c478bd9Sstevel@tonic-gate 		if (!QS_IS_BADADDR(q->q_state) ||
8967c478bd9Sstevel@tonic-gate 		    !bitset(QPINGONFAILURE, q->q_flags))
8977c478bd9Sstevel@tonic-gate 			continue;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		if (printheader)
9007c478bd9Sstevel@tonic-gate 		{
901445f2479Sjbeck 			if (!putline("   ----- The following addresses had permanent fatal errors -----",
902445f2479Sjbeck 					mci))
903445f2479Sjbeck 				goto writeerr;
9047c478bd9Sstevel@tonic-gate 			printheader = false;
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
908058561cbSjbeck 				  sizeof(buf));
909445f2479Sjbeck 		if (!putline(buf, mci))
910445f2479Sjbeck 			goto writeerr;
9117c478bd9Sstevel@tonic-gate 		if (q->q_rstatus != NULL)
9127c478bd9Sstevel@tonic-gate 		{
913058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
9147c478bd9Sstevel@tonic-gate 				"    (reason: %s)",
9157c478bd9Sstevel@tonic-gate 				shortenstring(exitstat(q->q_rstatus),
9167c478bd9Sstevel@tonic-gate 					      MAXSHORTSTR));
917445f2479Sjbeck 			if (!putline(buf, mci))
918445f2479Sjbeck 				goto writeerr;
9197c478bd9Sstevel@tonic-gate 		}
9207c478bd9Sstevel@tonic-gate 		if (q->q_alias != NULL)
9217c478bd9Sstevel@tonic-gate 		{
922058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
9237c478bd9Sstevel@tonic-gate 				"    (expanded from: %s)",
9247c478bd9Sstevel@tonic-gate 				shortenstring(q->q_alias->q_paddr,
9257c478bd9Sstevel@tonic-gate 					      MAXSHORTSTR));
926445f2479Sjbeck 			if (!putline(buf, mci))
927445f2479Sjbeck 				goto writeerr;
9287c478bd9Sstevel@tonic-gate 		}
9297c478bd9Sstevel@tonic-gate 	}
930445f2479Sjbeck 	if (!printheader && !putline("", mci))
931445f2479Sjbeck 		goto writeerr;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/* transient non-fatal errors */
9347c478bd9Sstevel@tonic-gate 	printheader = true;
9357c478bd9Sstevel@tonic-gate 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
9367c478bd9Sstevel@tonic-gate 	{
9377c478bd9Sstevel@tonic-gate 		if (QS_IS_BADADDR(q->q_state) ||
9387c478bd9Sstevel@tonic-gate 		    !bitset(QPRIMARY, q->q_flags) ||
9397c478bd9Sstevel@tonic-gate 		    !bitset(QBYNDELAY, q->q_flags) ||
9407c478bd9Sstevel@tonic-gate 		    !bitset(QDELAYED, q->q_flags))
9417c478bd9Sstevel@tonic-gate 			continue;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 		if (printheader)
9447c478bd9Sstevel@tonic-gate 		{
945445f2479Sjbeck 			if (!putline("   ----- The following addresses had transient non-fatal errors -----",
946445f2479Sjbeck 					mci))
947445f2479Sjbeck 				goto writeerr;
9487c478bd9Sstevel@tonic-gate 			printheader = false;
9497c478bd9Sstevel@tonic-gate 		}
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
952058561cbSjbeck 				  sizeof(buf));
953445f2479Sjbeck 		if (!putline(buf, mci))
954445f2479Sjbeck 			goto writeerr;
9557c478bd9Sstevel@tonic-gate 		if (q->q_alias != NULL)
9567c478bd9Sstevel@tonic-gate 		{
957058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
9587c478bd9Sstevel@tonic-gate 				"    (expanded from: %s)",
9597c478bd9Sstevel@tonic-gate 				shortenstring(q->q_alias->q_paddr,
9607c478bd9Sstevel@tonic-gate 					      MAXSHORTSTR));
961445f2479Sjbeck 			if (!putline(buf, mci))
962445f2479Sjbeck 				goto writeerr;
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 	}
965445f2479Sjbeck 	if (!printheader && !putline("", mci))
966445f2479Sjbeck 		goto writeerr;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/* successful delivery notifications */
9697c478bd9Sstevel@tonic-gate 	printheader = true;
9707c478bd9Sstevel@tonic-gate 	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
9717c478bd9Sstevel@tonic-gate 	{
9727c478bd9Sstevel@tonic-gate 		if (QS_IS_BADADDR(q->q_state) ||
9737c478bd9Sstevel@tonic-gate 		    !bitset(QPRIMARY, q->q_flags) ||
9747c478bd9Sstevel@tonic-gate 		    bitset(QBYNDELAY, q->q_flags) ||
9757c478bd9Sstevel@tonic-gate 		    bitset(QDELAYED, q->q_flags))
9767c478bd9Sstevel@tonic-gate 			continue;
9777c478bd9Sstevel@tonic-gate 		else if (bitset(QBYNRELAY, q->q_flags))
9787c478bd9Sstevel@tonic-gate 			p = "Deliver-By notify: relayed";
9797c478bd9Sstevel@tonic-gate 		else if (bitset(QBYTRACE, q->q_flags))
9807c478bd9Sstevel@tonic-gate 			p = "Deliver-By trace: relayed";
9817c478bd9Sstevel@tonic-gate 		else if (!bitset(QPINGONSUCCESS, q->q_flags))
9827c478bd9Sstevel@tonic-gate 			continue;
9837c478bd9Sstevel@tonic-gate 		else if (bitset(QRELAYED, q->q_flags))
9847c478bd9Sstevel@tonic-gate 			p = "relayed to non-DSN-aware mailer";
9857c478bd9Sstevel@tonic-gate 		else if (bitset(QDELIVERED, q->q_flags))
9867c478bd9Sstevel@tonic-gate 		{
9877c478bd9Sstevel@tonic-gate 			if (bitset(QEXPANDED, q->q_flags))
9887c478bd9Sstevel@tonic-gate 				p = "successfully delivered to mailing list";
9897c478bd9Sstevel@tonic-gate 			else
9907c478bd9Sstevel@tonic-gate 				p = "successfully delivered to mailbox";
9917c478bd9Sstevel@tonic-gate 		}
9927c478bd9Sstevel@tonic-gate 		else if (bitset(QEXPANDED, q->q_flags))
9937c478bd9Sstevel@tonic-gate 			p = "expanded by alias";
9947c478bd9Sstevel@tonic-gate 		else
9957c478bd9Sstevel@tonic-gate 			continue;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		if (printheader)
9987c478bd9Sstevel@tonic-gate 		{
999445f2479Sjbeck 			if (!putline("   ----- The following addresses had successful delivery notifications -----",
1000445f2479Sjbeck 					mci))
1001445f2479Sjbeck 				goto writeerr;
10027c478bd9Sstevel@tonic-gate 			printheader = false;
10037c478bd9Sstevel@tonic-gate 		}
10047c478bd9Sstevel@tonic-gate 
1005058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf), "%s  (%s)",
10067c478bd9Sstevel@tonic-gate 			 shortenstring(q->q_paddr, MAXSHORTSTR), p);
1007445f2479Sjbeck 		if (!putline(buf, mci))
1008445f2479Sjbeck 			goto writeerr;
10097c478bd9Sstevel@tonic-gate 		if (q->q_alias != NULL)
10107c478bd9Sstevel@tonic-gate 		{
1011058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
10127c478bd9Sstevel@tonic-gate 				"    (expanded from: %s)",
10137c478bd9Sstevel@tonic-gate 				shortenstring(q->q_alias->q_paddr,
10147c478bd9Sstevel@tonic-gate 					      MAXSHORTSTR));
1015445f2479Sjbeck 			if (!putline(buf, mci))
1016445f2479Sjbeck 				goto writeerr;
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 	}
1019445f2479Sjbeck 	if (!printheader && !putline("", mci))
1020445f2479Sjbeck 		goto writeerr;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	/*
10237c478bd9Sstevel@tonic-gate 	**  Output transcript of errors
10247c478bd9Sstevel@tonic-gate 	*/
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
10277c478bd9Sstevel@tonic-gate 	if (e->e_parent->e_xfp == NULL)
10287c478bd9Sstevel@tonic-gate 	{
1029445f2479Sjbeck 		if (!putline("   ----- Transcript of session is unavailable -----\n",
1030445f2479Sjbeck 				mci))
1031445f2479Sjbeck 			goto writeerr;
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 	else
10347c478bd9Sstevel@tonic-gate 	{
10357c478bd9Sstevel@tonic-gate 		printheader = true;
10367c478bd9Sstevel@tonic-gate 		(void) bfrewind(e->e_parent->e_xfp);
10377c478bd9Sstevel@tonic-gate 		if (e->e_xfp != NULL)
10387c478bd9Sstevel@tonic-gate 			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
10397c478bd9Sstevel@tonic-gate 		while (sm_io_fgets(e->e_parent->e_xfp, SM_TIME_DEFAULT, buf,
1040058561cbSjbeck 				   sizeof(buf)) != NULL)
10417c478bd9Sstevel@tonic-gate 		{
1042445f2479Sjbeck 			if (printheader && !putline("   ----- Transcript of session follows -----\n",
1043445f2479Sjbeck 						mci))
1044445f2479Sjbeck 				goto writeerr;
10457c478bd9Sstevel@tonic-gate 			printheader = false;
1046445f2479Sjbeck 			if (!putline(buf, mci))
1047445f2479Sjbeck 				goto writeerr;
10487c478bd9Sstevel@tonic-gate 		}
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 	errno = 0;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate #if DSN
10537c478bd9Sstevel@tonic-gate 	/*
10547c478bd9Sstevel@tonic-gate 	**  Output machine-readable version.
10557c478bd9Sstevel@tonic-gate 	*/
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	if (e->e_msgboundary != NULL)
10587c478bd9Sstevel@tonic-gate 	{
1059058561cbSjbeck 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
1060445f2479Sjbeck 		if (!putline("", mci) ||
1061445f2479Sjbeck 		    !putline(buf, mci) ||
1062445f2479Sjbeck 		    !putline("Content-Type: message/delivery-status", mci) ||
1063445f2479Sjbeck 		    !putline("", mci))
1064445f2479Sjbeck 			goto writeerr;
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 		/*
10677c478bd9Sstevel@tonic-gate 		**  Output per-message information.
10687c478bd9Sstevel@tonic-gate 		*/
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 		/* original envelope id from MAIL FROM: line */
10717c478bd9Sstevel@tonic-gate 		if (e->e_parent->e_envid != NULL)
10727c478bd9Sstevel@tonic-gate 		{
1073058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
10747c478bd9Sstevel@tonic-gate 					"Original-Envelope-Id: %.800s",
10757c478bd9Sstevel@tonic-gate 					xuntextify(e->e_parent->e_envid));
1076445f2479Sjbeck 			if (!putline(buf, mci))
1077445f2479Sjbeck 				goto writeerr;
10787c478bd9Sstevel@tonic-gate 		}
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 		/* Reporting-MTA: is us (required) */
1081058561cbSjbeck 		(void) sm_snprintf(buf, sizeof(buf),
10827c478bd9Sstevel@tonic-gate 				   "Reporting-MTA: dns; %.800s", MyHostName);
1083445f2479Sjbeck 		if (!putline(buf, mci))
1084445f2479Sjbeck 			goto writeerr;
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 		/* DSN-Gateway: not relevant since we are not translating */
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		/* Received-From-MTA: shows where we got this message from */
10897c478bd9Sstevel@tonic-gate 		if (RealHostName != NULL)
10907c478bd9Sstevel@tonic-gate 		{
10917c478bd9Sstevel@tonic-gate 			/* XXX use $s for type? */
10927c478bd9Sstevel@tonic-gate 			if (e->e_parent->e_from.q_mailer == NULL ||
10937c478bd9Sstevel@tonic-gate 			    (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
10947c478bd9Sstevel@tonic-gate 				p = "dns";
1095058561cbSjbeck 			(void) sm_snprintf(buf, sizeof(buf),
10967c478bd9Sstevel@tonic-gate 					"Received-From-MTA: %s; %.800s",
10977c478bd9Sstevel@tonic-gate 					p, RealHostName);
1098445f2479Sjbeck 			if (!putline(buf, mci))
1099445f2479Sjbeck 				goto writeerr;
11007c478bd9Sstevel@tonic-gate 		}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		/* Arrival-Date: -- when it arrived here */
1103058561cbSjbeck 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "Arrival-Date: ",
11047c478bd9Sstevel@tonic-gate 				arpadate(ctime(&e->e_parent->e_ctime)));
1105445f2479Sjbeck 		if (!putline(buf, mci))
1106445f2479Sjbeck 			goto writeerr;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		/* Deliver-By-Date: -- when it should have been delivered */
11097c478bd9Sstevel@tonic-gate 		if (IS_DLVR_BY(e->e_parent))
11107c478bd9Sstevel@tonic-gate 		{
11117c478bd9Sstevel@tonic-gate 			time_t dbyd;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 			dbyd = e->e_parent->e_ctime + e->e_parent->e_deliver_by;
1114058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2,
11157c478bd9Sstevel@tonic-gate 					"Deliver-By-Date: ",
11167c478bd9Sstevel@tonic-gate 					arpadate(ctime(&dbyd)));
1117445f2479Sjbeck 			if (!putline(buf, mci))
1118445f2479Sjbeck 				goto writeerr;
11197c478bd9Sstevel@tonic-gate 		}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		/*
11227c478bd9Sstevel@tonic-gate 		**  Output per-address information.
11237c478bd9Sstevel@tonic-gate 		*/
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
11267c478bd9Sstevel@tonic-gate 		{
11277c478bd9Sstevel@tonic-gate 			char *action;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 			if (QS_IS_BADADDR(q->q_state))
11307c478bd9Sstevel@tonic-gate 			{
11317c478bd9Sstevel@tonic-gate 				/* RFC 1891, 6.2.6 (b) */
11327c478bd9Sstevel@tonic-gate 				if (bitset(QHASNOTIFY, q->q_flags) &&
11337c478bd9Sstevel@tonic-gate 				    !bitset(QPINGONFAILURE, q->q_flags))
11347c478bd9Sstevel@tonic-gate 					continue;
11357c478bd9Sstevel@tonic-gate 				action = "failed";
11367c478bd9Sstevel@tonic-gate 			}
11377c478bd9Sstevel@tonic-gate 			else if (!bitset(QPRIMARY, q->q_flags))
11387c478bd9Sstevel@tonic-gate 				continue;
11397c478bd9Sstevel@tonic-gate 			else if (bitset(QDELIVERED, q->q_flags))
11407c478bd9Sstevel@tonic-gate 			{
11417c478bd9Sstevel@tonic-gate 				if (bitset(QEXPANDED, q->q_flags))
11427c478bd9Sstevel@tonic-gate 					action = "delivered (to mailing list)";
11437c478bd9Sstevel@tonic-gate 				else
11447c478bd9Sstevel@tonic-gate 					action = "delivered (to mailbox)";
11457c478bd9Sstevel@tonic-gate 			}
11467c478bd9Sstevel@tonic-gate 			else if (bitset(QRELAYED, q->q_flags))
11477c478bd9Sstevel@tonic-gate 				action = "relayed (to non-DSN-aware mailer)";
11487c478bd9Sstevel@tonic-gate 			else if (bitset(QEXPANDED, q->q_flags))
11497c478bd9Sstevel@tonic-gate 				action = "expanded (to multi-recipient alias)";
11507c478bd9Sstevel@tonic-gate 			else if (bitset(QDELAYED, q->q_flags))
11517c478bd9Sstevel@tonic-gate 				action = "delayed";
11527c478bd9Sstevel@tonic-gate 			else if (bitset(QBYTRACE, q->q_flags))
11537c478bd9Sstevel@tonic-gate 				action = "relayed (Deliver-By trace mode)";
11547c478bd9Sstevel@tonic-gate 			else if (bitset(QBYNDELAY, q->q_flags))
11557c478bd9Sstevel@tonic-gate 				action = "delayed (Deliver-By notify mode)";
11567c478bd9Sstevel@tonic-gate 			else if (bitset(QBYNRELAY, q->q_flags))
11577c478bd9Sstevel@tonic-gate 				action = "relayed (Deliver-By notify mode)";
11587c478bd9Sstevel@tonic-gate 			else
11597c478bd9Sstevel@tonic-gate 				continue;
11607c478bd9Sstevel@tonic-gate 
1161445f2479Sjbeck 			if (!putline("", mci))
1162445f2479Sjbeck 				goto writeerr;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 			/* Original-Recipient: -- passed from on high */
11657c478bd9Sstevel@tonic-gate 			if (q->q_orcpt != NULL)
11667c478bd9Sstevel@tonic-gate 			{
1167058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
11687c478bd9Sstevel@tonic-gate 						"Original-Recipient: %.800s",
11697c478bd9Sstevel@tonic-gate 						q->q_orcpt);
1170445f2479Sjbeck 				if (!putline(buf, mci))
1171445f2479Sjbeck 					goto writeerr;
11727c478bd9Sstevel@tonic-gate 			}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 			/* Figure out actual recipient */
11757c478bd9Sstevel@tonic-gate 			actual[0] = '\0';
11767c478bd9Sstevel@tonic-gate 			if (q->q_user[0] != '\0')
11777c478bd9Sstevel@tonic-gate 			{
11787c478bd9Sstevel@tonic-gate 				if (q->q_mailer != NULL &&
11797c478bd9Sstevel@tonic-gate 				    q->q_mailer->m_addrtype != NULL)
11807c478bd9Sstevel@tonic-gate 					p = q->q_mailer->m_addrtype;
11817c478bd9Sstevel@tonic-gate 				else
11827c478bd9Sstevel@tonic-gate 					p = "rfc822";
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 				if (sm_strcasecmp(p, "rfc822") == 0 &&
11857c478bd9Sstevel@tonic-gate 				    strchr(q->q_user, '@') == NULL)
11867c478bd9Sstevel@tonic-gate 				{
11877c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(actual,
1188058561cbSjbeck 							   sizeof(actual),
11897c478bd9Sstevel@tonic-gate 							   "%s; %.700s@%.100s",
11907c478bd9Sstevel@tonic-gate 							   p, q->q_user,
11917c478bd9Sstevel@tonic-gate 							   MyHostName);
11927c478bd9Sstevel@tonic-gate 				}
11937c478bd9Sstevel@tonic-gate 				else
11947c478bd9Sstevel@tonic-gate 				{
11957c478bd9Sstevel@tonic-gate 					(void) sm_snprintf(actual,
1196058561cbSjbeck 							   sizeof(actual),
11977c478bd9Sstevel@tonic-gate 							   "%s; %.800s",
11987c478bd9Sstevel@tonic-gate 							   p, q->q_user);
11997c478bd9Sstevel@tonic-gate 				}
12007c478bd9Sstevel@tonic-gate 			}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 			/* Final-Recipient: -- the name from the RCPT command */
12037c478bd9Sstevel@tonic-gate 			if (q->q_finalrcpt == NULL)
12047c478bd9Sstevel@tonic-gate 			{
12057c478bd9Sstevel@tonic-gate 				/* should never happen */
12067c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
12077c478bd9Sstevel@tonic-gate 					  "returntosender: q_finalrcpt is NULL");
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 				/* try to fall back to the actual recipient */
12107c478bd9Sstevel@tonic-gate 				if (actual[0] != '\0')
12117c478bd9Sstevel@tonic-gate 					q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
12127c478bd9Sstevel@tonic-gate 									   actual);
12137c478bd9Sstevel@tonic-gate 			}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 			if (q->q_finalrcpt != NULL)
12167c478bd9Sstevel@tonic-gate 			{
1217058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
12187c478bd9Sstevel@tonic-gate 						   "Final-Recipient: %s",
12197c478bd9Sstevel@tonic-gate 						   q->q_finalrcpt);
1220445f2479Sjbeck 				if (!putline(buf, mci))
1221445f2479Sjbeck 					goto writeerr;
12227c478bd9Sstevel@tonic-gate 			}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 			/* X-Actual-Recipient: -- the real problem address */
12257c478bd9Sstevel@tonic-gate 			if (actual[0] != '\0' &&
12267c478bd9Sstevel@tonic-gate 			    q->q_finalrcpt != NULL &&
12277c478bd9Sstevel@tonic-gate 			    !bitset(PRIV_NOACTUALRECIPIENT, PrivacyFlags) &&
12287c478bd9Sstevel@tonic-gate 			    strcmp(actual, q->q_finalrcpt) != 0)
12297c478bd9Sstevel@tonic-gate 			{
1230058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
12317c478bd9Sstevel@tonic-gate 						   "X-Actual-Recipient: %s",
12327c478bd9Sstevel@tonic-gate 						   actual);
1233445f2479Sjbeck 				if (!putline(buf, mci))
1234445f2479Sjbeck 					goto writeerr;
12357c478bd9Sstevel@tonic-gate 			}
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 			/* Action: -- what happened? */
1238058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Action: ",
12397c478bd9Sstevel@tonic-gate 				action);
1240445f2479Sjbeck 			if (!putline(buf, mci))
1241445f2479Sjbeck 				goto writeerr;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 			/* Status: -- what _really_ happened? */
12447c478bd9Sstevel@tonic-gate 			if (q->q_status != NULL)
12457c478bd9Sstevel@tonic-gate 				p = q->q_status;
12467c478bd9Sstevel@tonic-gate 			else if (QS_IS_BADADDR(q->q_state))
12477c478bd9Sstevel@tonic-gate 				p = "5.0.0";
12487c478bd9Sstevel@tonic-gate 			else if (QS_IS_QUEUEUP(q->q_state))
12497c478bd9Sstevel@tonic-gate 				p = "4.0.0";
12507c478bd9Sstevel@tonic-gate 			else
12517c478bd9Sstevel@tonic-gate 				p = "2.0.0";
1252058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Status: ", p);
1253445f2479Sjbeck 			if (!putline(buf, mci))
1254445f2479Sjbeck 				goto writeerr;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 			/* Remote-MTA: -- who was I talking to? */
12577c478bd9Sstevel@tonic-gate 			if (q->q_statmta != NULL)
12587c478bd9Sstevel@tonic-gate 			{
12597c478bd9Sstevel@tonic-gate 				if (q->q_mailer == NULL ||
12607c478bd9Sstevel@tonic-gate 				    (p = q->q_mailer->m_mtatype) == NULL)
12617c478bd9Sstevel@tonic-gate 					p = "dns";
1262058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
12637c478bd9Sstevel@tonic-gate 						"Remote-MTA: %s; %.800s",
12647c478bd9Sstevel@tonic-gate 						p, q->q_statmta);
12657c478bd9Sstevel@tonic-gate 				p = &buf[strlen(buf) - 1];
12667c478bd9Sstevel@tonic-gate 				if (*p == '.')
12677c478bd9Sstevel@tonic-gate 					*p = '\0';
1268445f2479Sjbeck 				if (!putline(buf, mci))
1269445f2479Sjbeck 					goto writeerr;
12707c478bd9Sstevel@tonic-gate 			}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 			/* Diagnostic-Code: -- actual result from other end */
12737c478bd9Sstevel@tonic-gate 			if (q->q_rstatus != NULL)
12747c478bd9Sstevel@tonic-gate 			{
12753ee0e492Sjbeck 				if (q->q_mailer == NULL ||
12763ee0e492Sjbeck 				    (p = q->q_mailer->m_diagtype) == NULL)
12777c478bd9Sstevel@tonic-gate 					p = "smtp";
1278058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
12797c478bd9Sstevel@tonic-gate 						"Diagnostic-Code: %s; %.800s",
12807c478bd9Sstevel@tonic-gate 						p, q->q_rstatus);
1281445f2479Sjbeck 				if (!putline(buf, mci))
1282445f2479Sjbeck 					goto writeerr;
12837c478bd9Sstevel@tonic-gate 			}
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 			/* Last-Attempt-Date: -- fine granularity */
12867c478bd9Sstevel@tonic-gate 			if (q->q_statdate == (time_t) 0L)
12877c478bd9Sstevel@tonic-gate 				q->q_statdate = curtime();
1288058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2,
12897c478bd9Sstevel@tonic-gate 					"Last-Attempt-Date: ",
12907c478bd9Sstevel@tonic-gate 					arpadate(ctime(&q->q_statdate)));
1291445f2479Sjbeck 			if (!putline(buf, mci))
1292445f2479Sjbeck 				goto writeerr;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 			/* Will-Retry-Until: -- for delayed messages only */
12957c478bd9Sstevel@tonic-gate 			if (QS_IS_QUEUEUP(q->q_state))
12967c478bd9Sstevel@tonic-gate 			{
12977c478bd9Sstevel@tonic-gate 				time_t xdate;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 				xdate = e->e_parent->e_ctime +
13007c478bd9Sstevel@tonic-gate 					TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1301058561cbSjbeck 				(void) sm_strlcpyn(buf, sizeof(buf), 2,
13027c478bd9Sstevel@tonic-gate 					 "Will-Retry-Until: ",
13037c478bd9Sstevel@tonic-gate 					 arpadate(ctime(&xdate)));
1304445f2479Sjbeck 				if (!putline(buf, mci))
1305445f2479Sjbeck 					goto writeerr;
13067c478bd9Sstevel@tonic-gate 			}
13077c478bd9Sstevel@tonic-gate 		}
13087c478bd9Sstevel@tonic-gate 	}
13097c478bd9Sstevel@tonic-gate #endif /* DSN */
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	/*
13127c478bd9Sstevel@tonic-gate 	**  Output text of original message
13137c478bd9Sstevel@tonic-gate 	*/
13147c478bd9Sstevel@tonic-gate 
1315445f2479Sjbeck 	if (!putline("", mci))
1316445f2479Sjbeck 		goto writeerr;
13177c478bd9Sstevel@tonic-gate 	if (bitset(EF_HAS_DF, e->e_parent->e_flags))
13187c478bd9Sstevel@tonic-gate 	{
13197c478bd9Sstevel@tonic-gate 		sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
13207c478bd9Sstevel@tonic-gate 			   !bitset(EF_NO_BODY_RETN, e->e_flags);
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 		if (e->e_msgboundary == NULL)
13237c478bd9Sstevel@tonic-gate 		{
1324445f2479Sjbeck 			if (!putline(
1325445f2479Sjbeck 				sendbody
1326445f2479Sjbeck 				? "   ----- Original message follows -----\n"
1327445f2479Sjbeck 				: "   ----- Message header follows -----\n",
1328445f2479Sjbeck 				mci))
1329445f2479Sjbeck 			{
1330445f2479Sjbeck 				goto writeerr;
1331445f2479Sjbeck 			}
13327c478bd9Sstevel@tonic-gate 		}
13337c478bd9Sstevel@tonic-gate 		else
13347c478bd9Sstevel@tonic-gate 		{
1335058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2, "--",
13367c478bd9Sstevel@tonic-gate 					e->e_msgboundary);
13377c478bd9Sstevel@tonic-gate 
1338445f2479Sjbeck 			if (!putline(buf, mci))
1339445f2479Sjbeck 				goto writeerr;
1340058561cbSjbeck 			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Content-Type: ",
13417c478bd9Sstevel@tonic-gate 					sendbody ? "message/rfc822"
13427c478bd9Sstevel@tonic-gate 						 : "text/rfc822-headers");
1343445f2479Sjbeck 			if (!putline(buf, mci))
1344445f2479Sjbeck 				goto writeerr;
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 			p = hvalue("Content-Transfer-Encoding",
13477c478bd9Sstevel@tonic-gate 				   e->e_parent->e_header);
13487c478bd9Sstevel@tonic-gate 			if (p != NULL && sm_strcasecmp(p, "binary") != 0)
13497c478bd9Sstevel@tonic-gate 				p = NULL;
13507c478bd9Sstevel@tonic-gate 			if (p == NULL &&
13517c478bd9Sstevel@tonic-gate 			    bitset(EF_HAS8BIT, e->e_parent->e_flags))
13527c478bd9Sstevel@tonic-gate 				p = "8bit";
13537c478bd9Sstevel@tonic-gate 			if (p != NULL)
13547c478bd9Sstevel@tonic-gate 			{
1355058561cbSjbeck 				(void) sm_snprintf(buf, sizeof(buf),
13567c478bd9Sstevel@tonic-gate 						"Content-Transfer-Encoding: %s",
13577c478bd9Sstevel@tonic-gate 						p);
1358445f2479Sjbeck 				if (!putline(buf, mci))
1359445f2479Sjbeck 					goto writeerr;
13607c478bd9Sstevel@tonic-gate 			}
13617c478bd9Sstevel@tonic-gate 		}
1362445f2479Sjbeck 		if (!putline("", mci))
1363445f2479Sjbeck 			goto writeerr;
13647c478bd9Sstevel@tonic-gate 		save_errno = errno;
1365445f2479Sjbeck 		if (!putheader(mci, e->e_parent->e_header, e->e_parent,
1366445f2479Sjbeck 				M87F_OUTER))
1367445f2479Sjbeck 			goto writeerr;
13687c478bd9Sstevel@tonic-gate 		errno = save_errno;
13697c478bd9Sstevel@tonic-gate 		if (sendbody)
1370445f2479Sjbeck 		{
1371445f2479Sjbeck 			if (!putbody(mci, e->e_parent, e->e_msgboundary))
1372445f2479Sjbeck 				goto writeerr;
1373445f2479Sjbeck 		}
13747c478bd9Sstevel@tonic-gate 		else if (e->e_msgboundary == NULL)
13757c478bd9Sstevel@tonic-gate 		{
1376445f2479Sjbeck 			if (!putline("", mci) ||
1377445f2479Sjbeck 			    !putline("   ----- Message body suppressed -----",
1378445f2479Sjbeck 					mci))
1379445f2479Sjbeck 			{
1380445f2479Sjbeck 				goto writeerr;
1381445f2479Sjbeck 			}
13827c478bd9Sstevel@tonic-gate 		}
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 	else if (e->e_msgboundary == NULL)
13857c478bd9Sstevel@tonic-gate 	{
1386445f2479Sjbeck 		if (!putline("  ----- No message was collected -----\n", mci))
1387445f2479Sjbeck 			goto writeerr;
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	if (e->e_msgboundary != NULL)
13917c478bd9Sstevel@tonic-gate 	{
1392058561cbSjbeck 		(void) sm_strlcpyn(buf, sizeof(buf), 3, "--", e->e_msgboundary,
13937c478bd9Sstevel@tonic-gate 				   "--");
1394445f2479Sjbeck 		if (!putline("", mci) || !putline(buf, mci))
1395445f2479Sjbeck 			goto writeerr;
13967c478bd9Sstevel@tonic-gate 	}
1397445f2479Sjbeck 	if (!putline("", mci) ||
1398445f2479Sjbeck 	    sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF)
1399445f2479Sjbeck 			goto writeerr;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/*
14027c478bd9Sstevel@tonic-gate 	**  Cleanup and exit
14037c478bd9Sstevel@tonic-gate 	*/
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	if (errno != 0)
1406445f2479Sjbeck 	{
1407445f2479Sjbeck   writeerr:
14087c478bd9Sstevel@tonic-gate 		syserr("errbody: I/O error");
1409445f2479Sjbeck 		return false;
1410445f2479Sjbeck 	}
1411445f2479Sjbeck 	return true;
14127c478bd9Sstevel@tonic-gate }
1413445f2479Sjbeck 
14147c478bd9Sstevel@tonic-gate /*
14157c478bd9Sstevel@tonic-gate **  SMTPTODSN -- convert SMTP to DSN status code
14167c478bd9Sstevel@tonic-gate **
14177c478bd9Sstevel@tonic-gate **	Parameters:
14187c478bd9Sstevel@tonic-gate **		smtpstat -- the smtp status code (e.g., 550).
14197c478bd9Sstevel@tonic-gate **
14207c478bd9Sstevel@tonic-gate **	Returns:
14217c478bd9Sstevel@tonic-gate **		The DSN version of the status code.
14227c478bd9Sstevel@tonic-gate **
14237c478bd9Sstevel@tonic-gate **	Storage Management:
14247c478bd9Sstevel@tonic-gate **		smtptodsn() returns a pointer to a character string literal,
14257c478bd9Sstevel@tonic-gate **		which will remain valid forever, and thus does not need to
14267c478bd9Sstevel@tonic-gate **		be copied.  Current code relies on this property.
14277c478bd9Sstevel@tonic-gate */
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate char *
smtptodsn(smtpstat)14307c478bd9Sstevel@tonic-gate smtptodsn(smtpstat)
14317c478bd9Sstevel@tonic-gate 	int smtpstat;
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate 	if (smtpstat < 0)
14347c478bd9Sstevel@tonic-gate 		return "4.4.2";
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	switch (smtpstat)
14377c478bd9Sstevel@tonic-gate 	{
14387c478bd9Sstevel@tonic-gate 	  case 450:	/* Req mail action not taken: mailbox unavailable */
14397c478bd9Sstevel@tonic-gate 		return "4.2.0";
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	  case 451:	/* Req action aborted: local error in processing */
14427c478bd9Sstevel@tonic-gate 		return "4.3.0";
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	  case 452:	/* Req action not taken: insufficient sys storage */
14457c478bd9Sstevel@tonic-gate 		return "4.3.1";
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	  case 500:	/* Syntax error, command unrecognized */
14487c478bd9Sstevel@tonic-gate 		return "5.5.2";
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	  case 501:	/* Syntax error in parameters or arguments */
14517c478bd9Sstevel@tonic-gate 		return "5.5.4";
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	  case 502:	/* Command not implemented */
14547c478bd9Sstevel@tonic-gate 		return "5.5.1";
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	  case 503:	/* Bad sequence of commands */
14577c478bd9Sstevel@tonic-gate 		return "5.5.1";
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	  case 504:	/* Command parameter not implemented */
14607c478bd9Sstevel@tonic-gate 		return "5.5.4";
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	  case 550:	/* Req mail action not taken: mailbox unavailable */
14637c478bd9Sstevel@tonic-gate 		return "5.2.0";
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	  case 551:	/* User not local; please try <...> */
14667c478bd9Sstevel@tonic-gate 		return "5.1.6";
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	  case 552:	/* Req mail action aborted: exceeded storage alloc */
14697c478bd9Sstevel@tonic-gate 		return "5.2.2";
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	  case 553:	/* Req action not taken: mailbox name not allowed */
14727c478bd9Sstevel@tonic-gate 		return "5.1.0";
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	  case 554:	/* Transaction failed */
14757c478bd9Sstevel@tonic-gate 		return "5.0.0";
14767c478bd9Sstevel@tonic-gate 	}
14777c478bd9Sstevel@tonic-gate 
1478445f2479Sjbeck 	if (REPLYTYPE(smtpstat) == 2)
14797c478bd9Sstevel@tonic-gate 		return "2.0.0";
1480445f2479Sjbeck 	if (REPLYTYPE(smtpstat) == 4)
14817c478bd9Sstevel@tonic-gate 		return "4.0.0";
14827c478bd9Sstevel@tonic-gate 	return "5.0.0";
14837c478bd9Sstevel@tonic-gate }
14847c478bd9Sstevel@tonic-gate /*
14857c478bd9Sstevel@tonic-gate **  XTEXTIFY -- take regular text and turn it into DSN-style xtext
14867c478bd9Sstevel@tonic-gate **
14877c478bd9Sstevel@tonic-gate **	Parameters:
14887c478bd9Sstevel@tonic-gate **		t -- the text to convert.
14897c478bd9Sstevel@tonic-gate **		taboo -- additional characters that must be encoded.
14907c478bd9Sstevel@tonic-gate **
14917c478bd9Sstevel@tonic-gate **	Returns:
14927c478bd9Sstevel@tonic-gate **		The xtext-ified version of the same string.
14937c478bd9Sstevel@tonic-gate */
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate char *
xtextify(t,taboo)14967c478bd9Sstevel@tonic-gate xtextify(t, taboo)
14977c478bd9Sstevel@tonic-gate 	register char *t;
14987c478bd9Sstevel@tonic-gate 	char *taboo;
14997c478bd9Sstevel@tonic-gate {
15007c478bd9Sstevel@tonic-gate 	register char *p;
15017c478bd9Sstevel@tonic-gate 	int l;
15027c478bd9Sstevel@tonic-gate 	int nbogus;
15037c478bd9Sstevel@tonic-gate 	static char *bp = NULL;
15047c478bd9Sstevel@tonic-gate 	static int bplen = 0;
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	if (taboo == NULL)
15077c478bd9Sstevel@tonic-gate 		taboo = "";
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	/* figure out how long this xtext will have to be */
15107c478bd9Sstevel@tonic-gate 	nbogus = l = 0;
15117c478bd9Sstevel@tonic-gate 	for (p = t; *p != '\0'; p++)
15127c478bd9Sstevel@tonic-gate 	{
15137c478bd9Sstevel@tonic-gate 		register int c = (*p & 0xff);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 		/* ASCII dependence here -- this is the way the spec words it */
15167c478bd9Sstevel@tonic-gate 		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
15177c478bd9Sstevel@tonic-gate 		    strchr(taboo, c) != NULL)
15187c478bd9Sstevel@tonic-gate 			nbogus++;
15197c478bd9Sstevel@tonic-gate 		l++;
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 	if (nbogus < 0)
15227c478bd9Sstevel@tonic-gate 	{
15237c478bd9Sstevel@tonic-gate 		/* since nbogus is ssize_t and wrapped, 2 * size_t would wrap */
15247c478bd9Sstevel@tonic-gate 		syserr("!xtextify string too long");
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 	if (nbogus == 0)
15277c478bd9Sstevel@tonic-gate 		return t;
15287c478bd9Sstevel@tonic-gate 	l += nbogus * 2 + 1;
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/* now allocate space if necessary for the new string */
15317c478bd9Sstevel@tonic-gate 	if (l > bplen)
15327c478bd9Sstevel@tonic-gate 	{
15337c478bd9Sstevel@tonic-gate 		if (bp != NULL)
15347c478bd9Sstevel@tonic-gate 			sm_free(bp); /* XXX */
15357c478bd9Sstevel@tonic-gate 		bp = sm_pmalloc_x(l);
15367c478bd9Sstevel@tonic-gate 		bplen = l;
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/* ok, copy the text with byte expansion */
15407c478bd9Sstevel@tonic-gate 	for (p = bp; *t != '\0'; )
15417c478bd9Sstevel@tonic-gate 	{
15427c478bd9Sstevel@tonic-gate 		register int c = (*t++ & 0xff);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 		/* ASCII dependence here -- this is the way the spec words it */
15457c478bd9Sstevel@tonic-gate 		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
15467c478bd9Sstevel@tonic-gate 		    strchr(taboo, c) != NULL)
15477c478bd9Sstevel@tonic-gate 		{
15487c478bd9Sstevel@tonic-gate 			*p++ = '+';
15497c478bd9Sstevel@tonic-gate 			*p++ = "0123456789ABCDEF"[c >> 4];
15507c478bd9Sstevel@tonic-gate 			*p++ = "0123456789ABCDEF"[c & 0xf];
15517c478bd9Sstevel@tonic-gate 		}
15527c478bd9Sstevel@tonic-gate 		else
15537c478bd9Sstevel@tonic-gate 			*p++ = c;
15547c478bd9Sstevel@tonic-gate 	}
15557c478bd9Sstevel@tonic-gate 	*p = '\0';
15567c478bd9Sstevel@tonic-gate 	return bp;
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate /*
15597c478bd9Sstevel@tonic-gate **  XUNTEXTIFY -- take xtext and turn it into plain text
15607c478bd9Sstevel@tonic-gate **
15617c478bd9Sstevel@tonic-gate **	Parameters:
15627c478bd9Sstevel@tonic-gate **		t -- the xtextified text.
15637c478bd9Sstevel@tonic-gate **
15647c478bd9Sstevel@tonic-gate **	Returns:
15657c478bd9Sstevel@tonic-gate **		The decoded text.  No attempt is made to deal with
15667c478bd9Sstevel@tonic-gate **		null strings in the resulting text.
15677c478bd9Sstevel@tonic-gate */
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate char *
xuntextify(t)15707c478bd9Sstevel@tonic-gate xuntextify(t)
15717c478bd9Sstevel@tonic-gate 	register char *t;
15727c478bd9Sstevel@tonic-gate {
15737c478bd9Sstevel@tonic-gate 	register char *p;
15747c478bd9Sstevel@tonic-gate 	int l;
15757c478bd9Sstevel@tonic-gate 	static char *bp = NULL;
15767c478bd9Sstevel@tonic-gate 	static int bplen = 0;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	/* heuristic -- if no plus sign, just return the input */
15797c478bd9Sstevel@tonic-gate 	if (strchr(t, '+') == NULL)
15807c478bd9Sstevel@tonic-gate 		return t;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	/* xtext is always longer than decoded text */
15837c478bd9Sstevel@tonic-gate 	l = strlen(t);
15847c478bd9Sstevel@tonic-gate 	if (l > bplen)
15857c478bd9Sstevel@tonic-gate 	{
15867c478bd9Sstevel@tonic-gate 		if (bp != NULL)
15877c478bd9Sstevel@tonic-gate 			sm_free(bp); /* XXX */
15887c478bd9Sstevel@tonic-gate 		bp = xalloc(l);
15897c478bd9Sstevel@tonic-gate 		bplen = l;
15907c478bd9Sstevel@tonic-gate 	}
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	/* ok, copy the text with byte compression */
15937c478bd9Sstevel@tonic-gate 	for (p = bp; *t != '\0'; t++)
15947c478bd9Sstevel@tonic-gate 	{
15957c478bd9Sstevel@tonic-gate 		register int c = *t & 0xff;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		if (c != '+')
15987c478bd9Sstevel@tonic-gate 		{
15997c478bd9Sstevel@tonic-gate 			*p++ = c;
16007c478bd9Sstevel@tonic-gate 			continue;
16017c478bd9Sstevel@tonic-gate 		}
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 		c = *++t & 0xff;
16047c478bd9Sstevel@tonic-gate 		if (!isascii(c) || !isxdigit(c))
16057c478bd9Sstevel@tonic-gate 		{
16067c478bd9Sstevel@tonic-gate 			/* error -- first digit is not hex */
16077c478bd9Sstevel@tonic-gate 			usrerr("bogus xtext: +%c", c);
16087c478bd9Sstevel@tonic-gate 			t--;
16097c478bd9Sstevel@tonic-gate 			continue;
16107c478bd9Sstevel@tonic-gate 		}
16117c478bd9Sstevel@tonic-gate 		if (isdigit(c))
16127c478bd9Sstevel@tonic-gate 			c -= '0';
16137c478bd9Sstevel@tonic-gate 		else if (isupper(c))
16147c478bd9Sstevel@tonic-gate 			c -= 'A' - 10;
16157c478bd9Sstevel@tonic-gate 		else
16167c478bd9Sstevel@tonic-gate 			c -= 'a' - 10;
16177c478bd9Sstevel@tonic-gate 		*p = c << 4;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 		c = *++t & 0xff;
16207c478bd9Sstevel@tonic-gate 		if (!isascii(c) || !isxdigit(c))
16217c478bd9Sstevel@tonic-gate 		{
16227c478bd9Sstevel@tonic-gate 			/* error -- second digit is not hex */
16237c478bd9Sstevel@tonic-gate 			usrerr("bogus xtext: +%x%c", *p >> 4, c);
16247c478bd9Sstevel@tonic-gate 			t--;
16257c478bd9Sstevel@tonic-gate 			continue;
16267c478bd9Sstevel@tonic-gate 		}
16277c478bd9Sstevel@tonic-gate 		if (isdigit(c))
16287c478bd9Sstevel@tonic-gate 			c -= '0';
16297c478bd9Sstevel@tonic-gate 		else if (isupper(c))
16307c478bd9Sstevel@tonic-gate 			c -= 'A' - 10;
16317c478bd9Sstevel@tonic-gate 		else
16327c478bd9Sstevel@tonic-gate 			c -= 'a' - 10;
16337c478bd9Sstevel@tonic-gate 		*p++ |= c;
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate 	*p = '\0';
16367c478bd9Sstevel@tonic-gate 	return bp;
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate /*
16397c478bd9Sstevel@tonic-gate **  XTEXTOK -- check if a string is legal xtext
16407c478bd9Sstevel@tonic-gate **
16417c478bd9Sstevel@tonic-gate **	Xtext is used in Delivery Status Notifications.  The spec was
16427c478bd9Sstevel@tonic-gate **	taken from RFC 1891, ``SMTP Service Extension for Delivery
16437c478bd9Sstevel@tonic-gate **	Status Notifications''.
16447c478bd9Sstevel@tonic-gate **
16457c478bd9Sstevel@tonic-gate **	Parameters:
16467c478bd9Sstevel@tonic-gate **		s -- the string to check.
16477c478bd9Sstevel@tonic-gate **
16487c478bd9Sstevel@tonic-gate **	Returns:
16497c478bd9Sstevel@tonic-gate **		true -- if 's' is legal xtext.
16507c478bd9Sstevel@tonic-gate **		false -- if it has any illegal characters in it.
16517c478bd9Sstevel@tonic-gate */
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate bool
xtextok(s)16547c478bd9Sstevel@tonic-gate xtextok(s)
16557c478bd9Sstevel@tonic-gate 	char *s;
16567c478bd9Sstevel@tonic-gate {
16577c478bd9Sstevel@tonic-gate 	int c;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	while ((c = *s++) != '\0')
16607c478bd9Sstevel@tonic-gate 	{
16617c478bd9Sstevel@tonic-gate 		if (c == '+')
16627c478bd9Sstevel@tonic-gate 		{
16637c478bd9Sstevel@tonic-gate 			c = *s++;
16647c478bd9Sstevel@tonic-gate 			if (!isascii(c) || !isxdigit(c))
16657c478bd9Sstevel@tonic-gate 				return false;
16667c478bd9Sstevel@tonic-gate 			c = *s++;
16677c478bd9Sstevel@tonic-gate 			if (!isascii(c) || !isxdigit(c))
16687c478bd9Sstevel@tonic-gate 				return false;
16697c478bd9Sstevel@tonic-gate 		}
16707c478bd9Sstevel@tonic-gate 		else if (c < '!' || c > '~' || c == '=')
16717c478bd9Sstevel@tonic-gate 			return false;
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 	return true;
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate /*
16767c478bd9Sstevel@tonic-gate **  PRUNEROUTE -- prune an RFC-822 source route
16777c478bd9Sstevel@tonic-gate **
16787c478bd9Sstevel@tonic-gate **	Trims down a source route to the last internet-registered hop.
16797c478bd9Sstevel@tonic-gate **	This is encouraged by RFC 1123 section 5.3.3.
16807c478bd9Sstevel@tonic-gate **
16817c478bd9Sstevel@tonic-gate **	Parameters:
16827c478bd9Sstevel@tonic-gate **		addr -- the address
16837c478bd9Sstevel@tonic-gate **
16847c478bd9Sstevel@tonic-gate **	Returns:
16857c478bd9Sstevel@tonic-gate **		true -- address was modified
16867c478bd9Sstevel@tonic-gate **		false -- address could not be pruned
16877c478bd9Sstevel@tonic-gate **
16887c478bd9Sstevel@tonic-gate **	Side Effects:
16897c478bd9Sstevel@tonic-gate **		modifies addr in-place
16907c478bd9Sstevel@tonic-gate */
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate static bool
pruneroute(addr)16937c478bd9Sstevel@tonic-gate pruneroute(addr)
16947c478bd9Sstevel@tonic-gate 	char *addr;
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate #if NAMED_BIND
16977c478bd9Sstevel@tonic-gate 	char *start, *at, *comma;
16987c478bd9Sstevel@tonic-gate 	char c;
16997c478bd9Sstevel@tonic-gate 	int braclev;
17007c478bd9Sstevel@tonic-gate 	int rcode;
17017c478bd9Sstevel@tonic-gate 	int i;
17027c478bd9Sstevel@tonic-gate 	char hostbuf[BUFSIZ];
17037c478bd9Sstevel@tonic-gate 	char *mxhosts[MAXMXHOSTS + 1];
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	/* check to see if this is really a route-addr */
17067c478bd9Sstevel@tonic-gate 	if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
17077c478bd9Sstevel@tonic-gate 		return false;
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	/*
17107c478bd9Sstevel@tonic-gate 	**  Can't simply find the first ':' is the address might be in the
17117c478bd9Sstevel@tonic-gate 	**  form:  "<@[IPv6:::1]:user@host>" and the first ':' in inside
17127c478bd9Sstevel@tonic-gate 	**  the IPv6 address.
17137c478bd9Sstevel@tonic-gate 	*/
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	start = addr;
17167c478bd9Sstevel@tonic-gate 	braclev = 0;
17177c478bd9Sstevel@tonic-gate 	while (*start != '\0')
17187c478bd9Sstevel@tonic-gate 	{
17197c478bd9Sstevel@tonic-gate 		if (*start == ':' && braclev <= 0)
17207c478bd9Sstevel@tonic-gate 			break;
17217c478bd9Sstevel@tonic-gate 		else if (*start == '[')
17227c478bd9Sstevel@tonic-gate 			braclev++;
17237c478bd9Sstevel@tonic-gate 		else if (*start == ']' && braclev > 0)
17247c478bd9Sstevel@tonic-gate 			braclev--;
17257c478bd9Sstevel@tonic-gate 		start++;
17267c478bd9Sstevel@tonic-gate 	}
17277c478bd9Sstevel@tonic-gate 	if (braclev > 0 || *start != ':')
17287c478bd9Sstevel@tonic-gate 		return false;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	at = strrchr(addr, '@');
17317c478bd9Sstevel@tonic-gate 	if (at == NULL || at < start)
17327c478bd9Sstevel@tonic-gate 		return false;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	/* slice off the angle brackets */
17357c478bd9Sstevel@tonic-gate 	i = strlen(at + 1);
1736058561cbSjbeck 	if (i >= sizeof(hostbuf))
17377c478bd9Sstevel@tonic-gate 		return false;
1738058561cbSjbeck 	(void) sm_strlcpy(hostbuf, at + 1, sizeof(hostbuf));
17397c478bd9Sstevel@tonic-gate 	hostbuf[i - 1] = '\0';
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	while (start != NULL)
17427c478bd9Sstevel@tonic-gate 	{
17437c478bd9Sstevel@tonic-gate 		if (getmxrr(hostbuf, mxhosts, NULL, false,
17447c478bd9Sstevel@tonic-gate 			    &rcode, true, NULL) > 0)
17457c478bd9Sstevel@tonic-gate 		{
17467c478bd9Sstevel@tonic-gate 			(void) sm_strlcpy(addr + 1, start + 1,
17477c478bd9Sstevel@tonic-gate 					  strlen(addr) - 1);
17487c478bd9Sstevel@tonic-gate 			return true;
17497c478bd9Sstevel@tonic-gate 		}
17507c478bd9Sstevel@tonic-gate 		c = *start;
17517c478bd9Sstevel@tonic-gate 		*start = '\0';
17527c478bd9Sstevel@tonic-gate 		comma = strrchr(addr, ',');
17537c478bd9Sstevel@tonic-gate 		if (comma != NULL && comma[1] == '@' &&
1754058561cbSjbeck 		    strlen(comma + 2) < sizeof(hostbuf))
1755058561cbSjbeck 			(void) sm_strlcpy(hostbuf, comma + 2, sizeof(hostbuf));
17567c478bd9Sstevel@tonic-gate 		else
17577c478bd9Sstevel@tonic-gate 			comma = NULL;
17587c478bd9Sstevel@tonic-gate 		*start = c;
17597c478bd9Sstevel@tonic-gate 		start = comma;
17607c478bd9Sstevel@tonic-gate 	}
17617c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */
17627c478bd9Sstevel@tonic-gate 	return false;
17637c478bd9Sstevel@tonic-gate }
1764