xref: /freebsd/contrib/sendmail/src/err.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1c2aa98e2SPeter Wemm /*
25b0945b5SGregory Neil Shapiro  * Copyright (c) 1998-2003, 2010, 2015 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
1512ed1c7cSGregory Neil Shapiro 
164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: err.c,v 8.206 2013-11-22 20:51:55 ca Exp $")
17c2aa98e2SPeter Wemm 
1812ed1c7cSGregory Neil Shapiro #if LDAPMAP
193299c2f1SGregory Neil Shapiro # include <lber.h>
203299c2f1SGregory Neil Shapiro # include <ldap.h>			/* for LDAP error codes */
215b0945b5SGregory Neil Shapiro #endif
22*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
23*2fb4f839SGregory Neil Shapiro # include <sm/sendmail.h>
24*2fb4f839SGregory Neil Shapiro #endif
253299c2f1SGregory Neil Shapiro 
263299c2f1SGregory Neil Shapiro static void	putoutmsg __P((char *, bool, bool));
273299c2f1SGregory Neil Shapiro static void	puterrmsg __P((char *));
283299c2f1SGregory Neil Shapiro static char	*fmtmsg __P((char *, const char *, const char *, const char *,
293299c2f1SGregory Neil Shapiro 			     int, const char *, va_list));
30c2aa98e2SPeter Wemm 
31c2aa98e2SPeter Wemm /*
3212ed1c7cSGregory Neil Shapiro **  FATAL_ERROR -- handle a fatal exception
3312ed1c7cSGregory Neil Shapiro **
3412ed1c7cSGregory Neil Shapiro **	This function is installed as the default exception handler
3512ed1c7cSGregory Neil Shapiro **	in the main sendmail process, and in all child processes
3612ed1c7cSGregory Neil Shapiro **	that we create.  Its job is to handle exceptions that are not
3712ed1c7cSGregory Neil Shapiro **	handled at a lower level.
3812ed1c7cSGregory Neil Shapiro **
3912ed1c7cSGregory Neil Shapiro **	The theory is that unhandled exceptions will be 'fatal' class
4012ed1c7cSGregory Neil Shapiro **	exceptions (with an "F:" prefix), such as the out-of-memory
4112ed1c7cSGregory Neil Shapiro **	exception "F:sm.heap".  As such, they are handled by exiting
4212ed1c7cSGregory Neil Shapiro **	the process in exactly the same way that xalloc() in Sendmail 8.10
4312ed1c7cSGregory Neil Shapiro **	exits the process when it fails due to lack of memory:
4412ed1c7cSGregory Neil Shapiro **	we call syserr with a message beginning with "!".
4512ed1c7cSGregory Neil Shapiro **
4612ed1c7cSGregory Neil Shapiro **	Parameters:
4712ed1c7cSGregory Neil Shapiro **		exc -- exception which is terminating this process
4812ed1c7cSGregory Neil Shapiro **
4912ed1c7cSGregory Neil Shapiro **	Returns:
5012ed1c7cSGregory Neil Shapiro **		none
5112ed1c7cSGregory Neil Shapiro */
5212ed1c7cSGregory Neil Shapiro 
5312ed1c7cSGregory Neil Shapiro void
fatal_error(exc)5412ed1c7cSGregory Neil Shapiro fatal_error(exc)
5512ed1c7cSGregory Neil Shapiro 	SM_EXC_T *exc;
5612ed1c7cSGregory Neil Shapiro {
5712ed1c7cSGregory Neil Shapiro 	static char buf[256];
5812ed1c7cSGregory Neil Shapiro 	SM_FILE_T f;
5912ed1c7cSGregory Neil Shapiro 
6012ed1c7cSGregory Neil Shapiro 	/*
6112ed1c7cSGregory Neil Shapiro 	**  This function may be called when the heap is exhausted.
6212ed1c7cSGregory Neil Shapiro 	**  The following code writes the message for 'exc' into our
6312ed1c7cSGregory Neil Shapiro 	**  static buffer without allocating memory or raising exceptions.
6412ed1c7cSGregory Neil Shapiro 	*/
6512ed1c7cSGregory Neil Shapiro 
6612ed1c7cSGregory Neil Shapiro 	sm_strio_init(&f, buf, sizeof(buf));
6712ed1c7cSGregory Neil Shapiro 	sm_exc_write(exc, &f);
6812ed1c7cSGregory Neil Shapiro 	(void) sm_io_flush(&f, SM_TIME_DEFAULT);
6912ed1c7cSGregory Neil Shapiro 
7012ed1c7cSGregory Neil Shapiro 	/*
7112ed1c7cSGregory Neil Shapiro 	**  Terminate the process after logging an error and cleaning up.
7212ed1c7cSGregory Neil Shapiro 	**  Problems:
7312ed1c7cSGregory Neil Shapiro 	**  - syserr decides what class of error this is by looking at errno.
7412ed1c7cSGregory Neil Shapiro 	**    That's no good; we should look at the exc structure.
7512ed1c7cSGregory Neil Shapiro 	**  - The cleanup code should be moved out of syserr
7612ed1c7cSGregory Neil Shapiro 	**    and into individual exception handlers
7712ed1c7cSGregory Neil Shapiro 	**    that are part of the module they clean up after.
7812ed1c7cSGregory Neil Shapiro 	*/
7912ed1c7cSGregory Neil Shapiro 
8012ed1c7cSGregory Neil Shapiro 	errno = ENOMEM;
8112ed1c7cSGregory Neil Shapiro 	syserr("!%s", buf);
8212ed1c7cSGregory Neil Shapiro }
8312ed1c7cSGregory Neil Shapiro 
8412ed1c7cSGregory Neil Shapiro /*
85c2aa98e2SPeter Wemm **  SYSERR -- Print error message.
86c2aa98e2SPeter Wemm **
8712ed1c7cSGregory Neil Shapiro **	Prints an error message via sm_io_printf to the diagnostic output.
88c2aa98e2SPeter Wemm **
89c2aa98e2SPeter Wemm **	If the first character of the syserr message is `!' it will
90c2aa98e2SPeter Wemm **	log this as an ALERT message and exit immediately.  This can
91c2aa98e2SPeter Wemm **	leave queue files in an indeterminate state, so it should not
92c2aa98e2SPeter Wemm **	be used lightly.
93c2aa98e2SPeter Wemm **
9412ed1c7cSGregory Neil Shapiro **	If the first character of the syserr message is '!' or '@'
9512ed1c7cSGregory Neil Shapiro **	then syserr knows that the process is about to be terminated,
9612ed1c7cSGregory Neil Shapiro **	so the SMTP reply code defaults to 421.  Otherwise, the
9712ed1c7cSGregory Neil Shapiro **	reply code defaults to 451 or 554, depending on errno.
9812ed1c7cSGregory Neil Shapiro **
99c2aa98e2SPeter Wemm **	Parameters:
100da7d7b9cSGregory Neil Shapiro **		fmt -- the format string.  An optional '!', '@', or '+',
10112ed1c7cSGregory Neil Shapiro **			followed by an optional three-digit SMTP
10212ed1c7cSGregory Neil Shapiro **			reply code, followed by message text.
103c2aa98e2SPeter Wemm **		(others) -- parameters
104c2aa98e2SPeter Wemm **
105c2aa98e2SPeter Wemm **	Returns:
106c2aa98e2SPeter Wemm **		none
10712ed1c7cSGregory Neil Shapiro **		Raises E:mta.quickabort if QuickAbort is set.
108c2aa98e2SPeter Wemm **
109c2aa98e2SPeter Wemm **	Side Effects:
110c2aa98e2SPeter Wemm **		increments Errors.
111c2aa98e2SPeter Wemm **		sets ExitStat.
112c2aa98e2SPeter Wemm */
113c2aa98e2SPeter Wemm 
114c2aa98e2SPeter Wemm char		MsgBuf[BUFSIZ*2];	/* text of most recent message */
115951742c4SGregory Neil Shapiro static char	HeldMessageBuf[sizeof(MsgBuf)];	/* for held messages */
116c2aa98e2SPeter Wemm 
117c2aa98e2SPeter Wemm void
118c2aa98e2SPeter Wemm /*VARARGS1*/
119c2aa98e2SPeter Wemm #ifdef __STDC__
syserr(const char * fmt,...)120c2aa98e2SPeter Wemm syserr(const char *fmt, ...)
1213299c2f1SGregory Neil Shapiro #else /* __STDC__ */
122c2aa98e2SPeter Wemm syserr(fmt, va_alist)
123c2aa98e2SPeter Wemm 	const char *fmt;
124c2aa98e2SPeter Wemm 	va_dcl
1253299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
126c2aa98e2SPeter Wemm {
127c2aa98e2SPeter Wemm 	register char *p;
1283299c2f1SGregory Neil Shapiro 	int save_errno = errno;
129da7d7b9cSGregory Neil Shapiro 	bool panic, exiting, keep;
1303299c2f1SGregory Neil Shapiro 	char *user;
1313299c2f1SGregory Neil Shapiro 	char *enhsc;
1323299c2f1SGregory Neil Shapiro 	char *errtxt;
133c2aa98e2SPeter Wemm 	struct passwd *pw;
134c2aa98e2SPeter Wemm 	char ubuf[80];
13512ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
136c2aa98e2SPeter Wemm 
137da7d7b9cSGregory Neil Shapiro 	panic = exiting = keep = false;
13812ed1c7cSGregory Neil Shapiro 	switch (*fmt)
139c2aa98e2SPeter Wemm 	{
14012ed1c7cSGregory Neil Shapiro 	  case '!':
14112ed1c7cSGregory Neil Shapiro 		++fmt;
142da7d7b9cSGregory Neil Shapiro 		panic = exiting = true;
14312ed1c7cSGregory Neil Shapiro 		break;
14412ed1c7cSGregory Neil Shapiro 	  case '@':
14512ed1c7cSGregory Neil Shapiro 		++fmt;
14612ed1c7cSGregory Neil Shapiro 		exiting = true;
14712ed1c7cSGregory Neil Shapiro 		break;
148da7d7b9cSGregory Neil Shapiro 	  case '+':
149da7d7b9cSGregory Neil Shapiro 		++fmt;
150da7d7b9cSGregory Neil Shapiro 		keep = true;
151da7d7b9cSGregory Neil Shapiro 		break;
15212ed1c7cSGregory Neil Shapiro 	  default:
15312ed1c7cSGregory Neil Shapiro 		break;
154c2aa98e2SPeter Wemm 	}
155c2aa98e2SPeter Wemm 
156c2aa98e2SPeter Wemm 	/* format and output the error message */
15712ed1c7cSGregory Neil Shapiro 	if (exiting)
15812ed1c7cSGregory Neil Shapiro 	{
15912ed1c7cSGregory Neil Shapiro 		/*
16012ed1c7cSGregory Neil Shapiro 		**  Since we are terminating the process,
16112ed1c7cSGregory Neil Shapiro 		**  we are aborting the entire SMTP session,
16212ed1c7cSGregory Neil Shapiro 		**  rather than just the current transaction.
16312ed1c7cSGregory Neil Shapiro 		*/
16412ed1c7cSGregory Neil Shapiro 
16512ed1c7cSGregory Neil Shapiro 		p = "421";
16612ed1c7cSGregory Neil Shapiro 		enhsc = "4.0.0";
16712ed1c7cSGregory Neil Shapiro 	}
16812ed1c7cSGregory Neil Shapiro 	else if (save_errno == 0)
1693299c2f1SGregory Neil Shapiro 	{
170c2aa98e2SPeter Wemm 		p = "554";
1713299c2f1SGregory Neil Shapiro 		enhsc = "5.0.0";
1723299c2f1SGregory Neil Shapiro 	}
173c2aa98e2SPeter Wemm 	else
1743299c2f1SGregory Neil Shapiro 	{
175c2aa98e2SPeter Wemm 		p = "451";
1763299c2f1SGregory Neil Shapiro 		enhsc = "4.0.0";
1773299c2f1SGregory Neil Shapiro 	}
17812ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
1793299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
18012ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
181c2aa98e2SPeter Wemm 	puterrmsg(MsgBuf);
182c2aa98e2SPeter Wemm 
183c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
184da7d7b9cSGregory Neil Shapiro 	if (!panic && CurEnv != NULL && (!keep || CurEnv->e_message == NULL))
185c2aa98e2SPeter Wemm 	{
18612ed1c7cSGregory Neil Shapiro 		char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
18712ed1c7cSGregory Neil Shapiro 
18812ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
189c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
19012ed1c7cSGregory Neil Shapiro 		CurEnv->e_message = nmsg;
191c2aa98e2SPeter Wemm 	}
192c2aa98e2SPeter Wemm 
193c2aa98e2SPeter Wemm 	/* determine exit status if not already set */
194c2aa98e2SPeter Wemm 	if (ExitStat == EX_OK)
195c2aa98e2SPeter Wemm 	{
1963299c2f1SGregory Neil Shapiro 		if (save_errno == 0)
197c2aa98e2SPeter Wemm 			ExitStat = EX_SOFTWARE;
198c2aa98e2SPeter Wemm 		else
199c2aa98e2SPeter Wemm 			ExitStat = EX_OSERR;
200c2aa98e2SPeter Wemm 		if (tTd(54, 1))
20112ed1c7cSGregory Neil Shapiro 			sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
202c2aa98e2SPeter Wemm 	}
203c2aa98e2SPeter Wemm 
204c0c4794dSGregory Neil Shapiro 	pw = sm_getpwuid(RealUid);
205c2aa98e2SPeter Wemm 	if (pw != NULL)
2063299c2f1SGregory Neil Shapiro 		user = pw->pw_name;
207c2aa98e2SPeter Wemm 	else
208c2aa98e2SPeter Wemm 	{
2093299c2f1SGregory Neil Shapiro 		user = ubuf;
210951742c4SGregory Neil Shapiro 		(void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid);
211c2aa98e2SPeter Wemm 	}
212c2aa98e2SPeter Wemm 
213c2aa98e2SPeter Wemm 	if (LogLevel > 0)
214c2aa98e2SPeter Wemm 		sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
215c2aa98e2SPeter Wemm 			  CurEnv == NULL ? NOQID : CurEnv->e_id,
216c2aa98e2SPeter Wemm 			  "SYSERR(%s): %.900s",
2173299c2f1SGregory Neil Shapiro 			  user, errtxt);
2183299c2f1SGregory Neil Shapiro 	switch (save_errno)
219c2aa98e2SPeter Wemm 	{
220c2aa98e2SPeter Wemm 	  case EBADF:
221c2aa98e2SPeter Wemm 	  case ENFILE:
222c2aa98e2SPeter Wemm 	  case EMFILE:
223c2aa98e2SPeter Wemm 	  case ENOTTY:
224c2aa98e2SPeter Wemm #ifdef EFBIG
225c2aa98e2SPeter Wemm 	  case EFBIG:
2265b0945b5SGregory Neil Shapiro #endif
227c2aa98e2SPeter Wemm #ifdef ESPIPE
228c2aa98e2SPeter Wemm 	  case ESPIPE:
2295b0945b5SGregory Neil Shapiro #endif
230c2aa98e2SPeter Wemm #ifdef EPIPE
231c2aa98e2SPeter Wemm 	  case EPIPE:
2325b0945b5SGregory Neil Shapiro #endif
233c2aa98e2SPeter Wemm #ifdef ENOBUFS
234c2aa98e2SPeter Wemm 	  case ENOBUFS:
2355b0945b5SGregory Neil Shapiro #endif
236c2aa98e2SPeter Wemm #ifdef ESTALE
237c2aa98e2SPeter Wemm 	  case ESTALE:
2385b0945b5SGregory Neil Shapiro #endif
23912ed1c7cSGregory Neil Shapiro 		printopenfds(true);
240bfb62e91SGregory Neil Shapiro 		mci_dump_all(smioout, true);
241c2aa98e2SPeter Wemm 		break;
242c2aa98e2SPeter Wemm 	}
243c2aa98e2SPeter Wemm 	if (panic)
244c2aa98e2SPeter Wemm 	{
24512ed1c7cSGregory Neil Shapiro #if XLA
246c2aa98e2SPeter Wemm 		xla_all_end();
2475b0945b5SGregory Neil Shapiro #endif
2483299c2f1SGregory Neil Shapiro 		sync_queue_time();
249c2aa98e2SPeter Wemm 		if (tTd(0, 1))
250c2aa98e2SPeter Wemm 			abort();
251c2aa98e2SPeter Wemm 		exit(EX_OSERR);
252c2aa98e2SPeter Wemm 	}
253c2aa98e2SPeter Wemm 	errno = 0;
254c2aa98e2SPeter Wemm 	if (QuickAbort)
25512ed1c7cSGregory Neil Shapiro 		sm_exc_raisenew_x(&EtypeQuickAbort, 2);
256c2aa98e2SPeter Wemm }
2575b0945b5SGregory Neil Shapiro 
25812ed1c7cSGregory Neil Shapiro /*
259c2aa98e2SPeter Wemm **  USRERR -- Signal user error.
260c2aa98e2SPeter Wemm **
261c2aa98e2SPeter Wemm **	This is much like syserr except it is for user errors.
262c2aa98e2SPeter Wemm **
263c2aa98e2SPeter Wemm **	Parameters:
264c2aa98e2SPeter Wemm **		fmt -- the format string.  If it does not begin with
26512ed1c7cSGregory Neil Shapiro **			a three-digit SMTP reply code, 550 is assumed.
26612ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf strings
267c2aa98e2SPeter Wemm **
268c2aa98e2SPeter Wemm **	Returns:
269c2aa98e2SPeter Wemm **		none
27012ed1c7cSGregory Neil Shapiro **		Raises E:mta.quickabort if QuickAbort is set.
271c2aa98e2SPeter Wemm **
272c2aa98e2SPeter Wemm **	Side Effects:
273c2aa98e2SPeter Wemm **		increments Errors.
274c2aa98e2SPeter Wemm */
275c2aa98e2SPeter Wemm 
276c2aa98e2SPeter Wemm /*VARARGS1*/
277c2aa98e2SPeter Wemm void
278c2aa98e2SPeter Wemm #ifdef __STDC__
usrerr(const char * fmt,...)279c2aa98e2SPeter Wemm usrerr(const char *fmt, ...)
2803299c2f1SGregory Neil Shapiro #else /* __STDC__ */
281c2aa98e2SPeter Wemm usrerr(fmt, va_alist)
282c2aa98e2SPeter Wemm 	const char *fmt;
283c2aa98e2SPeter Wemm 	va_dcl
2843299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
285c2aa98e2SPeter Wemm {
2863299c2f1SGregory Neil Shapiro 	char *enhsc;
2873299c2f1SGregory Neil Shapiro 	char *errtxt;
28812ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
289c2aa98e2SPeter Wemm 
2903299c2f1SGregory Neil Shapiro 	if (fmt[0] == '5' || fmt[0] == '6')
2913299c2f1SGregory Neil Shapiro 		enhsc = "5.0.0";
2923299c2f1SGregory Neil Shapiro 	else if (fmt[0] == '4' || fmt[0] == '8')
2933299c2f1SGregory Neil Shapiro 		enhsc = "4.0.0";
2943299c2f1SGregory Neil Shapiro 	else if (fmt[0] == '2')
2953299c2f1SGregory Neil Shapiro 		enhsc = "2.0.0";
2963299c2f1SGregory Neil Shapiro 	else
2973299c2f1SGregory Neil Shapiro 		enhsc = NULL;
29812ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
29912ed1c7cSGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
30012ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
3013299c2f1SGregory Neil Shapiro 
302c2aa98e2SPeter Wemm 	if (SuprErrs)
303c2aa98e2SPeter Wemm 		return;
304c2aa98e2SPeter Wemm 
305c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
306c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
307c2aa98e2SPeter Wemm 	{
308c2aa98e2SPeter Wemm 	  case '4':
309c2aa98e2SPeter Wemm 	  case '8':
310c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
311c2aa98e2SPeter Wemm 			break;
312c2aa98e2SPeter Wemm 
3133299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
314c2aa98e2SPeter Wemm 
315c2aa98e2SPeter Wemm 	  case '5':
316c2aa98e2SPeter Wemm 	  case '6':
31712ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
318c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
319c2aa98e2SPeter Wemm 		if (MsgBuf[0] == '6')
320c2aa98e2SPeter Wemm 		{
321c2aa98e2SPeter Wemm 			char buf[MAXLINE];
322c2aa98e2SPeter Wemm 
323951742c4SGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf),
32412ed1c7cSGregory Neil Shapiro 					   "Postmaster warning: %.*s",
325951742c4SGregory Neil Shapiro 					   (int) sizeof(buf) - 22, errtxt);
32612ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
32712ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, buf);
328c2aa98e2SPeter Wemm 		}
329c2aa98e2SPeter Wemm 		else
330c2aa98e2SPeter Wemm 		{
33112ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
33212ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
333c2aa98e2SPeter Wemm 		}
334c2aa98e2SPeter Wemm 		break;
335c2aa98e2SPeter Wemm 	}
336c2aa98e2SPeter Wemm 
337c2aa98e2SPeter Wemm 	puterrmsg(MsgBuf);
338c2aa98e2SPeter Wemm 	if (LogLevel > 3 && LogUsrErrs)
3393299c2f1SGregory Neil Shapiro 		sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
3403299c2f1SGregory Neil Shapiro 	if (QuickAbort)
34112ed1c7cSGregory Neil Shapiro 		sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3423299c2f1SGregory Neil Shapiro }
3435b0945b5SGregory Neil Shapiro 
34412ed1c7cSGregory Neil Shapiro /*
3453299c2f1SGregory Neil Shapiro **  USRERRENH -- Signal user error.
3463299c2f1SGregory Neil Shapiro **
3473299c2f1SGregory Neil Shapiro **	Same as usrerr but with enhanced status code.
3483299c2f1SGregory Neil Shapiro **
3493299c2f1SGregory Neil Shapiro **	Parameters:
3503299c2f1SGregory Neil Shapiro **		enhsc -- the enhanced status code.
3513299c2f1SGregory Neil Shapiro **		fmt -- the format string.  If it does not begin with
35212ed1c7cSGregory Neil Shapiro **			a three-digit SMTP reply code, 550 is assumed.
35312ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf strings
3543299c2f1SGregory Neil Shapiro **
3553299c2f1SGregory Neil Shapiro **	Returns:
3563299c2f1SGregory Neil Shapiro **		none
35712ed1c7cSGregory Neil Shapiro **		Raises E:mta.quickabort if QuickAbort is set.
3583299c2f1SGregory Neil Shapiro **
3593299c2f1SGregory Neil Shapiro **	Side Effects:
3603299c2f1SGregory Neil Shapiro **		increments Errors.
3613299c2f1SGregory Neil Shapiro */
3623299c2f1SGregory Neil Shapiro 
3636f9c8e5bSGregory Neil Shapiro /*VARARGS2*/
3643299c2f1SGregory Neil Shapiro void
3653299c2f1SGregory Neil Shapiro #ifdef __STDC__
usrerrenh(char * enhsc,const char * fmt,...)3663299c2f1SGregory Neil Shapiro usrerrenh(char *enhsc, const char *fmt, ...)
3673299c2f1SGregory Neil Shapiro #else /* __STDC__ */
3683299c2f1SGregory Neil Shapiro usrerrenh(enhsc, fmt, va_alist)
3693299c2f1SGregory Neil Shapiro 	char *enhsc;
3703299c2f1SGregory Neil Shapiro 	const char *fmt;
3713299c2f1SGregory Neil Shapiro 	va_dcl
3723299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
3733299c2f1SGregory Neil Shapiro {
3743299c2f1SGregory Neil Shapiro 	char *errtxt;
37512ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
3763299c2f1SGregory Neil Shapiro 
377*2fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(enhsc))
3783299c2f1SGregory Neil Shapiro 	{
3793299c2f1SGregory Neil Shapiro 		if (fmt[0] == '5' || fmt[0] == '6')
3803299c2f1SGregory Neil Shapiro 			enhsc = "5.0.0";
3813299c2f1SGregory Neil Shapiro 		else if (fmt[0] == '4' || fmt[0] == '8')
3823299c2f1SGregory Neil Shapiro 			enhsc = "4.0.0";
3833299c2f1SGregory Neil Shapiro 		else if (fmt[0] == '2')
3843299c2f1SGregory Neil Shapiro 			enhsc = "2.0.0";
3853299c2f1SGregory Neil Shapiro 	}
38612ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
38712ed1c7cSGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
38812ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
3893299c2f1SGregory Neil Shapiro 
3903299c2f1SGregory Neil Shapiro 	if (SuprErrs)
3913299c2f1SGregory Neil Shapiro 		return;
3923299c2f1SGregory Neil Shapiro 
3933299c2f1SGregory Neil Shapiro 	/* save this message for mailq printing */
3943299c2f1SGregory Neil Shapiro 	switch (MsgBuf[0])
3953299c2f1SGregory Neil Shapiro 	{
3963299c2f1SGregory Neil Shapiro 	  case '4':
3973299c2f1SGregory Neil Shapiro 	  case '8':
3983299c2f1SGregory Neil Shapiro 		if (CurEnv->e_message != NULL)
3993299c2f1SGregory Neil Shapiro 			break;
4003299c2f1SGregory Neil Shapiro 
4013299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
4023299c2f1SGregory Neil Shapiro 
4033299c2f1SGregory Neil Shapiro 	  case '5':
4043299c2f1SGregory Neil Shapiro 	  case '6':
40512ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
406c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
4073299c2f1SGregory Neil Shapiro 		if (MsgBuf[0] == '6')
4083299c2f1SGregory Neil Shapiro 		{
4093299c2f1SGregory Neil Shapiro 			char buf[MAXLINE];
4103299c2f1SGregory Neil Shapiro 
411951742c4SGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf),
41212ed1c7cSGregory Neil Shapiro 					   "Postmaster warning: %.*s",
413951742c4SGregory Neil Shapiro 					   (int) sizeof(buf) - 22, errtxt);
41412ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
41512ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, buf);
4163299c2f1SGregory Neil Shapiro 		}
4173299c2f1SGregory Neil Shapiro 		else
4183299c2f1SGregory Neil Shapiro 		{
41912ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
42012ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
4213299c2f1SGregory Neil Shapiro 		}
4223299c2f1SGregory Neil Shapiro 		break;
4233299c2f1SGregory Neil Shapiro 	}
4243299c2f1SGregory Neil Shapiro 
4253299c2f1SGregory Neil Shapiro 	puterrmsg(MsgBuf);
4263299c2f1SGregory Neil Shapiro 	if (LogLevel > 3 && LogUsrErrs)
4273299c2f1SGregory Neil Shapiro 		sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
428c2aa98e2SPeter Wemm 	if (QuickAbort)
42912ed1c7cSGregory Neil Shapiro 		sm_exc_raisenew_x(&EtypeQuickAbort, 1);
430c2aa98e2SPeter Wemm }
4316f9c8e5bSGregory Neil Shapiro 
43212ed1c7cSGregory Neil Shapiro /*
433c2aa98e2SPeter Wemm **  MESSAGE -- print message (not necessarily an error)
434c2aa98e2SPeter Wemm **
435c2aa98e2SPeter Wemm **	Parameters:
43612ed1c7cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- it can begin with
437c2aa98e2SPeter Wemm **			an SMTP reply code.  If not, 050 is assumed.
43812ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
439c2aa98e2SPeter Wemm **
440c2aa98e2SPeter Wemm **	Returns:
441c2aa98e2SPeter Wemm **		none
442c2aa98e2SPeter Wemm */
443c2aa98e2SPeter Wemm 
444c2aa98e2SPeter Wemm /*VARARGS1*/
445c2aa98e2SPeter Wemm void
446c2aa98e2SPeter Wemm #ifdef __STDC__
message(const char * msg,...)447c2aa98e2SPeter Wemm message(const char *msg, ...)
4483299c2f1SGregory Neil Shapiro #else /* __STDC__ */
449c2aa98e2SPeter Wemm message(msg, va_alist)
450c2aa98e2SPeter Wemm 	const char *msg;
451c2aa98e2SPeter Wemm 	va_dcl
4523299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
453c2aa98e2SPeter Wemm {
4543299c2f1SGregory Neil Shapiro 	char *errtxt;
45512ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
456c2aa98e2SPeter Wemm 
457c2aa98e2SPeter Wemm 	errno = 0;
45812ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
4593299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
46012ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
46112ed1c7cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
462c2aa98e2SPeter Wemm 
463c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
464c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
465c2aa98e2SPeter Wemm 	{
466c2aa98e2SPeter Wemm 	  case '4':
467c2aa98e2SPeter Wemm 	  case '8':
468c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
469c2aa98e2SPeter Wemm 			break;
4703299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
471c2aa98e2SPeter Wemm 
472c2aa98e2SPeter Wemm 	  case '5':
47312ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
474c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
4756f9c8e5bSGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
476c2aa98e2SPeter Wemm 		break;
477c2aa98e2SPeter Wemm 	}
478c2aa98e2SPeter Wemm }
4796f9c8e5bSGregory Neil Shapiro 
480da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
481da7d7b9cSGregory Neil Shapiro /*
482da7d7b9cSGregory Neil Shapiro **  EMESSAGE -- print message (not necessarily an error)
483da7d7b9cSGregory Neil Shapiro **	(same as message() but requires reply code and enhanced status code)
484da7d7b9cSGregory Neil Shapiro **
485da7d7b9cSGregory Neil Shapiro **	Parameters:
486da7d7b9cSGregory Neil Shapiro **		replycode -- SMTP reply code.
487da7d7b9cSGregory Neil Shapiro **		enhsc -- enhanced status code.
488da7d7b9cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- it can begin with
489da7d7b9cSGregory Neil Shapiro **			an SMTP reply code.  If not, 050 is assumed.
490da7d7b9cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
491da7d7b9cSGregory Neil Shapiro **
492da7d7b9cSGregory Neil Shapiro **	Returns:
493da7d7b9cSGregory Neil Shapiro **		none
494da7d7b9cSGregory Neil Shapiro */
495da7d7b9cSGregory Neil Shapiro 
496da7d7b9cSGregory Neil Shapiro /*VARARGS3*/
497da7d7b9cSGregory Neil Shapiro void
498da7d7b9cSGregory Neil Shapiro # ifdef __STDC__
emessage(const char * replycode,const char * enhsc,const char * msg,...)499da7d7b9cSGregory Neil Shapiro emessage(const char *replycode, const char *enhsc, const char *msg, ...)
500da7d7b9cSGregory Neil Shapiro # else /* __STDC__ */
501da7d7b9cSGregory Neil Shapiro emessage(replycode, enhsc, msg, va_alist)
502da7d7b9cSGregory Neil Shapiro 	const char *replycode;
503da7d7b9cSGregory Neil Shapiro 	const char *enhsc;
504da7d7b9cSGregory Neil Shapiro 	const char *msg;
505da7d7b9cSGregory Neil Shapiro 	va_dcl
506da7d7b9cSGregory Neil Shapiro # endif /* __STDC__ */
507da7d7b9cSGregory Neil Shapiro {
508da7d7b9cSGregory Neil Shapiro 	char *errtxt;
509da7d7b9cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
510da7d7b9cSGregory Neil Shapiro 
511da7d7b9cSGregory Neil Shapiro 	errno = 0;
512da7d7b9cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
513da7d7b9cSGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, replycode, enhsc, 0, msg, ap);
514da7d7b9cSGregory Neil Shapiro 	SM_VA_END(ap);
515da7d7b9cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
516da7d7b9cSGregory Neil Shapiro 
517da7d7b9cSGregory Neil Shapiro 	/* save this message for mailq printing */
518da7d7b9cSGregory Neil Shapiro 	switch (MsgBuf[0])
519da7d7b9cSGregory Neil Shapiro 	{
520da7d7b9cSGregory Neil Shapiro 	  case '4':
521da7d7b9cSGregory Neil Shapiro 	  case '8':
522da7d7b9cSGregory Neil Shapiro 		if (CurEnv->e_message != NULL)
523da7d7b9cSGregory Neil Shapiro 			break;
524da7d7b9cSGregory Neil Shapiro 		/* FALLTHROUGH */
525da7d7b9cSGregory Neil Shapiro 
526da7d7b9cSGregory Neil Shapiro 	  case '5':
527da7d7b9cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
528da7d7b9cSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
529da7d7b9cSGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
530da7d7b9cSGregory Neil Shapiro 		break;
531da7d7b9cSGregory Neil Shapiro 	}
532da7d7b9cSGregory Neil Shapiro }
533da7d7b9cSGregory Neil Shapiro 
534da7d7b9cSGregory Neil Shapiro /*
535da7d7b9cSGregory Neil Shapiro **  EXTSC -- check and extract a status codes
536da7d7b9cSGregory Neil Shapiro **
537da7d7b9cSGregory Neil Shapiro **	Parameters:
538da7d7b9cSGregory Neil Shapiro **		msg -- string with possible enhanced status code.
539da7d7b9cSGregory Neil Shapiro **		delim -- delim for enhanced status code.
540da7d7b9cSGregory Neil Shapiro **		replycode -- pointer to storage for SMTP reply code;
541da7d7b9cSGregory Neil Shapiro **			must be != NULL and have space for at least
542da7d7b9cSGregory Neil Shapiro **			4 characters.
543da7d7b9cSGregory Neil Shapiro **		enhsc -- pointer to storage for enhanced status code;
544da7d7b9cSGregory Neil Shapiro **			must be != NULL and have space for at least
545da7d7b9cSGregory Neil Shapiro **			10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
546da7d7b9cSGregory Neil Shapiro **
547da7d7b9cSGregory Neil Shapiro **	Returns:
548da7d7b9cSGregory Neil Shapiro **		-1  -- no SMTP reply code.
549da7d7b9cSGregory Neil Shapiro **		>=3 -- offset of error text in msg.
550da7d7b9cSGregory Neil Shapiro **		(<=4  -- no enhanced status code)
551da7d7b9cSGregory Neil Shapiro */
552da7d7b9cSGregory Neil Shapiro 
553da7d7b9cSGregory Neil Shapiro int
extsc(msg,delim,replycode,enhsc)554da7d7b9cSGregory Neil Shapiro extsc(msg, delim, replycode, enhsc)
555da7d7b9cSGregory Neil Shapiro 	const char *msg;
556da7d7b9cSGregory Neil Shapiro 	int delim;
557da7d7b9cSGregory Neil Shapiro 	char *replycode;
558da7d7b9cSGregory Neil Shapiro 	char *enhsc;
559da7d7b9cSGregory Neil Shapiro {
560da7d7b9cSGregory Neil Shapiro 	int offset;
561da7d7b9cSGregory Neil Shapiro 
562da7d7b9cSGregory Neil Shapiro 	SM_REQUIRE(replycode != NULL);
563da7d7b9cSGregory Neil Shapiro 	SM_REQUIRE(enhsc != NULL);
564da7d7b9cSGregory Neil Shapiro 	replycode[0] = '\0';
565da7d7b9cSGregory Neil Shapiro 	enhsc[0] = '\0';
566da7d7b9cSGregory Neil Shapiro 	if (msg == NULL)
567da7d7b9cSGregory Neil Shapiro 		return -1;
568da7d7b9cSGregory Neil Shapiro 	if (!ISSMTPREPLY(msg))
569da7d7b9cSGregory Neil Shapiro 		return -1;
570da7d7b9cSGregory Neil Shapiro 	sm_strlcpy(replycode, msg, 4);
571da7d7b9cSGregory Neil Shapiro 	if (msg[3] == '\0')
572da7d7b9cSGregory Neil Shapiro 		return 3;
573da7d7b9cSGregory Neil Shapiro 	offset = 4;
574da7d7b9cSGregory Neil Shapiro 	if (isenhsc(msg + 4, delim))
575da7d7b9cSGregory Neil Shapiro 		offset = extenhsc(msg + 4, delim, enhsc) + 4;
576da7d7b9cSGregory Neil Shapiro 	return offset;
577da7d7b9cSGregory Neil Shapiro }
578da7d7b9cSGregory Neil Shapiro #endif /* _FFR_PROXY */
5796f9c8e5bSGregory Neil Shapiro 
58012ed1c7cSGregory Neil Shapiro /*
581c2aa98e2SPeter Wemm **  NMESSAGE -- print message (not necessarily an error)
582c2aa98e2SPeter Wemm **
583c2aa98e2SPeter Wemm **	Just like "message" except it never puts the to... tag on.
584c2aa98e2SPeter Wemm **
585c2aa98e2SPeter Wemm **	Parameters:
58612ed1c7cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- if it begins
587c2aa98e2SPeter Wemm **			with a three digit SMTP reply code, that is used,
588c2aa98e2SPeter Wemm **			otherwise 050 is assumed.
58912ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
590c2aa98e2SPeter Wemm **
591c2aa98e2SPeter Wemm **	Returns:
592c2aa98e2SPeter Wemm **		none
593c2aa98e2SPeter Wemm */
594c2aa98e2SPeter Wemm 
595c2aa98e2SPeter Wemm /*VARARGS1*/
596c2aa98e2SPeter Wemm void
597c2aa98e2SPeter Wemm #ifdef __STDC__
nmessage(const char * msg,...)598c2aa98e2SPeter Wemm nmessage(const char *msg, ...)
5993299c2f1SGregory Neil Shapiro #else /* __STDC__ */
600c2aa98e2SPeter Wemm nmessage(msg, va_alist)
601c2aa98e2SPeter Wemm 	const char *msg;
602c2aa98e2SPeter Wemm 	va_dcl
6033299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
604c2aa98e2SPeter Wemm {
6053299c2f1SGregory Neil Shapiro 	char *errtxt;
60612ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
607c2aa98e2SPeter Wemm 
608c2aa98e2SPeter Wemm 	errno = 0;
60912ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
6103299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
6113299c2f1SGregory Neil Shapiro 			(char *) NULL, 0, msg, ap);
61212ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
61312ed1c7cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
614c2aa98e2SPeter Wemm 
615c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
616c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
617c2aa98e2SPeter Wemm 	{
618c2aa98e2SPeter Wemm 	  case '4':
619c2aa98e2SPeter Wemm 	  case '8':
620c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
621c2aa98e2SPeter Wemm 			break;
6223299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
623c2aa98e2SPeter Wemm 
624c2aa98e2SPeter Wemm 	  case '5':
62512ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
626c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
627951742c4SGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
628c2aa98e2SPeter Wemm 		break;
629c2aa98e2SPeter Wemm 	}
630c2aa98e2SPeter Wemm }
6315b0945b5SGregory Neil Shapiro 
63212ed1c7cSGregory Neil Shapiro /*
633c2aa98e2SPeter Wemm **  PUTOUTMSG -- output error message to transcript and channel
634c2aa98e2SPeter Wemm **
635c2aa98e2SPeter Wemm **	Parameters:
636c2aa98e2SPeter Wemm **		msg -- message to output (in SMTP format).
63712ed1c7cSGregory Neil Shapiro **		holdmsg -- if true, don't output a copy of the message to
638c2aa98e2SPeter Wemm **			our output channel.
63912ed1c7cSGregory Neil Shapiro **		heldmsg -- if true, this is a previously held message;
640c2aa98e2SPeter Wemm **			don't log it to the transcript file.
641c2aa98e2SPeter Wemm **
642c2aa98e2SPeter Wemm **	Returns:
643c2aa98e2SPeter Wemm **		none.
644c2aa98e2SPeter Wemm **
645c2aa98e2SPeter Wemm **	Side Effects:
646c2aa98e2SPeter Wemm **		Outputs msg to the transcript.
647c2aa98e2SPeter Wemm **		If appropriate, outputs it to the channel.
648c2aa98e2SPeter Wemm **		Deletes SMTP reply code number as appropriate.
649c2aa98e2SPeter Wemm */
650c2aa98e2SPeter Wemm 
6513299c2f1SGregory Neil Shapiro static void
putoutmsg(msg,holdmsg,heldmsg)652c2aa98e2SPeter Wemm putoutmsg(msg, holdmsg, heldmsg)
653c2aa98e2SPeter Wemm 	char *msg;
654c2aa98e2SPeter Wemm 	bool holdmsg;
655c2aa98e2SPeter Wemm 	bool heldmsg;
656c2aa98e2SPeter Wemm {
657c2aa98e2SPeter Wemm 	char msgcode = msg[0];
658951742c4SGregory Neil Shapiro 	char *errtxt = msg;
659951742c4SGregory Neil Shapiro 	char *id;
660c2aa98e2SPeter Wemm 
661c2aa98e2SPeter Wemm 	/* display for debugging */
662c2aa98e2SPeter Wemm 	if (tTd(54, 8))
66312ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
664c2aa98e2SPeter Wemm 			heldmsg ? " (held)" : "");
665c2aa98e2SPeter Wemm 
666c2aa98e2SPeter Wemm 	/* map warnings to something SMTP can handle */
667c2aa98e2SPeter Wemm 	if (msgcode == '6')
668c2aa98e2SPeter Wemm 		msg[0] = '5';
669c2aa98e2SPeter Wemm 	else if (msgcode == '8')
670c2aa98e2SPeter Wemm 		msg[0] = '4';
671951742c4SGregory Neil Shapiro 	id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
672c2aa98e2SPeter Wemm 
673c2aa98e2SPeter Wemm 	/* output to transcript if serious */
674c2aa98e2SPeter Wemm 	if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
675c2aa98e2SPeter Wemm 	    strchr("45", msg[0]) != NULL)
67612ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
67712ed1c7cSGregory Neil Shapiro 				     msg);
678c2aa98e2SPeter Wemm 
67912ed1c7cSGregory Neil Shapiro 	if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
680951742c4SGregory Neil Shapiro 		sm_syslog(LOG_INFO, id,
68112ed1c7cSGregory Neil Shapiro 			  "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
68212ed1c7cSGregory Neil Shapiro 			  heldmsg ? " (held)" : "");
683c2aa98e2SPeter Wemm 
684c2aa98e2SPeter Wemm 	if (msgcode == '8')
685c2aa98e2SPeter Wemm 		msg[0] = '0';
686c2aa98e2SPeter Wemm 
687c2aa98e2SPeter Wemm 	/* output to channel if appropriate */
688c2aa98e2SPeter Wemm 	if (!Verbose && msg[0] == '0')
689c2aa98e2SPeter Wemm 		return;
690c2aa98e2SPeter Wemm 	if (holdmsg)
691c2aa98e2SPeter Wemm 	{
692c2aa98e2SPeter Wemm 		/* save for possible future display */
693c2aa98e2SPeter Wemm 		msg[0] = msgcode;
6943299c2f1SGregory Neil Shapiro 		if (HeldMessageBuf[0] == '5' && msgcode == '4')
6953299c2f1SGregory Neil Shapiro 			return;
696951742c4SGregory Neil Shapiro 		(void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
697c2aa98e2SPeter Wemm 		return;
698c2aa98e2SPeter Wemm 	}
699c2aa98e2SPeter Wemm 
70012ed1c7cSGregory Neil Shapiro 	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
701c2aa98e2SPeter Wemm 
702c2aa98e2SPeter Wemm 	if (OutChannel == NULL)
703c2aa98e2SPeter Wemm 		return;
704c2aa98e2SPeter Wemm 
7053299c2f1SGregory Neil Shapiro 	/* find actual text of error (after SMTP status codes) */
7063299c2f1SGregory Neil Shapiro 	if (ISSMTPREPLY(errtxt))
7073299c2f1SGregory Neil Shapiro 	{
7083299c2f1SGregory Neil Shapiro 		int l;
7093299c2f1SGregory Neil Shapiro 
7103299c2f1SGregory Neil Shapiro 		errtxt += 4;
7113299c2f1SGregory Neil Shapiro 		l = isenhsc(errtxt, ' ');
7123299c2f1SGregory Neil Shapiro 		if (l <= 0)
7133299c2f1SGregory Neil Shapiro 			l = isenhsc(errtxt, '\0');
7143299c2f1SGregory Neil Shapiro 		if (l > 0)
7153299c2f1SGregory Neil Shapiro 			errtxt += l + 1;
7163299c2f1SGregory Neil Shapiro 	}
7173299c2f1SGregory Neil Shapiro 
718c2aa98e2SPeter Wemm 	/* if DisConnected, OutChannel now points to the transcript */
719c2aa98e2SPeter Wemm 	if (!DisConnected &&
720c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
72112ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
72212ed1c7cSGregory Neil Shapiro 				     msg);
723c2aa98e2SPeter Wemm 	else
72412ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
72512ed1c7cSGregory Neil Shapiro 				     errtxt);
726c2aa98e2SPeter Wemm 	if (TrafficLogFile != NULL)
72712ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
72812ed1c7cSGregory Neil Shapiro 				     "%05d >>> %s\n", (int) CurrentPid,
72912ed1c7cSGregory Neil Shapiro 				     (OpMode == MD_SMTP || OpMode == MD_DAEMON)
73012ed1c7cSGregory Neil Shapiro 					? msg : errtxt);
73112ed1c7cSGregory Neil Shapiro #if !PIPELINING
732*2fb4f839SGregory Neil Shapiro 	/*
733*2fb4f839SGregory Neil Shapiro 	**  Note: in case of an SMTP reply this should check
734*2fb4f839SGregory Neil Shapiro 	**  that the last line of msg is not a continuation line
735*2fb4f839SGregory Neil Shapiro 	**  but that's probably not worth the effort.
736*2fb4f839SGregory Neil Shapiro 	*/
737*2fb4f839SGregory Neil Shapiro 
738*2fb4f839SGregory Neil Shapiro 	if (ISSMTPREPLY(msg))
73912ed1c7cSGregory Neil Shapiro 		(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
74012ed1c7cSGregory Neil Shapiro 	if (!sm_io_error(OutChannel) || DisConnected)
741c2aa98e2SPeter Wemm 		return;
742c2aa98e2SPeter Wemm 
743c2aa98e2SPeter Wemm 	/*
744c2aa98e2SPeter Wemm 	**  Error on output -- if reporting lost channel, just ignore it.
745c2aa98e2SPeter Wemm 	**  Also, ignore errors from QUIT response (221 message) -- some
746c2aa98e2SPeter Wemm 	**	rude servers don't read result.
747c2aa98e2SPeter Wemm 	*/
748c2aa98e2SPeter Wemm 
74912ed1c7cSGregory Neil Shapiro 	if (InChannel == NULL || sm_io_eof(InChannel) ||
75012ed1c7cSGregory Neil Shapiro 	    sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
751c2aa98e2SPeter Wemm 		return;
752c2aa98e2SPeter Wemm 
753c2aa98e2SPeter Wemm 	/* can't call syserr, 'cause we are using MsgBuf */
75412ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
755c2aa98e2SPeter Wemm 	if (LogLevel > 0)
756951742c4SGregory Neil Shapiro 		sm_syslog(LOG_CRIT, id,
757c2aa98e2SPeter Wemm 			  "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
75812ed1c7cSGregory Neil Shapiro 			  CURHOSTNAME,
75912ed1c7cSGregory Neil Shapiro 			  shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
76012ed1c7cSGregory Neil Shapiro #endif /* !PIPELINING */
761c2aa98e2SPeter Wemm }
7625b0945b5SGregory Neil Shapiro 
76312ed1c7cSGregory Neil Shapiro /*
764c2aa98e2SPeter Wemm **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
765c2aa98e2SPeter Wemm **
766c2aa98e2SPeter Wemm **	Parameters:
767c2aa98e2SPeter Wemm **		msg -- the message to output.
768c2aa98e2SPeter Wemm **
769c2aa98e2SPeter Wemm **	Returns:
770c2aa98e2SPeter Wemm **		none.
771c2aa98e2SPeter Wemm **
772c2aa98e2SPeter Wemm **	Side Effects:
773c2aa98e2SPeter Wemm **		Sets the fatal error bit in the envelope as appropriate.
774c2aa98e2SPeter Wemm */
775c2aa98e2SPeter Wemm 
7763299c2f1SGregory Neil Shapiro static void
puterrmsg(msg)777c2aa98e2SPeter Wemm puterrmsg(msg)
778c2aa98e2SPeter Wemm 	char *msg;
779c2aa98e2SPeter Wemm {
780c2aa98e2SPeter Wemm 	char msgcode = msg[0];
781c2aa98e2SPeter Wemm 
782c2aa98e2SPeter Wemm 	/* output the message as usual */
78312ed1c7cSGregory Neil Shapiro 	putoutmsg(msg, HoldErrs, false);
784c2aa98e2SPeter Wemm 
785c2aa98e2SPeter Wemm 	/* be careful about multiple error messages */
786c2aa98e2SPeter Wemm 	if (OnlyOneError)
78712ed1c7cSGregory Neil Shapiro 		HoldErrs = true;
788c2aa98e2SPeter Wemm 
789c2aa98e2SPeter Wemm 	/* signal the error */
790c2aa98e2SPeter Wemm 	Errors++;
791c2aa98e2SPeter Wemm 
792c2aa98e2SPeter Wemm 	if (CurEnv == NULL)
793c2aa98e2SPeter Wemm 		return;
794c2aa98e2SPeter Wemm 
795c2aa98e2SPeter Wemm 	if (msgcode == '6')
796c2aa98e2SPeter Wemm 	{
797c2aa98e2SPeter Wemm 		/* notify the postmaster */
798c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_PM_NOTIFY;
799c2aa98e2SPeter Wemm 	}
800c2aa98e2SPeter Wemm 	else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
801c2aa98e2SPeter Wemm 	{
802c2aa98e2SPeter Wemm 		/* mark long-term fatal errors */
803c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_FATALERRS;
804c2aa98e2SPeter Wemm 	}
805c2aa98e2SPeter Wemm }
8065b0945b5SGregory Neil Shapiro 
80712ed1c7cSGregory Neil Shapiro /*
8083299c2f1SGregory Neil Shapiro **  ISENHSC -- check whether a string contains an enhanced status code
8093299c2f1SGregory Neil Shapiro **
8103299c2f1SGregory Neil Shapiro **	Parameters:
8113299c2f1SGregory Neil Shapiro **		s -- string with possible enhanced status code.
8123299c2f1SGregory Neil Shapiro **		delim -- delim for enhanced status code.
8133299c2f1SGregory Neil Shapiro **
8143299c2f1SGregory Neil Shapiro **	Returns:
8153299c2f1SGregory Neil Shapiro **		0  -- no enhanced status code.
8163299c2f1SGregory Neil Shapiro **		>4 -- length of enhanced status code.
8173299c2f1SGregory Neil Shapiro */
8185b0945b5SGregory Neil Shapiro 
8193299c2f1SGregory Neil Shapiro int
isenhsc(s,delim)8203299c2f1SGregory Neil Shapiro isenhsc(s, delim)
8213299c2f1SGregory Neil Shapiro 	const char *s;
8223299c2f1SGregory Neil Shapiro 	int delim;
8233299c2f1SGregory Neil Shapiro {
8243299c2f1SGregory Neil Shapiro 	int l, h;
8253299c2f1SGregory Neil Shapiro 
8263299c2f1SGregory Neil Shapiro 	if (s == NULL)
8273299c2f1SGregory Neil Shapiro 		return 0;
8283299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8293299c2f1SGregory Neil Shapiro 		return 0;
8303299c2f1SGregory Neil Shapiro 	h = 0;
8313299c2f1SGregory Neil Shapiro 	l = 2;
8323299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8333299c2f1SGregory Neil Shapiro 		++h;
8343299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
8353299c2f1SGregory Neil Shapiro 		return 0;
8363299c2f1SGregory Neil Shapiro 	l += h + 1;
8373299c2f1SGregory Neil Shapiro 	h = 0;
8383299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8393299c2f1SGregory Neil Shapiro 		++h;
8403299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
8413299c2f1SGregory Neil Shapiro 		return 0;
8423299c2f1SGregory Neil Shapiro 	return l + h;
8433299c2f1SGregory Neil Shapiro }
8445b0945b5SGregory Neil Shapiro 
84512ed1c7cSGregory Neil Shapiro /*
8463299c2f1SGregory Neil Shapiro **  EXTENHSC -- check and extract an enhanced status code
8473299c2f1SGregory Neil Shapiro **
8483299c2f1SGregory Neil Shapiro **	Parameters:
8493299c2f1SGregory Neil Shapiro **		s -- string with possible enhanced status code.
8503299c2f1SGregory Neil Shapiro **		delim -- delim for enhanced status code.
8513299c2f1SGregory Neil Shapiro **		e -- pointer to storage for enhanced status code.
8523299c2f1SGregory Neil Shapiro **			must be != NULL and have space for at least
8533299c2f1SGregory Neil Shapiro **			10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
8543299c2f1SGregory Neil Shapiro **
8553299c2f1SGregory Neil Shapiro **	Returns:
8563299c2f1SGregory Neil Shapiro **		0  -- no enhanced status code.
8573299c2f1SGregory Neil Shapiro **		>4 -- length of enhanced status code.
8583299c2f1SGregory Neil Shapiro **
8593299c2f1SGregory Neil Shapiro **	Side Effects:
8603299c2f1SGregory Neil Shapiro **		fills e with enhanced status code.
8613299c2f1SGregory Neil Shapiro */
86212ed1c7cSGregory Neil Shapiro 
8633299c2f1SGregory Neil Shapiro int
extenhsc(s,delim,e)8643299c2f1SGregory Neil Shapiro extenhsc(s, delim, e)
8653299c2f1SGregory Neil Shapiro 	const char *s;
8663299c2f1SGregory Neil Shapiro 	int delim;
8673299c2f1SGregory Neil Shapiro 	char *e;
8683299c2f1SGregory Neil Shapiro {
8693299c2f1SGregory Neil Shapiro 	int l, h;
8703299c2f1SGregory Neil Shapiro 
8713299c2f1SGregory Neil Shapiro 	if (s == NULL)
8723299c2f1SGregory Neil Shapiro 		return 0;
8733299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8743299c2f1SGregory Neil Shapiro 		return 0;
8753299c2f1SGregory Neil Shapiro 	h = 0;
8763299c2f1SGregory Neil Shapiro 	l = 2;
8773299c2f1SGregory Neil Shapiro 	e[0] = s[0];
8783299c2f1SGregory Neil Shapiro 	e[1] = '.';
8793299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8803299c2f1SGregory Neil Shapiro 	{
8813299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
8823299c2f1SGregory Neil Shapiro 		++h;
8833299c2f1SGregory Neil Shapiro 	}
8843299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
8853299c2f1SGregory Neil Shapiro 		return 0;
8863299c2f1SGregory Neil Shapiro 	e[l + h] = '.';
8873299c2f1SGregory Neil Shapiro 	l += h + 1;
8883299c2f1SGregory Neil Shapiro 	h = 0;
8893299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8903299c2f1SGregory Neil Shapiro 	{
8913299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
8923299c2f1SGregory Neil Shapiro 		++h;
8933299c2f1SGregory Neil Shapiro 	}
8943299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
8953299c2f1SGregory Neil Shapiro 		return 0;
8963299c2f1SGregory Neil Shapiro 	e[l + h] = '\0';
8973299c2f1SGregory Neil Shapiro 	return l + h;
8983299c2f1SGregory Neil Shapiro }
8995b0945b5SGregory Neil Shapiro 
900*2fb4f839SGregory Neil Shapiro #if USE_EAI
901*2fb4f839SGregory Neil Shapiro /*
902*2fb4f839SGregory Neil Shapiro **  SKIPADDRHOST -- skip address and host in a message
903*2fb4f839SGregory Neil Shapiro **
904*2fb4f839SGregory Neil Shapiro **	Parameters:
905*2fb4f839SGregory Neil Shapiro **		s -- string with possible address and host
906*2fb4f839SGregory Neil Shapiro **		skiphost -- skip also host?
907*2fb4f839SGregory Neil Shapiro **
908*2fb4f839SGregory Neil Shapiro **	Returns:
909*2fb4f839SGregory Neil Shapiro **		0  -- no address and host
910*2fb4f839SGregory Neil Shapiro **		>0 -- position after address (and host)
911*2fb4f839SGregory Neil Shapiro */
912*2fb4f839SGregory Neil Shapiro 
913*2fb4f839SGregory Neil Shapiro int
skipaddrhost(s,skiphost)914*2fb4f839SGregory Neil Shapiro skipaddrhost(s, skiphost)
915*2fb4f839SGregory Neil Shapiro 	const char *s;
916*2fb4f839SGregory Neil Shapiro 	bool skiphost;
917*2fb4f839SGregory Neil Shapiro {
918*2fb4f839SGregory Neil Shapiro 	char *str;
919*2fb4f839SGregory Neil Shapiro 	size_t len;
920*2fb4f839SGregory Neil Shapiro 
921*2fb4f839SGregory Neil Shapiro #define SM_ADDR_DELIM "... "
922*2fb4f839SGregory Neil Shapiro 	if (s == NULL)
923*2fb4f839SGregory Neil Shapiro 		return 0;
924*2fb4f839SGregory Neil Shapiro 	str = strstr(s, SM_ADDR_DELIM);
925*2fb4f839SGregory Neil Shapiro 	if (str == NULL)
926*2fb4f839SGregory Neil Shapiro 		return 0;
927*2fb4f839SGregory Neil Shapiro 	str += sizeof(SM_ADDR_DELIM) + 1;
928*2fb4f839SGregory Neil Shapiro 	len = strlen(s);
929*2fb4f839SGregory Neil Shapiro 	if (str >= s + len)
930*2fb4f839SGregory Neil Shapiro 		return 0;
931*2fb4f839SGregory Neil Shapiro 	if (!skiphost)
932*2fb4f839SGregory Neil Shapiro 		return str - s + 1;
933*2fb4f839SGregory Neil Shapiro 
934*2fb4f839SGregory Neil Shapiro 	str = strchr(str, ' ');
935*2fb4f839SGregory Neil Shapiro 	if (str >= s + len)
936*2fb4f839SGregory Neil Shapiro 		return 0;
937*2fb4f839SGregory Neil Shapiro 	return str - s + 1;
938*2fb4f839SGregory Neil Shapiro }
939*2fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
940*2fb4f839SGregory Neil Shapiro 
94112ed1c7cSGregory Neil Shapiro /*
942c2aa98e2SPeter Wemm **  FMTMSG -- format a message into buffer.
943c2aa98e2SPeter Wemm **
944c2aa98e2SPeter Wemm **	Parameters:
9453299c2f1SGregory Neil Shapiro **		eb -- error buffer to get result -- MUST BE MsgBuf.
946c2aa98e2SPeter Wemm **		to -- the recipient tag for this message.
9473299c2f1SGregory Neil Shapiro **		num -- default three digit SMTP reply code.
9483299c2f1SGregory Neil Shapiro **		enhsc -- enhanced status code.
949c2aa98e2SPeter Wemm **		en -- the error number to display.
9505b0945b5SGregory Neil Shapiro **		fmt -- format of string: See NOTE below.
9513299c2f1SGregory Neil Shapiro **		ap -- arguments for fmt.
952c2aa98e2SPeter Wemm **
953c2aa98e2SPeter Wemm **	Returns:
9543299c2f1SGregory Neil Shapiro **		pointer to error text beyond status codes.
955c2aa98e2SPeter Wemm **
9565b0945b5SGregory Neil Shapiro **	NOTE:
9575b0945b5SGregory Neil Shapiro **		Do NOT use "%s" as fmt if the argument starts with an SMTP
9585b0945b5SGregory Neil Shapiro **		reply code!
959c2aa98e2SPeter Wemm */
960c2aa98e2SPeter Wemm 
9613299c2f1SGregory Neil Shapiro static char *
fmtmsg(eb,to,num,enhsc,eno,fmt,ap)9623299c2f1SGregory Neil Shapiro fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
963c2aa98e2SPeter Wemm 	register char *eb;
964c2aa98e2SPeter Wemm 	const char *to;
965c2aa98e2SPeter Wemm 	const char *num;
9663299c2f1SGregory Neil Shapiro 	const char *enhsc;
967c2aa98e2SPeter Wemm 	int eno;
968c2aa98e2SPeter Wemm 	const char *fmt;
969*2fb4f839SGregory Neil Shapiro 	va_list ap;
970c2aa98e2SPeter Wemm {
971c2aa98e2SPeter Wemm 	char del;
972c2aa98e2SPeter Wemm 	int l;
973951742c4SGregory Neil Shapiro 	int spaceleft = sizeof(MsgBuf);
9743299c2f1SGregory Neil Shapiro 	char *errtxt;
975c2aa98e2SPeter Wemm 
976c2aa98e2SPeter Wemm 	/* output the reply code */
9773299c2f1SGregory Neil Shapiro 	if (ISSMTPCODE(fmt))
978c2aa98e2SPeter Wemm 	{
979c2aa98e2SPeter Wemm 		num = fmt;
980c2aa98e2SPeter Wemm 		fmt += 4;
981c2aa98e2SPeter Wemm 	}
982c2aa98e2SPeter Wemm 	if (num[3] == '-')
983c2aa98e2SPeter Wemm 		del = '-';
984c2aa98e2SPeter Wemm 	else
985c2aa98e2SPeter Wemm 		del = ' ';
98612ed1c7cSGregory Neil Shapiro 	if (SoftBounce && num[0] == '5')
98712ed1c7cSGregory Neil Shapiro 	{
98812ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
98912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
99012ed1c7cSGregory Neil Shapiro 	}
99112ed1c7cSGregory Neil Shapiro 	else
99212ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
993c2aa98e2SPeter Wemm 	eb += 4;
994c2aa98e2SPeter Wemm 	spaceleft -= 4;
995c2aa98e2SPeter Wemm 
9963299c2f1SGregory Neil Shapiro 	if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
9973299c2f1SGregory Neil Shapiro 	{
9983299c2f1SGregory Neil Shapiro 		/* copy enh.status code including trailing blank */
9993299c2f1SGregory Neil Shapiro 		l++;
100012ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, fmt, l + 1);
10013299c2f1SGregory Neil Shapiro 		eb += l;
10023299c2f1SGregory Neil Shapiro 		spaceleft -= l;
10033299c2f1SGregory Neil Shapiro 		fmt += l;
10043299c2f1SGregory Neil Shapiro 	}
10053299c2f1SGregory Neil Shapiro 	else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
10063299c2f1SGregory Neil Shapiro 	{
10073299c2f1SGregory Neil Shapiro 		/* copy enh.status code */
100812ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, enhsc, l + 1);
10093299c2f1SGregory Neil Shapiro 		eb[l] = ' ';
10103299c2f1SGregory Neil Shapiro 		eb[++l] = '\0';
10113299c2f1SGregory Neil Shapiro 		eb += l;
10123299c2f1SGregory Neil Shapiro 		spaceleft -= l;
10133299c2f1SGregory Neil Shapiro 	}
101412ed1c7cSGregory Neil Shapiro 	if (SoftBounce && eb[-l] == '5')
101512ed1c7cSGregory Neil Shapiro 	{
101612ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
101712ed1c7cSGregory Neil Shapiro 		eb[-l] = '4';
101812ed1c7cSGregory Neil Shapiro 	}
10193299c2f1SGregory Neil Shapiro 	errtxt = eb;
10203299c2f1SGregory Neil Shapiro 
1021c2aa98e2SPeter Wemm 	/* output the file name and line number */
1022c2aa98e2SPeter Wemm 	if (FileName != NULL)
1023c2aa98e2SPeter Wemm 	{
102412ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
1025c2aa98e2SPeter Wemm 				   shortenstring(FileName, 83), LineNumber);
1026c2aa98e2SPeter Wemm 		eb += (l = strlen(eb));
1027c2aa98e2SPeter Wemm 		spaceleft -= l;
1028c2aa98e2SPeter Wemm 	}
1029c2aa98e2SPeter Wemm 
103056477e1eSGregory Neil Shapiro 	/*
103156477e1eSGregory Neil Shapiro 	**  output the "to" address only if it is defined and one of the
103256477e1eSGregory Neil Shapiro 	**  following codes is used:
103356477e1eSGregory Neil Shapiro 	**  050 internal notices, e.g., alias expansion
103456477e1eSGregory Neil Shapiro 	**  250 Ok
103556477e1eSGregory Neil Shapiro 	**  252 Cannot VRFY user, but will accept message and attempt delivery
103656477e1eSGregory Neil Shapiro 	**  450 Requested mail action not taken: mailbox unavailable
103756477e1eSGregory Neil Shapiro 	**  550 Requested action not taken: mailbox unavailable
103856477e1eSGregory Neil Shapiro 	**  553 Requested action not taken: mailbox name not allowed
103956477e1eSGregory Neil Shapiro 	**
104056477e1eSGregory Neil Shapiro 	**  Notice: this still isn't "the right thing", this code shouldn't
104156477e1eSGregory Neil Shapiro 	**	(indirectly) depend on CurEnv->e_to.
104256477e1eSGregory Neil Shapiro 	*/
104356477e1eSGregory Neil Shapiro 
1044c2aa98e2SPeter Wemm 	if (to != NULL && to[0] != '\0' &&
104556477e1eSGregory Neil Shapiro 	    (strncmp(num, "050", 3) == 0 ||
104656477e1eSGregory Neil Shapiro 	     strncmp(num, "250", 3) == 0 ||
104756477e1eSGregory Neil Shapiro 	     strncmp(num, "252", 3) == 0 ||
104856477e1eSGregory Neil Shapiro 	     strncmp(num, "450", 3) == 0 ||
104956477e1eSGregory Neil Shapiro 	     strncmp(num, "550", 3) == 0 ||
105056477e1eSGregory Neil Shapiro 	     strncmp(num, "553", 3) == 0))
1051c2aa98e2SPeter Wemm 	{
1052*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
1053*2fb4f839SGregory Neil Shapiro 		char xbuf[MAXNAME + 1];	/* EAI:ok */
1054*2fb4f839SGregory Neil Shapiro 		int len;
1055*2fb4f839SGregory Neil Shapiro 
1056*2fb4f839SGregory Neil Shapiro 		len = sizeof(xbuf);
1057*2fb4f839SGregory Neil Shapiro 		(void) sm_strlcpy(xbuf, to, len);
1058*2fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(xbuf, xbuf, len);
1059*2fb4f839SGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2,
1060*2fb4f839SGregory Neil Shapiro 				   shortenstring(xbuf, MAXSHORTSTR), "... ");
1061*2fb4f839SGregory Neil Shapiro 		eb += strlen(eb);
1062*2fb4f839SGregory Neil Shapiro #else /* _FFR_8BITENVADDR */
106312ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2,
106412ed1c7cSGregory Neil Shapiro 				   shortenstring(to, MAXSHORTSTR), "... ");
1065c2aa98e2SPeter Wemm 		while (*eb != '\0')
1066c2aa98e2SPeter Wemm 			*eb++ &= 0177;
1067*2fb4f839SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */
1068*2fb4f839SGregory Neil Shapiro 		spaceleft -= strlen(eb);
1069c2aa98e2SPeter Wemm 	}
1070c2aa98e2SPeter Wemm 
1071c2aa98e2SPeter Wemm 	/* output the message */
107212ed1c7cSGregory Neil Shapiro 	(void) sm_vsnprintf(eb, spaceleft, fmt, ap);
1073c2aa98e2SPeter Wemm 	spaceleft -= strlen(eb);
1074*2fb4f839SGregory Neil Shapiro #if USE_EAI
10755b0945b5SGregory Neil Shapiro 	eb += strlen(eb);
10765b0945b5SGregory Neil Shapiro #else
1077c2aa98e2SPeter Wemm 	while (*eb != '\0')
1078c2aa98e2SPeter Wemm 		*eb++ &= 0177;
10795b0945b5SGregory Neil Shapiro #endif
1080c2aa98e2SPeter Wemm 
1081c2aa98e2SPeter Wemm 	/* output the error code, if any */
1082c2aa98e2SPeter Wemm 	if (eno != 0)
108312ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
10843299c2f1SGregory Neil Shapiro 
10853299c2f1SGregory Neil Shapiro 	return errtxt;
1086c2aa98e2SPeter Wemm }
10875b0945b5SGregory Neil Shapiro 
108812ed1c7cSGregory Neil Shapiro /*
1089c2aa98e2SPeter Wemm **  BUFFER_ERRORS -- arrange to buffer future error messages
1090c2aa98e2SPeter Wemm **
1091c2aa98e2SPeter Wemm **	Parameters:
1092c2aa98e2SPeter Wemm **		none
1093c2aa98e2SPeter Wemm **
1094c2aa98e2SPeter Wemm **	Returns:
1095c2aa98e2SPeter Wemm **		none.
1096c2aa98e2SPeter Wemm */
1097c2aa98e2SPeter Wemm 
1098c2aa98e2SPeter Wemm void
buffer_errors()1099c2aa98e2SPeter Wemm buffer_errors()
1100c2aa98e2SPeter Wemm {
1101c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
110212ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
1103c2aa98e2SPeter Wemm }
11045b0945b5SGregory Neil Shapiro 
110512ed1c7cSGregory Neil Shapiro /*
1106c2aa98e2SPeter Wemm **  FLUSH_ERRORS -- flush the held error message buffer
1107c2aa98e2SPeter Wemm **
1108c2aa98e2SPeter Wemm **	Parameters:
1109c2aa98e2SPeter Wemm **		print -- if set, print the message, otherwise just
1110c2aa98e2SPeter Wemm **			delete it.
1111c2aa98e2SPeter Wemm **
1112c2aa98e2SPeter Wemm **	Returns:
1113c2aa98e2SPeter Wemm **		none.
1114c2aa98e2SPeter Wemm */
1115c2aa98e2SPeter Wemm 
1116c2aa98e2SPeter Wemm void
flush_errors(print)1117c2aa98e2SPeter Wemm flush_errors(print)
1118c2aa98e2SPeter Wemm 	bool print;
1119c2aa98e2SPeter Wemm {
1120c2aa98e2SPeter Wemm 	if (print && HeldMessageBuf[0] != '\0')
112112ed1c7cSGregory Neil Shapiro 		putoutmsg(HeldMessageBuf, false, true);
1122c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
112312ed1c7cSGregory Neil Shapiro 	HoldErrs = false;
1124c2aa98e2SPeter Wemm }
112512ed1c7cSGregory Neil Shapiro /*
112612ed1c7cSGregory Neil Shapiro **  SM_ERRSTRING -- return string description of error code
1127c2aa98e2SPeter Wemm **
1128c2aa98e2SPeter Wemm **	Parameters:
1129c2aa98e2SPeter Wemm **		errnum -- the error number to translate
1130c2aa98e2SPeter Wemm **
1131c2aa98e2SPeter Wemm **	Returns:
1132c2aa98e2SPeter Wemm **		A string description of errnum.
1133c2aa98e2SPeter Wemm */
1134c2aa98e2SPeter Wemm 
1135c2aa98e2SPeter Wemm const char *
sm_errstring(errnum)113612ed1c7cSGregory Neil Shapiro sm_errstring(errnum)
1137c2aa98e2SPeter Wemm 	int errnum;
1138c2aa98e2SPeter Wemm {
1139c2aa98e2SPeter Wemm 	char *dnsmsg;
1140c2aa98e2SPeter Wemm 	char *bp;
1141c2aa98e2SPeter Wemm 	static char buf[MAXLINE];
114212ed1c7cSGregory Neil Shapiro #if HASSTRERROR
114312ed1c7cSGregory Neil Shapiro 	char *err;
114412ed1c7cSGregory Neil Shapiro 	char errbuf[30];
11455b0945b5SGregory Neil Shapiro #endif
1146c2aa98e2SPeter Wemm #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
1147c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
1148c2aa98e2SPeter Wemm 	extern int sys_nerr;
11495b0945b5SGregory Neil Shapiro #endif
1150c2aa98e2SPeter Wemm 
1151c2aa98e2SPeter Wemm 	/*
1152c2aa98e2SPeter Wemm 	**  Handle special network error codes.
1153c2aa98e2SPeter Wemm 	**
1154c2aa98e2SPeter Wemm 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
1155c2aa98e2SPeter Wemm 	*/
1156c2aa98e2SPeter Wemm 
1157c2aa98e2SPeter Wemm 	dnsmsg = NULL;
1158c2aa98e2SPeter Wemm 	switch (errnum)
1159c2aa98e2SPeter Wemm 	{
1160c2aa98e2SPeter Wemm 	  case ETIMEDOUT:
1161c2aa98e2SPeter Wemm 	  case ECONNRESET:
1162c2aa98e2SPeter Wemm 		bp = buf;
1163c2aa98e2SPeter Wemm #if HASSTRERROR
116412ed1c7cSGregory Neil Shapiro 		err = strerror(errnum);
116512ed1c7cSGregory Neil Shapiro 		if (err == NULL)
116612ed1c7cSGregory Neil Shapiro 		{
1167951742c4SGregory Neil Shapiro 			(void) sm_snprintf(errbuf, sizeof(errbuf),
116812ed1c7cSGregory Neil Shapiro 					   "Error %d", errnum);
116912ed1c7cSGregory Neil Shapiro 			err = errbuf;
117012ed1c7cSGregory Neil Shapiro 		}
117112ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
11723299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1173c2aa98e2SPeter Wemm 		if (errnum >= 0 && errnum < sys_nerr)
117412ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp, sys_errlist[errnum],
117512ed1c7cSGregory Neil Shapiro 					  SPACELEFT(buf, bp));
1176c2aa98e2SPeter Wemm 		else
117712ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
117812ed1c7cSGregory Neil Shapiro 				"Error %d", errnum);
11793299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1180c2aa98e2SPeter Wemm 		bp += strlen(bp);
1181c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1182c2aa98e2SPeter Wemm 		{
1183c2aa98e2SPeter Wemm 			if (errnum == ETIMEDOUT)
1184c2aa98e2SPeter Wemm 			{
118512ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
118612ed1c7cSGregory Neil Shapiro 					" with ");
1187c2aa98e2SPeter Wemm 				bp += strlen(bp);
1188c2aa98e2SPeter Wemm 			}
1189c2aa98e2SPeter Wemm 			else
1190c2aa98e2SPeter Wemm 			{
1191c2aa98e2SPeter Wemm 				bp = buf;
119212ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
1193c2aa98e2SPeter Wemm 					"Connection reset by ");
1194c2aa98e2SPeter Wemm 				bp += strlen(bp);
1195c2aa98e2SPeter Wemm 			}
119612ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp,
119712ed1c7cSGregory Neil Shapiro 					shortenstring(CurHostName, MAXSHORTSTR),
119812ed1c7cSGregory Neil Shapiro 					SPACELEFT(buf, bp));
1199c2aa98e2SPeter Wemm 			bp += strlen(buf);
1200c2aa98e2SPeter Wemm 		}
1201c2aa98e2SPeter Wemm 		if (SmtpPhase != NULL)
1202c2aa98e2SPeter Wemm 		{
120312ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
120412ed1c7cSGregory Neil Shapiro 				" during %s", SmtpPhase);
1205c2aa98e2SPeter Wemm 		}
12063299c2f1SGregory Neil Shapiro 		return buf;
1207c2aa98e2SPeter Wemm 
1208c2aa98e2SPeter Wemm 	  case EHOSTDOWN:
1209c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1210c2aa98e2SPeter Wemm 			break;
1211951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
1212c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
12133299c2f1SGregory Neil Shapiro 		return buf;
1214c2aa98e2SPeter Wemm 
1215c2aa98e2SPeter Wemm 	  case ECONNREFUSED:
1216c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1217c2aa98e2SPeter Wemm 			break;
1218951742c4SGregory Neil Shapiro 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
1219c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
12203299c2f1SGregory Neil Shapiro 		return buf;
1221c2aa98e2SPeter Wemm 
1222c2aa98e2SPeter Wemm #if NAMED_BIND
1223c2aa98e2SPeter Wemm 	  case HOST_NOT_FOUND + E_DNSBASE:
1224c2aa98e2SPeter Wemm 		dnsmsg = "host not found";
1225c2aa98e2SPeter Wemm 		break;
1226c2aa98e2SPeter Wemm 
1227c2aa98e2SPeter Wemm 	  case TRY_AGAIN + E_DNSBASE:
1228c2aa98e2SPeter Wemm 		dnsmsg = "host name lookup failure";
1229c2aa98e2SPeter Wemm 		break;
1230c2aa98e2SPeter Wemm 
1231c2aa98e2SPeter Wemm 	  case NO_RECOVERY + E_DNSBASE:
1232c2aa98e2SPeter Wemm 		dnsmsg = "non-recoverable error";
1233c2aa98e2SPeter Wemm 		break;
1234c2aa98e2SPeter Wemm 
1235c2aa98e2SPeter Wemm 	  case NO_DATA + E_DNSBASE:
1236c2aa98e2SPeter Wemm 		dnsmsg = "no data known";
1237c2aa98e2SPeter Wemm 		break;
12383299c2f1SGregory Neil Shapiro #endif /* NAMED_BIND */
1239c2aa98e2SPeter Wemm 
1240c2aa98e2SPeter Wemm 	  case EPERM:
1241c2aa98e2SPeter Wemm 		/* SunOS gives "Not owner" -- this is the POSIX message */
1242c2aa98e2SPeter Wemm 		return "Operation not permitted";
1243c2aa98e2SPeter Wemm 
1244c2aa98e2SPeter Wemm 	/*
1245c2aa98e2SPeter Wemm 	**  Error messages used internally in sendmail.
1246c2aa98e2SPeter Wemm 	*/
1247c2aa98e2SPeter Wemm 
1248c2aa98e2SPeter Wemm 	  case E_SM_OPENTIMEOUT:
1249c2aa98e2SPeter Wemm 		return "Timeout on file open";
1250c2aa98e2SPeter Wemm 
1251c2aa98e2SPeter Wemm 	  case E_SM_NOSLINK:
1252c2aa98e2SPeter Wemm 		return "Symbolic links not allowed";
1253c2aa98e2SPeter Wemm 
1254c2aa98e2SPeter Wemm 	  case E_SM_NOHLINK:
1255c2aa98e2SPeter Wemm 		return "Hard links not allowed";
1256c2aa98e2SPeter Wemm 
1257c2aa98e2SPeter Wemm 	  case E_SM_REGONLY:
1258c2aa98e2SPeter Wemm 		return "Regular files only";
1259c2aa98e2SPeter Wemm 
1260c2aa98e2SPeter Wemm 	  case E_SM_ISEXEC:
1261c2aa98e2SPeter Wemm 		return "Executable files not allowed";
1262c2aa98e2SPeter Wemm 
1263c2aa98e2SPeter Wemm 	  case E_SM_WWDIR:
1264c2aa98e2SPeter Wemm 		return "World writable directory";
1265c2aa98e2SPeter Wemm 
1266c2aa98e2SPeter Wemm 	  case E_SM_GWDIR:
1267c2aa98e2SPeter Wemm 		return "Group writable directory";
1268c2aa98e2SPeter Wemm 
1269c2aa98e2SPeter Wemm 	  case E_SM_FILECHANGE:
1270c2aa98e2SPeter Wemm 		return "File changed after open";
1271c2aa98e2SPeter Wemm 
1272c2aa98e2SPeter Wemm 	  case E_SM_WWFILE:
1273c2aa98e2SPeter Wemm 		return "World writable file";
1274c2aa98e2SPeter Wemm 
1275c2aa98e2SPeter Wemm 	  case E_SM_GWFILE:
1276c2aa98e2SPeter Wemm 		return "Group writable file";
12773299c2f1SGregory Neil Shapiro 
12783299c2f1SGregory Neil Shapiro 	  case E_SM_GRFILE:
12793299c2f1SGregory Neil Shapiro 		return "Group readable file";
12803299c2f1SGregory Neil Shapiro 
12813299c2f1SGregory Neil Shapiro 	  case E_SM_WRFILE:
12823299c2f1SGregory Neil Shapiro 		return "World readable file";
1283c2aa98e2SPeter Wemm 	}
1284c2aa98e2SPeter Wemm 
1285c2aa98e2SPeter Wemm 	if (dnsmsg != NULL)
1286c2aa98e2SPeter Wemm 	{
1287c2aa98e2SPeter Wemm 		bp = buf;
1288951742c4SGregory Neil Shapiro 		bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
1289c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1290c2aa98e2SPeter Wemm 		{
129112ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
129212ed1c7cSGregory Neil Shapiro 				shortenstring(CurHostName, MAXSHORTSTR), ": ");
1293c2aa98e2SPeter Wemm 			bp += strlen(bp);
1294c2aa98e2SPeter Wemm 		}
129512ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1296c2aa98e2SPeter Wemm 		return buf;
1297c2aa98e2SPeter Wemm 	}
1298c2aa98e2SPeter Wemm 
129912ed1c7cSGregory Neil Shapiro #if LDAPMAP
1300da7d7b9cSGregory Neil Shapiro 	if (errnum >= E_LDAPBASE - E_LDAP_SHIM)
13013299c2f1SGregory Neil Shapiro 		return ldap_err2string(errnum - E_LDAPBASE);
13025b0945b5SGregory Neil Shapiro #endif
13033299c2f1SGregory Neil Shapiro 
1304c2aa98e2SPeter Wemm #if HASSTRERROR
130512ed1c7cSGregory Neil Shapiro 	err = strerror(errnum);
130612ed1c7cSGregory Neil Shapiro 	if (err == NULL)
130712ed1c7cSGregory Neil Shapiro 	{
1308951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
130912ed1c7cSGregory Neil Shapiro 		return buf;
131012ed1c7cSGregory Neil Shapiro 	}
131112ed1c7cSGregory Neil Shapiro 	return err;
13123299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1313c2aa98e2SPeter Wemm 	if (errnum > 0 && errnum < sys_nerr)
13143299c2f1SGregory Neil Shapiro 		return sys_errlist[errnum];
1315c2aa98e2SPeter Wemm 
1316951742c4SGregory Neil Shapiro 	(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
13173299c2f1SGregory Neil Shapiro 	return buf;
13183299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1319c2aa98e2SPeter Wemm }
1320