xref: /freebsd/contrib/sendmail/src/err.c (revision 4313cc83440a39bdf976f955b1d4d3f3c4d1552f)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2003, 2010 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 
16*4313cc83SGregory 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 */
213299c2f1SGregory Neil Shapiro #endif /* LDAPMAP */
223299c2f1SGregory Neil Shapiro 
233299c2f1SGregory Neil Shapiro static void	putoutmsg __P((char *, bool, bool));
243299c2f1SGregory Neil Shapiro static void	puterrmsg __P((char *));
253299c2f1SGregory Neil Shapiro static char	*fmtmsg __P((char *, const char *, const char *, const char *,
263299c2f1SGregory Neil Shapiro 			     int, const char *, va_list));
27c2aa98e2SPeter Wemm 
28c2aa98e2SPeter Wemm /*
2912ed1c7cSGregory Neil Shapiro **  FATAL_ERROR -- handle a fatal exception
3012ed1c7cSGregory Neil Shapiro **
3112ed1c7cSGregory Neil Shapiro **	This function is installed as the default exception handler
3212ed1c7cSGregory Neil Shapiro **	in the main sendmail process, and in all child processes
3312ed1c7cSGregory Neil Shapiro **	that we create.  Its job is to handle exceptions that are not
3412ed1c7cSGregory Neil Shapiro **	handled at a lower level.
3512ed1c7cSGregory Neil Shapiro **
3612ed1c7cSGregory Neil Shapiro **	The theory is that unhandled exceptions will be 'fatal' class
3712ed1c7cSGregory Neil Shapiro **	exceptions (with an "F:" prefix), such as the out-of-memory
3812ed1c7cSGregory Neil Shapiro **	exception "F:sm.heap".  As such, they are handled by exiting
3912ed1c7cSGregory Neil Shapiro **	the process in exactly the same way that xalloc() in Sendmail 8.10
4012ed1c7cSGregory Neil Shapiro **	exits the process when it fails due to lack of memory:
4112ed1c7cSGregory Neil Shapiro **	we call syserr with a message beginning with "!".
4212ed1c7cSGregory Neil Shapiro **
4312ed1c7cSGregory Neil Shapiro **	Parameters:
4412ed1c7cSGregory Neil Shapiro **		exc -- exception which is terminating this process
4512ed1c7cSGregory Neil Shapiro **
4612ed1c7cSGregory Neil Shapiro **	Returns:
4712ed1c7cSGregory Neil Shapiro **		none
4812ed1c7cSGregory Neil Shapiro */
4912ed1c7cSGregory Neil Shapiro 
5012ed1c7cSGregory Neil Shapiro void
5112ed1c7cSGregory Neil Shapiro fatal_error(exc)
5212ed1c7cSGregory Neil Shapiro 	SM_EXC_T *exc;
5312ed1c7cSGregory Neil Shapiro {
5412ed1c7cSGregory Neil Shapiro 	static char buf[256];
5512ed1c7cSGregory Neil Shapiro 	SM_FILE_T f;
5612ed1c7cSGregory Neil Shapiro 
5712ed1c7cSGregory Neil Shapiro 	/*
5812ed1c7cSGregory Neil Shapiro 	**  This function may be called when the heap is exhausted.
5912ed1c7cSGregory Neil Shapiro 	**  The following code writes the message for 'exc' into our
6012ed1c7cSGregory Neil Shapiro 	**  static buffer without allocating memory or raising exceptions.
6112ed1c7cSGregory Neil Shapiro 	*/
6212ed1c7cSGregory Neil Shapiro 
6312ed1c7cSGregory Neil Shapiro 	sm_strio_init(&f, buf, sizeof(buf));
6412ed1c7cSGregory Neil Shapiro 	sm_exc_write(exc, &f);
6512ed1c7cSGregory Neil Shapiro 	(void) sm_io_flush(&f, SM_TIME_DEFAULT);
6612ed1c7cSGregory Neil Shapiro 
6712ed1c7cSGregory Neil Shapiro 	/*
6812ed1c7cSGregory Neil Shapiro 	**  Terminate the process after logging an error and cleaning up.
6912ed1c7cSGregory Neil Shapiro 	**  Problems:
7012ed1c7cSGregory Neil Shapiro 	**  - syserr decides what class of error this is by looking at errno.
7112ed1c7cSGregory Neil Shapiro 	**    That's no good; we should look at the exc structure.
7212ed1c7cSGregory Neil Shapiro 	**  - The cleanup code should be moved out of syserr
7312ed1c7cSGregory Neil Shapiro 	**    and into individual exception handlers
7412ed1c7cSGregory Neil Shapiro 	**    that are part of the module they clean up after.
7512ed1c7cSGregory Neil Shapiro 	*/
7612ed1c7cSGregory Neil Shapiro 
7712ed1c7cSGregory Neil Shapiro 	errno = ENOMEM;
7812ed1c7cSGregory Neil Shapiro 	syserr("!%s", buf);
7912ed1c7cSGregory Neil Shapiro }
8012ed1c7cSGregory Neil Shapiro 
8112ed1c7cSGregory Neil Shapiro /*
82c2aa98e2SPeter Wemm **  SYSERR -- Print error message.
83c2aa98e2SPeter Wemm **
8412ed1c7cSGregory Neil Shapiro **	Prints an error message via sm_io_printf to the diagnostic output.
85c2aa98e2SPeter Wemm **
86c2aa98e2SPeter Wemm **	If the first character of the syserr message is `!' it will
87c2aa98e2SPeter Wemm **	log this as an ALERT message and exit immediately.  This can
88c2aa98e2SPeter Wemm **	leave queue files in an indeterminate state, so it should not
89c2aa98e2SPeter Wemm **	be used lightly.
90c2aa98e2SPeter Wemm **
9112ed1c7cSGregory Neil Shapiro **	If the first character of the syserr message is '!' or '@'
9212ed1c7cSGregory Neil Shapiro **	then syserr knows that the process is about to be terminated,
9312ed1c7cSGregory Neil Shapiro **	so the SMTP reply code defaults to 421.  Otherwise, the
9412ed1c7cSGregory Neil Shapiro **	reply code defaults to 451 or 554, depending on errno.
9512ed1c7cSGregory Neil Shapiro **
96c2aa98e2SPeter Wemm **	Parameters:
9712ed1c7cSGregory Neil Shapiro **		fmt -- the format string.  An optional '!' or '@',
9812ed1c7cSGregory Neil Shapiro **			followed by an optional three-digit SMTP
9912ed1c7cSGregory Neil Shapiro **			reply code, followed by message text.
100c2aa98e2SPeter Wemm **		(others) -- parameters
101c2aa98e2SPeter Wemm **
102c2aa98e2SPeter Wemm **	Returns:
103c2aa98e2SPeter Wemm **		none
10412ed1c7cSGregory Neil Shapiro **		Raises E:mta.quickabort if QuickAbort is set.
105c2aa98e2SPeter Wemm **
106c2aa98e2SPeter Wemm **	Side Effects:
107c2aa98e2SPeter Wemm **		increments Errors.
108c2aa98e2SPeter Wemm **		sets ExitStat.
109c2aa98e2SPeter Wemm */
110c2aa98e2SPeter Wemm 
111c2aa98e2SPeter Wemm char		MsgBuf[BUFSIZ*2];	/* text of most recent message */
112951742c4SGregory Neil Shapiro static char	HeldMessageBuf[sizeof(MsgBuf)];	/* for held messages */
113c2aa98e2SPeter Wemm 
114c2aa98e2SPeter Wemm #if NAMED_BIND && !defined(NO_DATA)
115c2aa98e2SPeter Wemm # define NO_DATA	NO_ADDRESS
1163299c2f1SGregory Neil Shapiro #endif /* NAMED_BIND && !defined(NO_DATA) */
117c2aa98e2SPeter Wemm 
118c2aa98e2SPeter Wemm void
119c2aa98e2SPeter Wemm /*VARARGS1*/
120c2aa98e2SPeter Wemm #ifdef __STDC__
121c2aa98e2SPeter Wemm syserr(const char *fmt, ...)
1223299c2f1SGregory Neil Shapiro #else /* __STDC__ */
123c2aa98e2SPeter Wemm syserr(fmt, va_alist)
124c2aa98e2SPeter Wemm 	const char *fmt;
125c2aa98e2SPeter Wemm 	va_dcl
1263299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
127c2aa98e2SPeter Wemm {
128c2aa98e2SPeter Wemm 	register char *p;
1293299c2f1SGregory Neil Shapiro 	int save_errno = errno;
130c2aa98e2SPeter Wemm 	bool panic;
13112ed1c7cSGregory Neil Shapiro 	bool exiting;
1323299c2f1SGregory Neil Shapiro 	char *user;
1333299c2f1SGregory Neil Shapiro 	char *enhsc;
1343299c2f1SGregory Neil Shapiro 	char *errtxt;
135c2aa98e2SPeter Wemm 	struct passwd *pw;
136c2aa98e2SPeter Wemm 	char ubuf[80];
13712ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
138c2aa98e2SPeter Wemm 
13912ed1c7cSGregory Neil Shapiro 	switch (*fmt)
140c2aa98e2SPeter Wemm 	{
14112ed1c7cSGregory Neil Shapiro 	  case '!':
14212ed1c7cSGregory Neil Shapiro 		++fmt;
14312ed1c7cSGregory Neil Shapiro 		panic = true;
14412ed1c7cSGregory Neil Shapiro 		exiting = true;
14512ed1c7cSGregory Neil Shapiro 		break;
14612ed1c7cSGregory Neil Shapiro 	  case '@':
14712ed1c7cSGregory Neil Shapiro 		++fmt;
14812ed1c7cSGregory Neil Shapiro 		panic = false;
14912ed1c7cSGregory Neil Shapiro 		exiting = true;
15012ed1c7cSGregory Neil Shapiro 		break;
15112ed1c7cSGregory Neil Shapiro 	  default:
15212ed1c7cSGregory Neil Shapiro 		panic = false;
15312ed1c7cSGregory Neil Shapiro 		exiting = false;
15412ed1c7cSGregory Neil Shapiro 		break;
155c2aa98e2SPeter Wemm 	}
156c2aa98e2SPeter Wemm 
157c2aa98e2SPeter Wemm 	/* format and output the error message */
15812ed1c7cSGregory Neil Shapiro 	if (exiting)
15912ed1c7cSGregory Neil Shapiro 	{
16012ed1c7cSGregory Neil Shapiro 		/*
16112ed1c7cSGregory Neil Shapiro 		**  Since we are terminating the process,
16212ed1c7cSGregory Neil Shapiro 		**  we are aborting the entire SMTP session,
16312ed1c7cSGregory Neil Shapiro 		**  rather than just the current transaction.
16412ed1c7cSGregory Neil Shapiro 		*/
16512ed1c7cSGregory Neil Shapiro 
16612ed1c7cSGregory Neil Shapiro 		p = "421";
16712ed1c7cSGregory Neil Shapiro 		enhsc = "4.0.0";
16812ed1c7cSGregory Neil Shapiro 	}
16912ed1c7cSGregory Neil Shapiro 	else if (save_errno == 0)
1703299c2f1SGregory Neil Shapiro 	{
171c2aa98e2SPeter Wemm 		p = "554";
1723299c2f1SGregory Neil Shapiro 		enhsc = "5.0.0";
1733299c2f1SGregory Neil Shapiro 	}
174c2aa98e2SPeter Wemm 	else
1753299c2f1SGregory Neil Shapiro 	{
176c2aa98e2SPeter Wemm 		p = "451";
1773299c2f1SGregory Neil Shapiro 		enhsc = "4.0.0";
1783299c2f1SGregory Neil Shapiro 	}
17912ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
1803299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
18112ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
182c2aa98e2SPeter Wemm 	puterrmsg(MsgBuf);
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
185c2aa98e2SPeter Wemm 	if (!panic && CurEnv != NULL)
186c2aa98e2SPeter Wemm 	{
18712ed1c7cSGregory Neil Shapiro 		char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
18812ed1c7cSGregory Neil Shapiro 
18912ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
190c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
19112ed1c7cSGregory Neil Shapiro 		CurEnv->e_message = nmsg;
192c2aa98e2SPeter Wemm 	}
193c2aa98e2SPeter Wemm 
194c2aa98e2SPeter Wemm 	/* determine exit status if not already set */
195c2aa98e2SPeter Wemm 	if (ExitStat == EX_OK)
196c2aa98e2SPeter Wemm 	{
1973299c2f1SGregory Neil Shapiro 		if (save_errno == 0)
198c2aa98e2SPeter Wemm 			ExitStat = EX_SOFTWARE;
199c2aa98e2SPeter Wemm 		else
200c2aa98e2SPeter Wemm 			ExitStat = EX_OSERR;
201c2aa98e2SPeter Wemm 		if (tTd(54, 1))
20212ed1c7cSGregory Neil Shapiro 			sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
203c2aa98e2SPeter Wemm 	}
204c2aa98e2SPeter Wemm 
205c0c4794dSGregory Neil Shapiro 	pw = sm_getpwuid(RealUid);
206c2aa98e2SPeter Wemm 	if (pw != NULL)
2073299c2f1SGregory Neil Shapiro 		user = pw->pw_name;
208c2aa98e2SPeter Wemm 	else
209c2aa98e2SPeter Wemm 	{
2103299c2f1SGregory Neil Shapiro 		user = ubuf;
211951742c4SGregory Neil Shapiro 		(void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid);
212c2aa98e2SPeter Wemm 	}
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 	if (LogLevel > 0)
215c2aa98e2SPeter Wemm 		sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
216c2aa98e2SPeter Wemm 			  CurEnv == NULL ? NOQID : CurEnv->e_id,
217c2aa98e2SPeter Wemm 			  "SYSERR(%s): %.900s",
2183299c2f1SGregory Neil Shapiro 			  user, errtxt);
2193299c2f1SGregory Neil Shapiro 	switch (save_errno)
220c2aa98e2SPeter Wemm 	{
221c2aa98e2SPeter Wemm 	  case EBADF:
222c2aa98e2SPeter Wemm 	  case ENFILE:
223c2aa98e2SPeter Wemm 	  case EMFILE:
224c2aa98e2SPeter Wemm 	  case ENOTTY:
225c2aa98e2SPeter Wemm #ifdef EFBIG
226c2aa98e2SPeter Wemm 	  case EFBIG:
2273299c2f1SGregory Neil Shapiro #endif /* EFBIG */
228c2aa98e2SPeter Wemm #ifdef ESPIPE
229c2aa98e2SPeter Wemm 	  case ESPIPE:
2303299c2f1SGregory Neil Shapiro #endif /* ESPIPE */
231c2aa98e2SPeter Wemm #ifdef EPIPE
232c2aa98e2SPeter Wemm 	  case EPIPE:
2333299c2f1SGregory Neil Shapiro #endif /* EPIPE */
234c2aa98e2SPeter Wemm #ifdef ENOBUFS
235c2aa98e2SPeter Wemm 	  case ENOBUFS:
2363299c2f1SGregory Neil Shapiro #endif /* ENOBUFS */
237c2aa98e2SPeter Wemm #ifdef ESTALE
238c2aa98e2SPeter Wemm 	  case ESTALE:
2393299c2f1SGregory Neil Shapiro #endif /* ESTALE */
24012ed1c7cSGregory Neil Shapiro 		printopenfds(true);
241bfb62e91SGregory Neil Shapiro 		mci_dump_all(smioout, true);
242c2aa98e2SPeter Wemm 		break;
243c2aa98e2SPeter Wemm 	}
244c2aa98e2SPeter Wemm 	if (panic)
245c2aa98e2SPeter Wemm 	{
24612ed1c7cSGregory Neil Shapiro #if XLA
247c2aa98e2SPeter Wemm 		xla_all_end();
2483299c2f1SGregory Neil Shapiro #endif /* XLA */
2493299c2f1SGregory Neil Shapiro 		sync_queue_time();
250c2aa98e2SPeter Wemm 		if (tTd(0, 1))
251c2aa98e2SPeter Wemm 			abort();
252c2aa98e2SPeter Wemm 		exit(EX_OSERR);
253c2aa98e2SPeter Wemm 	}
254c2aa98e2SPeter Wemm 	errno = 0;
255c2aa98e2SPeter Wemm 	if (QuickAbort)
25612ed1c7cSGregory Neil Shapiro 		sm_exc_raisenew_x(&EtypeQuickAbort, 2);
257c2aa98e2SPeter Wemm }
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__
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 }
34312ed1c7cSGregory Neil Shapiro /*
3443299c2f1SGregory Neil Shapiro **  USRERRENH -- Signal user error.
3453299c2f1SGregory Neil Shapiro **
3463299c2f1SGregory Neil Shapiro **	Same as usrerr but with enhanced status code.
3473299c2f1SGregory Neil Shapiro **
3483299c2f1SGregory Neil Shapiro **	Parameters:
3493299c2f1SGregory Neil Shapiro **		enhsc -- the enhanced status code.
3503299c2f1SGregory Neil Shapiro **		fmt -- the format string.  If it does not begin with
35112ed1c7cSGregory Neil Shapiro **			a three-digit SMTP reply code, 550 is assumed.
35212ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf strings
3533299c2f1SGregory Neil Shapiro **
3543299c2f1SGregory Neil Shapiro **	Returns:
3553299c2f1SGregory Neil Shapiro **		none
35612ed1c7cSGregory Neil Shapiro **		Raises E:mta.quickabort if QuickAbort is set.
3573299c2f1SGregory Neil Shapiro **
3583299c2f1SGregory Neil Shapiro **	Side Effects:
3593299c2f1SGregory Neil Shapiro **		increments Errors.
3603299c2f1SGregory Neil Shapiro */
3613299c2f1SGregory Neil Shapiro 
3626f9c8e5bSGregory Neil Shapiro /*VARARGS2*/
3633299c2f1SGregory Neil Shapiro void
3643299c2f1SGregory Neil Shapiro #ifdef __STDC__
3653299c2f1SGregory Neil Shapiro usrerrenh(char *enhsc, const char *fmt, ...)
3663299c2f1SGregory Neil Shapiro #else /* __STDC__ */
3673299c2f1SGregory Neil Shapiro usrerrenh(enhsc, fmt, va_alist)
3683299c2f1SGregory Neil Shapiro 	char *enhsc;
3693299c2f1SGregory Neil Shapiro 	const char *fmt;
3703299c2f1SGregory Neil Shapiro 	va_dcl
3713299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
3723299c2f1SGregory Neil Shapiro {
3733299c2f1SGregory Neil Shapiro 	char *errtxt;
37412ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
3753299c2f1SGregory Neil Shapiro 
3763299c2f1SGregory Neil Shapiro 	if (enhsc == NULL || *enhsc == '\0')
3773299c2f1SGregory Neil Shapiro 	{
3783299c2f1SGregory Neil Shapiro 		if (fmt[0] == '5' || fmt[0] == '6')
3793299c2f1SGregory Neil Shapiro 			enhsc = "5.0.0";
3803299c2f1SGregory Neil Shapiro 		else if (fmt[0] == '4' || fmt[0] == '8')
3813299c2f1SGregory Neil Shapiro 			enhsc = "4.0.0";
3823299c2f1SGregory Neil Shapiro 		else if (fmt[0] == '2')
3833299c2f1SGregory Neil Shapiro 			enhsc = "2.0.0";
3843299c2f1SGregory Neil Shapiro 	}
38512ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, fmt);
38612ed1c7cSGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
38712ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
3883299c2f1SGregory Neil Shapiro 
3893299c2f1SGregory Neil Shapiro 	if (SuprErrs)
3903299c2f1SGregory Neil Shapiro 		return;
3913299c2f1SGregory Neil Shapiro 
3923299c2f1SGregory Neil Shapiro 	/* save this message for mailq printing */
3933299c2f1SGregory Neil Shapiro 	switch (MsgBuf[0])
3943299c2f1SGregory Neil Shapiro 	{
3953299c2f1SGregory Neil Shapiro 	  case '4':
3963299c2f1SGregory Neil Shapiro 	  case '8':
3973299c2f1SGregory Neil Shapiro 		if (CurEnv->e_message != NULL)
3983299c2f1SGregory Neil Shapiro 			break;
3993299c2f1SGregory Neil Shapiro 
4003299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
4013299c2f1SGregory Neil Shapiro 
4023299c2f1SGregory Neil Shapiro 	  case '5':
4033299c2f1SGregory Neil Shapiro 	  case '6':
40412ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
405c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
4063299c2f1SGregory Neil Shapiro 		if (MsgBuf[0] == '6')
4073299c2f1SGregory Neil Shapiro 		{
4083299c2f1SGregory Neil Shapiro 			char buf[MAXLINE];
4093299c2f1SGregory Neil Shapiro 
410951742c4SGregory Neil Shapiro 			(void) sm_snprintf(buf, sizeof(buf),
41112ed1c7cSGregory Neil Shapiro 					   "Postmaster warning: %.*s",
412951742c4SGregory Neil Shapiro 					   (int) sizeof(buf) - 22, errtxt);
41312ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
41412ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, buf);
4153299c2f1SGregory Neil Shapiro 		}
4163299c2f1SGregory Neil Shapiro 		else
4173299c2f1SGregory Neil Shapiro 		{
41812ed1c7cSGregory Neil Shapiro 			CurEnv->e_message =
41912ed1c7cSGregory Neil Shapiro 				sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
4203299c2f1SGregory Neil Shapiro 		}
4213299c2f1SGregory Neil Shapiro 		break;
4223299c2f1SGregory Neil Shapiro 	}
4233299c2f1SGregory Neil Shapiro 
4243299c2f1SGregory Neil Shapiro 	puterrmsg(MsgBuf);
4253299c2f1SGregory Neil Shapiro 	if (LogLevel > 3 && LogUsrErrs)
4263299c2f1SGregory Neil Shapiro 		sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
427c2aa98e2SPeter Wemm 	if (QuickAbort)
42812ed1c7cSGregory Neil Shapiro 		sm_exc_raisenew_x(&EtypeQuickAbort, 1);
429c2aa98e2SPeter Wemm }
4306f9c8e5bSGregory Neil Shapiro 
43112ed1c7cSGregory Neil Shapiro /*
432c2aa98e2SPeter Wemm **  MESSAGE -- print message (not necessarily an error)
433c2aa98e2SPeter Wemm **
434c2aa98e2SPeter Wemm **	Parameters:
43512ed1c7cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- it can begin with
436c2aa98e2SPeter Wemm **			an SMTP reply code.  If not, 050 is assumed.
43712ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
438c2aa98e2SPeter Wemm **
439c2aa98e2SPeter Wemm **	Returns:
440c2aa98e2SPeter Wemm **		none
441c2aa98e2SPeter Wemm **
442c2aa98e2SPeter Wemm **	Side Effects:
443c2aa98e2SPeter Wemm **		none.
444c2aa98e2SPeter Wemm */
445c2aa98e2SPeter Wemm 
446c2aa98e2SPeter Wemm /*VARARGS1*/
447c2aa98e2SPeter Wemm void
448c2aa98e2SPeter Wemm #ifdef __STDC__
449c2aa98e2SPeter Wemm message(const char *msg, ...)
4503299c2f1SGregory Neil Shapiro #else /* __STDC__ */
451c2aa98e2SPeter Wemm message(msg, va_alist)
452c2aa98e2SPeter Wemm 	const char *msg;
453c2aa98e2SPeter Wemm 	va_dcl
4543299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
455c2aa98e2SPeter Wemm {
4563299c2f1SGregory Neil Shapiro 	char *errtxt;
45712ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
458c2aa98e2SPeter Wemm 
459c2aa98e2SPeter Wemm 	errno = 0;
46012ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
4613299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
46212ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
46312ed1c7cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
464c2aa98e2SPeter Wemm 
465c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
466c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
467c2aa98e2SPeter Wemm 	{
468c2aa98e2SPeter Wemm 	  case '4':
469c2aa98e2SPeter Wemm 	  case '8':
470c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
471c2aa98e2SPeter Wemm 			break;
4723299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
473c2aa98e2SPeter Wemm 
474c2aa98e2SPeter Wemm 	  case '5':
47512ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
476c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
4776f9c8e5bSGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
478c2aa98e2SPeter Wemm 		break;
479c2aa98e2SPeter Wemm 	}
480c2aa98e2SPeter Wemm }
4816f9c8e5bSGregory Neil Shapiro 
4826f9c8e5bSGregory Neil Shapiro 
48312ed1c7cSGregory Neil Shapiro /*
484c2aa98e2SPeter Wemm **  NMESSAGE -- print message (not necessarily an error)
485c2aa98e2SPeter Wemm **
486c2aa98e2SPeter Wemm **	Just like "message" except it never puts the to... tag on.
487c2aa98e2SPeter Wemm **
488c2aa98e2SPeter Wemm **	Parameters:
48912ed1c7cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- if it begins
490c2aa98e2SPeter Wemm **			with a three digit SMTP reply code, that is used,
491c2aa98e2SPeter Wemm **			otherwise 050 is assumed.
49212ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
493c2aa98e2SPeter Wemm **
494c2aa98e2SPeter Wemm **	Returns:
495c2aa98e2SPeter Wemm **		none
496c2aa98e2SPeter Wemm **
497c2aa98e2SPeter Wemm **	Side Effects:
498c2aa98e2SPeter Wemm **		none.
499c2aa98e2SPeter Wemm */
500c2aa98e2SPeter Wemm 
501c2aa98e2SPeter Wemm /*VARARGS1*/
502c2aa98e2SPeter Wemm void
503c2aa98e2SPeter Wemm #ifdef __STDC__
504c2aa98e2SPeter Wemm nmessage(const char *msg, ...)
5053299c2f1SGregory Neil Shapiro #else /* __STDC__ */
506c2aa98e2SPeter Wemm nmessage(msg, va_alist)
507c2aa98e2SPeter Wemm 	const char *msg;
508c2aa98e2SPeter Wemm 	va_dcl
5093299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
510c2aa98e2SPeter Wemm {
5113299c2f1SGregory Neil Shapiro 	char *errtxt;
51212ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
513c2aa98e2SPeter Wemm 
514c2aa98e2SPeter Wemm 	errno = 0;
51512ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
5163299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
5173299c2f1SGregory Neil Shapiro 			(char *) NULL, 0, msg, ap);
51812ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
51912ed1c7cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
520c2aa98e2SPeter Wemm 
521c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
522c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
523c2aa98e2SPeter Wemm 	{
524c2aa98e2SPeter Wemm 	  case '4':
525c2aa98e2SPeter Wemm 	  case '8':
526c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
527c2aa98e2SPeter Wemm 			break;
5283299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
529c2aa98e2SPeter Wemm 
530c2aa98e2SPeter Wemm 	  case '5':
53112ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
532c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
533951742c4SGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
534c2aa98e2SPeter Wemm 		break;
535c2aa98e2SPeter Wemm 	}
536c2aa98e2SPeter Wemm }
53712ed1c7cSGregory Neil Shapiro /*
538c2aa98e2SPeter Wemm **  PUTOUTMSG -- output error message to transcript and channel
539c2aa98e2SPeter Wemm **
540c2aa98e2SPeter Wemm **	Parameters:
541c2aa98e2SPeter Wemm **		msg -- message to output (in SMTP format).
54212ed1c7cSGregory Neil Shapiro **		holdmsg -- if true, don't output a copy of the message to
543c2aa98e2SPeter Wemm **			our output channel.
54412ed1c7cSGregory Neil Shapiro **		heldmsg -- if true, this is a previously held message;
545c2aa98e2SPeter Wemm **			don't log it to the transcript file.
546c2aa98e2SPeter Wemm **
547c2aa98e2SPeter Wemm **	Returns:
548c2aa98e2SPeter Wemm **		none.
549c2aa98e2SPeter Wemm **
550c2aa98e2SPeter Wemm **	Side Effects:
551c2aa98e2SPeter Wemm **		Outputs msg to the transcript.
552c2aa98e2SPeter Wemm **		If appropriate, outputs it to the channel.
553c2aa98e2SPeter Wemm **		Deletes SMTP reply code number as appropriate.
554c2aa98e2SPeter Wemm */
555c2aa98e2SPeter Wemm 
5563299c2f1SGregory Neil Shapiro static void
557c2aa98e2SPeter Wemm putoutmsg(msg, holdmsg, heldmsg)
558c2aa98e2SPeter Wemm 	char *msg;
559c2aa98e2SPeter Wemm 	bool holdmsg;
560c2aa98e2SPeter Wemm 	bool heldmsg;
561c2aa98e2SPeter Wemm {
562c2aa98e2SPeter Wemm 	char msgcode = msg[0];
563951742c4SGregory Neil Shapiro 	char *errtxt = msg;
564951742c4SGregory Neil Shapiro 	char *id;
565c2aa98e2SPeter Wemm 
566c2aa98e2SPeter Wemm 	/* display for debugging */
567c2aa98e2SPeter Wemm 	if (tTd(54, 8))
56812ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
569c2aa98e2SPeter Wemm 			heldmsg ? " (held)" : "");
570c2aa98e2SPeter Wemm 
571c2aa98e2SPeter Wemm 	/* map warnings to something SMTP can handle */
572c2aa98e2SPeter Wemm 	if (msgcode == '6')
573c2aa98e2SPeter Wemm 		msg[0] = '5';
574c2aa98e2SPeter Wemm 	else if (msgcode == '8')
575c2aa98e2SPeter Wemm 		msg[0] = '4';
576951742c4SGregory Neil Shapiro 	id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
577c2aa98e2SPeter Wemm 
578c2aa98e2SPeter Wemm 	/* output to transcript if serious */
579c2aa98e2SPeter Wemm 	if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
580c2aa98e2SPeter Wemm 	    strchr("45", msg[0]) != NULL)
58112ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
58212ed1c7cSGregory Neil Shapiro 				     msg);
583c2aa98e2SPeter Wemm 
58412ed1c7cSGregory Neil Shapiro 	if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
585951742c4SGregory Neil Shapiro 		sm_syslog(LOG_INFO, id,
58612ed1c7cSGregory Neil Shapiro 			  "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
58712ed1c7cSGregory Neil Shapiro 			  heldmsg ? " (held)" : "");
588c2aa98e2SPeter Wemm 
589c2aa98e2SPeter Wemm 	if (msgcode == '8')
590c2aa98e2SPeter Wemm 		msg[0] = '0';
591c2aa98e2SPeter Wemm 
592c2aa98e2SPeter Wemm 	/* output to channel if appropriate */
593c2aa98e2SPeter Wemm 	if (!Verbose && msg[0] == '0')
594c2aa98e2SPeter Wemm 		return;
595c2aa98e2SPeter Wemm 	if (holdmsg)
596c2aa98e2SPeter Wemm 	{
597c2aa98e2SPeter Wemm 		/* save for possible future display */
598c2aa98e2SPeter Wemm 		msg[0] = msgcode;
5993299c2f1SGregory Neil Shapiro 		if (HeldMessageBuf[0] == '5' && msgcode == '4')
6003299c2f1SGregory Neil Shapiro 			return;
601951742c4SGregory Neil Shapiro 		(void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
602c2aa98e2SPeter Wemm 		return;
603c2aa98e2SPeter Wemm 	}
604c2aa98e2SPeter Wemm 
60512ed1c7cSGregory Neil Shapiro 	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
606c2aa98e2SPeter Wemm 
607c2aa98e2SPeter Wemm 	if (OutChannel == NULL)
608c2aa98e2SPeter Wemm 		return;
609c2aa98e2SPeter Wemm 
6103299c2f1SGregory Neil Shapiro 	/* find actual text of error (after SMTP status codes) */
6113299c2f1SGregory Neil Shapiro 	if (ISSMTPREPLY(errtxt))
6123299c2f1SGregory Neil Shapiro 	{
6133299c2f1SGregory Neil Shapiro 		int l;
6143299c2f1SGregory Neil Shapiro 
6153299c2f1SGregory Neil Shapiro 		errtxt += 4;
6163299c2f1SGregory Neil Shapiro 		l = isenhsc(errtxt, ' ');
6173299c2f1SGregory Neil Shapiro 		if (l <= 0)
6183299c2f1SGregory Neil Shapiro 			l = isenhsc(errtxt, '\0');
6193299c2f1SGregory Neil Shapiro 		if (l > 0)
6203299c2f1SGregory Neil Shapiro 			errtxt += l + 1;
6213299c2f1SGregory Neil Shapiro 	}
6223299c2f1SGregory Neil Shapiro 
623c2aa98e2SPeter Wemm 	/* if DisConnected, OutChannel now points to the transcript */
624c2aa98e2SPeter Wemm 	if (!DisConnected &&
625c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
62612ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
62712ed1c7cSGregory Neil Shapiro 				     msg);
628c2aa98e2SPeter Wemm 	else
62912ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
63012ed1c7cSGregory Neil Shapiro 				     errtxt);
631c2aa98e2SPeter Wemm 	if (TrafficLogFile != NULL)
63212ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
63312ed1c7cSGregory Neil Shapiro 				     "%05d >>> %s\n", (int) CurrentPid,
63412ed1c7cSGregory Neil Shapiro 				     (OpMode == MD_SMTP || OpMode == MD_DAEMON)
63512ed1c7cSGregory Neil Shapiro 					? msg : errtxt);
63612ed1c7cSGregory Neil Shapiro #if !PIPELINING
63712ed1c7cSGregory Neil Shapiro 	/* XXX can't flush here for SMTP pipelining */
638c2aa98e2SPeter Wemm 	if (msg[3] == ' ')
63912ed1c7cSGregory Neil Shapiro 		(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
64012ed1c7cSGregory Neil Shapiro 	if (!sm_io_error(OutChannel) || DisConnected)
641c2aa98e2SPeter Wemm 		return;
642c2aa98e2SPeter Wemm 
643c2aa98e2SPeter Wemm 	/*
644c2aa98e2SPeter Wemm 	**  Error on output -- if reporting lost channel, just ignore it.
645c2aa98e2SPeter Wemm 	**  Also, ignore errors from QUIT response (221 message) -- some
646c2aa98e2SPeter Wemm 	**	rude servers don't read result.
647c2aa98e2SPeter Wemm 	*/
648c2aa98e2SPeter Wemm 
64912ed1c7cSGregory Neil Shapiro 	if (InChannel == NULL || sm_io_eof(InChannel) ||
65012ed1c7cSGregory Neil Shapiro 	    sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
651c2aa98e2SPeter Wemm 		return;
652c2aa98e2SPeter Wemm 
653c2aa98e2SPeter Wemm 	/* can't call syserr, 'cause we are using MsgBuf */
65412ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
655c2aa98e2SPeter Wemm 	if (LogLevel > 0)
656951742c4SGregory Neil Shapiro 		sm_syslog(LOG_CRIT, id,
657c2aa98e2SPeter Wemm 			  "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
65812ed1c7cSGregory Neil Shapiro 			  CURHOSTNAME,
65912ed1c7cSGregory Neil Shapiro 			  shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
66012ed1c7cSGregory Neil Shapiro #endif /* !PIPELINING */
661c2aa98e2SPeter Wemm }
66212ed1c7cSGregory Neil Shapiro /*
663c2aa98e2SPeter Wemm **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
664c2aa98e2SPeter Wemm **
665c2aa98e2SPeter Wemm **	Parameters:
666c2aa98e2SPeter Wemm **		msg -- the message to output.
667c2aa98e2SPeter Wemm **
668c2aa98e2SPeter Wemm **	Returns:
669c2aa98e2SPeter Wemm **		none.
670c2aa98e2SPeter Wemm **
671c2aa98e2SPeter Wemm **	Side Effects:
672c2aa98e2SPeter Wemm **		Sets the fatal error bit in the envelope as appropriate.
673c2aa98e2SPeter Wemm */
674c2aa98e2SPeter Wemm 
6753299c2f1SGregory Neil Shapiro static void
676c2aa98e2SPeter Wemm puterrmsg(msg)
677c2aa98e2SPeter Wemm 	char *msg;
678c2aa98e2SPeter Wemm {
679c2aa98e2SPeter Wemm 	char msgcode = msg[0];
680c2aa98e2SPeter Wemm 
681c2aa98e2SPeter Wemm 	/* output the message as usual */
68212ed1c7cSGregory Neil Shapiro 	putoutmsg(msg, HoldErrs, false);
683c2aa98e2SPeter Wemm 
684c2aa98e2SPeter Wemm 	/* be careful about multiple error messages */
685c2aa98e2SPeter Wemm 	if (OnlyOneError)
68612ed1c7cSGregory Neil Shapiro 		HoldErrs = true;
687c2aa98e2SPeter Wemm 
688c2aa98e2SPeter Wemm 	/* signal the error */
689c2aa98e2SPeter Wemm 	Errors++;
690c2aa98e2SPeter Wemm 
691c2aa98e2SPeter Wemm 	if (CurEnv == NULL)
692c2aa98e2SPeter Wemm 		return;
693c2aa98e2SPeter Wemm 
694c2aa98e2SPeter Wemm 	if (msgcode == '6')
695c2aa98e2SPeter Wemm 	{
696c2aa98e2SPeter Wemm 		/* notify the postmaster */
697c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_PM_NOTIFY;
698c2aa98e2SPeter Wemm 	}
699c2aa98e2SPeter Wemm 	else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
700c2aa98e2SPeter Wemm 	{
701c2aa98e2SPeter Wemm 		/* mark long-term fatal errors */
702c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_FATALERRS;
703c2aa98e2SPeter Wemm 	}
704c2aa98e2SPeter Wemm }
70512ed1c7cSGregory Neil Shapiro /*
7063299c2f1SGregory Neil Shapiro **  ISENHSC -- check whether a string contains an enhanced status code
7073299c2f1SGregory Neil Shapiro **
7083299c2f1SGregory Neil Shapiro **	Parameters:
7093299c2f1SGregory Neil Shapiro **		s -- string with possible enhanced status code.
7103299c2f1SGregory Neil Shapiro **		delim -- delim for enhanced status code.
7113299c2f1SGregory Neil Shapiro **
7123299c2f1SGregory Neil Shapiro **	Returns:
7133299c2f1SGregory Neil Shapiro **		0  -- no enhanced status code.
7143299c2f1SGregory Neil Shapiro **		>4 -- length of enhanced status code.
7153299c2f1SGregory Neil Shapiro **
7163299c2f1SGregory Neil Shapiro **	Side Effects:
7173299c2f1SGregory Neil Shapiro **		none.
7183299c2f1SGregory Neil Shapiro */
7193299c2f1SGregory Neil Shapiro int
7203299c2f1SGregory Neil Shapiro isenhsc(s, delim)
7213299c2f1SGregory Neil Shapiro 	const char *s;
7223299c2f1SGregory Neil Shapiro 	int delim;
7233299c2f1SGregory Neil Shapiro {
7243299c2f1SGregory Neil Shapiro 	int l, h;
7253299c2f1SGregory Neil Shapiro 
7263299c2f1SGregory Neil Shapiro 	if (s == NULL)
7273299c2f1SGregory Neil Shapiro 		return 0;
7283299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
7293299c2f1SGregory Neil Shapiro 		return 0;
7303299c2f1SGregory Neil Shapiro 	h = 0;
7313299c2f1SGregory Neil Shapiro 	l = 2;
7323299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
7333299c2f1SGregory Neil Shapiro 		++h;
7343299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
7353299c2f1SGregory Neil Shapiro 		return 0;
7363299c2f1SGregory Neil Shapiro 	l += h + 1;
7373299c2f1SGregory Neil Shapiro 	h = 0;
7383299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
7393299c2f1SGregory Neil Shapiro 		++h;
7403299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
7413299c2f1SGregory Neil Shapiro 		return 0;
7423299c2f1SGregory Neil Shapiro 	return l + h;
7433299c2f1SGregory Neil Shapiro }
74412ed1c7cSGregory Neil Shapiro /*
7453299c2f1SGregory Neil Shapiro **  EXTENHSC -- check and extract an enhanced status code
7463299c2f1SGregory Neil Shapiro **
7473299c2f1SGregory Neil Shapiro **	Parameters:
7483299c2f1SGregory Neil Shapiro **		s -- string with possible enhanced status code.
7493299c2f1SGregory Neil Shapiro **		delim -- delim for enhanced status code.
7503299c2f1SGregory Neil Shapiro **		e -- pointer to storage for enhanced status code.
7513299c2f1SGregory Neil Shapiro **			must be != NULL and have space for at least
7523299c2f1SGregory Neil Shapiro **			10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
7533299c2f1SGregory Neil Shapiro **
7543299c2f1SGregory Neil Shapiro **	Returns:
7553299c2f1SGregory Neil Shapiro **		0  -- no enhanced status code.
7563299c2f1SGregory Neil Shapiro **		>4 -- length of enhanced status code.
7573299c2f1SGregory Neil Shapiro **
7583299c2f1SGregory Neil Shapiro **	Side Effects:
7593299c2f1SGregory Neil Shapiro **		fills e with enhanced status code.
7603299c2f1SGregory Neil Shapiro */
76112ed1c7cSGregory Neil Shapiro 
7623299c2f1SGregory Neil Shapiro int
7633299c2f1SGregory Neil Shapiro extenhsc(s, delim, e)
7643299c2f1SGregory Neil Shapiro 	const char *s;
7653299c2f1SGregory Neil Shapiro 	int delim;
7663299c2f1SGregory Neil Shapiro 	char *e;
7673299c2f1SGregory Neil Shapiro {
7683299c2f1SGregory Neil Shapiro 	int l, h;
7693299c2f1SGregory Neil Shapiro 
7703299c2f1SGregory Neil Shapiro 	if (s == NULL)
7713299c2f1SGregory Neil Shapiro 		return 0;
7723299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
7733299c2f1SGregory Neil Shapiro 		return 0;
7743299c2f1SGregory Neil Shapiro 	h = 0;
7753299c2f1SGregory Neil Shapiro 	l = 2;
7763299c2f1SGregory Neil Shapiro 	e[0] = s[0];
7773299c2f1SGregory Neil Shapiro 	e[1] = '.';
7783299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
7793299c2f1SGregory Neil Shapiro 	{
7803299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
7813299c2f1SGregory Neil Shapiro 		++h;
7823299c2f1SGregory Neil Shapiro 	}
7833299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
7843299c2f1SGregory Neil Shapiro 		return 0;
7853299c2f1SGregory Neil Shapiro 	e[l + h] = '.';
7863299c2f1SGregory Neil Shapiro 	l += h + 1;
7873299c2f1SGregory Neil Shapiro 	h = 0;
7883299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
7893299c2f1SGregory Neil Shapiro 	{
7903299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
7913299c2f1SGregory Neil Shapiro 		++h;
7923299c2f1SGregory Neil Shapiro 	}
7933299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
7943299c2f1SGregory Neil Shapiro 		return 0;
7953299c2f1SGregory Neil Shapiro 	e[l + h] = '\0';
7963299c2f1SGregory Neil Shapiro 	return l + h;
7973299c2f1SGregory Neil Shapiro }
79812ed1c7cSGregory Neil Shapiro /*
799c2aa98e2SPeter Wemm **  FMTMSG -- format a message into buffer.
800c2aa98e2SPeter Wemm **
801c2aa98e2SPeter Wemm **	Parameters:
8023299c2f1SGregory Neil Shapiro **		eb -- error buffer to get result -- MUST BE MsgBuf.
803c2aa98e2SPeter Wemm **		to -- the recipient tag for this message.
8043299c2f1SGregory Neil Shapiro **		num -- default three digit SMTP reply code.
8053299c2f1SGregory Neil Shapiro **		enhsc -- enhanced status code.
806c2aa98e2SPeter Wemm **		en -- the error number to display.
807c2aa98e2SPeter Wemm **		fmt -- format of string.
8083299c2f1SGregory Neil Shapiro **		ap -- arguments for fmt.
809c2aa98e2SPeter Wemm **
810c2aa98e2SPeter Wemm **	Returns:
8113299c2f1SGregory Neil Shapiro **		pointer to error text beyond status codes.
812c2aa98e2SPeter Wemm **
813c2aa98e2SPeter Wemm **	Side Effects:
814c2aa98e2SPeter Wemm **		none.
815c2aa98e2SPeter Wemm */
816c2aa98e2SPeter Wemm 
8173299c2f1SGregory Neil Shapiro static char *
8183299c2f1SGregory Neil Shapiro fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
819c2aa98e2SPeter Wemm 	register char *eb;
820c2aa98e2SPeter Wemm 	const char *to;
821c2aa98e2SPeter Wemm 	const char *num;
8223299c2f1SGregory Neil Shapiro 	const char *enhsc;
823c2aa98e2SPeter Wemm 	int eno;
824c2aa98e2SPeter Wemm 	const char *fmt;
82512ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
826c2aa98e2SPeter Wemm {
827c2aa98e2SPeter Wemm 	char del;
828c2aa98e2SPeter Wemm 	int l;
829951742c4SGregory Neil Shapiro 	int spaceleft = sizeof(MsgBuf);
8303299c2f1SGregory Neil Shapiro 	char *errtxt;
831c2aa98e2SPeter Wemm 
832c2aa98e2SPeter Wemm 	/* output the reply code */
8333299c2f1SGregory Neil Shapiro 	if (ISSMTPCODE(fmt))
834c2aa98e2SPeter Wemm 	{
835c2aa98e2SPeter Wemm 		num = fmt;
836c2aa98e2SPeter Wemm 		fmt += 4;
837c2aa98e2SPeter Wemm 	}
838c2aa98e2SPeter Wemm 	if (num[3] == '-')
839c2aa98e2SPeter Wemm 		del = '-';
840c2aa98e2SPeter Wemm 	else
841c2aa98e2SPeter Wemm 		del = ' ';
84212ed1c7cSGregory Neil Shapiro 	if (SoftBounce && num[0] == '5')
84312ed1c7cSGregory Neil Shapiro 	{
84412ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
84512ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
84612ed1c7cSGregory Neil Shapiro 	}
84712ed1c7cSGregory Neil Shapiro 	else
84812ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
849c2aa98e2SPeter Wemm 	eb += 4;
850c2aa98e2SPeter Wemm 	spaceleft -= 4;
851c2aa98e2SPeter Wemm 
8523299c2f1SGregory Neil Shapiro 	if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
8533299c2f1SGregory Neil Shapiro 	{
8543299c2f1SGregory Neil Shapiro 		/* copy enh.status code including trailing blank */
8553299c2f1SGregory Neil Shapiro 		l++;
85612ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, fmt, l + 1);
8573299c2f1SGregory Neil Shapiro 		eb += l;
8583299c2f1SGregory Neil Shapiro 		spaceleft -= l;
8593299c2f1SGregory Neil Shapiro 		fmt += l;
8603299c2f1SGregory Neil Shapiro 	}
8613299c2f1SGregory Neil Shapiro 	else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
8623299c2f1SGregory Neil Shapiro 	{
8633299c2f1SGregory Neil Shapiro 		/* copy enh.status code */
86412ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, enhsc, l + 1);
8653299c2f1SGregory Neil Shapiro 		eb[l] = ' ';
8663299c2f1SGregory Neil Shapiro 		eb[++l] = '\0';
8673299c2f1SGregory Neil Shapiro 		eb += l;
8683299c2f1SGregory Neil Shapiro 		spaceleft -= l;
8693299c2f1SGregory Neil Shapiro 	}
87012ed1c7cSGregory Neil Shapiro 	if (SoftBounce && eb[-l] == '5')
87112ed1c7cSGregory Neil Shapiro 	{
87212ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
87312ed1c7cSGregory Neil Shapiro 		eb[-l] = '4';
87412ed1c7cSGregory Neil Shapiro 	}
8753299c2f1SGregory Neil Shapiro 	errtxt = eb;
8763299c2f1SGregory Neil Shapiro 
877c2aa98e2SPeter Wemm 	/* output the file name and line number */
878c2aa98e2SPeter Wemm 	if (FileName != NULL)
879c2aa98e2SPeter Wemm 	{
88012ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
881c2aa98e2SPeter Wemm 				   shortenstring(FileName, 83), LineNumber);
882c2aa98e2SPeter Wemm 		eb += (l = strlen(eb));
883c2aa98e2SPeter Wemm 		spaceleft -= l;
884c2aa98e2SPeter Wemm 	}
885c2aa98e2SPeter Wemm 
88656477e1eSGregory Neil Shapiro 	/*
88756477e1eSGregory Neil Shapiro 	**  output the "to" address only if it is defined and one of the
88856477e1eSGregory Neil Shapiro 	**  following codes is used:
88956477e1eSGregory Neil Shapiro 	**  050 internal notices, e.g., alias expansion
89056477e1eSGregory Neil Shapiro 	**  250 Ok
89156477e1eSGregory Neil Shapiro 	**  252 Cannot VRFY user, but will accept message and attempt delivery
89256477e1eSGregory Neil Shapiro 	**  450 Requested mail action not taken: mailbox unavailable
89356477e1eSGregory Neil Shapiro 	**  550 Requested action not taken: mailbox unavailable
89456477e1eSGregory Neil Shapiro 	**  553 Requested action not taken: mailbox name not allowed
89556477e1eSGregory Neil Shapiro 	**
89656477e1eSGregory Neil Shapiro 	**  Notice: this still isn't "the right thing", this code shouldn't
89756477e1eSGregory Neil Shapiro 	**	(indirectly) depend on CurEnv->e_to.
89856477e1eSGregory Neil Shapiro 	*/
89956477e1eSGregory Neil Shapiro 
900c2aa98e2SPeter Wemm 	if (to != NULL && to[0] != '\0' &&
90156477e1eSGregory Neil Shapiro 	    (strncmp(num, "050", 3) == 0 ||
90256477e1eSGregory Neil Shapiro 	     strncmp(num, "250", 3) == 0 ||
90356477e1eSGregory Neil Shapiro 	     strncmp(num, "252", 3) == 0 ||
90456477e1eSGregory Neil Shapiro 	     strncmp(num, "450", 3) == 0 ||
90556477e1eSGregory Neil Shapiro 	     strncmp(num, "550", 3) == 0 ||
90656477e1eSGregory Neil Shapiro 	     strncmp(num, "553", 3) == 0))
907c2aa98e2SPeter Wemm 	{
90812ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2,
90912ed1c7cSGregory Neil Shapiro 				   shortenstring(to, MAXSHORTSTR), "... ");
910c2aa98e2SPeter Wemm 		spaceleft -= strlen(eb);
911c2aa98e2SPeter Wemm 		while (*eb != '\0')
912c2aa98e2SPeter Wemm 			*eb++ &= 0177;
913c2aa98e2SPeter Wemm 	}
914c2aa98e2SPeter Wemm 
915c2aa98e2SPeter Wemm 	/* output the message */
91612ed1c7cSGregory Neil Shapiro 	(void) sm_vsnprintf(eb, spaceleft, fmt, ap);
917c2aa98e2SPeter Wemm 	spaceleft -= strlen(eb);
918c2aa98e2SPeter Wemm 	while (*eb != '\0')
919c2aa98e2SPeter Wemm 		*eb++ &= 0177;
920c2aa98e2SPeter Wemm 
921c2aa98e2SPeter Wemm 	/* output the error code, if any */
922c2aa98e2SPeter Wemm 	if (eno != 0)
92312ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
9243299c2f1SGregory Neil Shapiro 
9253299c2f1SGregory Neil Shapiro 	return errtxt;
926c2aa98e2SPeter Wemm }
92712ed1c7cSGregory Neil Shapiro /*
928c2aa98e2SPeter Wemm **  BUFFER_ERRORS -- arrange to buffer future error messages
929c2aa98e2SPeter Wemm **
930c2aa98e2SPeter Wemm **	Parameters:
931c2aa98e2SPeter Wemm **		none
932c2aa98e2SPeter Wemm **
933c2aa98e2SPeter Wemm **	Returns:
934c2aa98e2SPeter Wemm **		none.
935c2aa98e2SPeter Wemm */
936c2aa98e2SPeter Wemm 
937c2aa98e2SPeter Wemm void
938c2aa98e2SPeter Wemm buffer_errors()
939c2aa98e2SPeter Wemm {
940c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
94112ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
942c2aa98e2SPeter Wemm }
94312ed1c7cSGregory Neil Shapiro /*
944c2aa98e2SPeter Wemm **  FLUSH_ERRORS -- flush the held error message buffer
945c2aa98e2SPeter Wemm **
946c2aa98e2SPeter Wemm **	Parameters:
947c2aa98e2SPeter Wemm **		print -- if set, print the message, otherwise just
948c2aa98e2SPeter Wemm **			delete it.
949c2aa98e2SPeter Wemm **
950c2aa98e2SPeter Wemm **	Returns:
951c2aa98e2SPeter Wemm **		none.
952c2aa98e2SPeter Wemm */
953c2aa98e2SPeter Wemm 
954c2aa98e2SPeter Wemm void
955c2aa98e2SPeter Wemm flush_errors(print)
956c2aa98e2SPeter Wemm 	bool print;
957c2aa98e2SPeter Wemm {
958c2aa98e2SPeter Wemm 	if (print && HeldMessageBuf[0] != '\0')
95912ed1c7cSGregory Neil Shapiro 		putoutmsg(HeldMessageBuf, false, true);
960c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
96112ed1c7cSGregory Neil Shapiro 	HoldErrs = false;
962c2aa98e2SPeter Wemm }
96312ed1c7cSGregory Neil Shapiro /*
96412ed1c7cSGregory Neil Shapiro **  SM_ERRSTRING -- return string description of error code
965c2aa98e2SPeter Wemm **
966c2aa98e2SPeter Wemm **	Parameters:
967c2aa98e2SPeter Wemm **		errnum -- the error number to translate
968c2aa98e2SPeter Wemm **
969c2aa98e2SPeter Wemm **	Returns:
970c2aa98e2SPeter Wemm **		A string description of errnum.
971c2aa98e2SPeter Wemm **
972c2aa98e2SPeter Wemm **	Side Effects:
973c2aa98e2SPeter Wemm **		none.
974c2aa98e2SPeter Wemm */
975c2aa98e2SPeter Wemm 
976c2aa98e2SPeter Wemm const char *
97712ed1c7cSGregory Neil Shapiro sm_errstring(errnum)
978c2aa98e2SPeter Wemm 	int errnum;
979c2aa98e2SPeter Wemm {
980c2aa98e2SPeter Wemm 	char *dnsmsg;
981c2aa98e2SPeter Wemm 	char *bp;
982c2aa98e2SPeter Wemm 	static char buf[MAXLINE];
98312ed1c7cSGregory Neil Shapiro #if HASSTRERROR
98412ed1c7cSGregory Neil Shapiro 	char *err;
98512ed1c7cSGregory Neil Shapiro 	char errbuf[30];
98612ed1c7cSGregory Neil Shapiro #endif /* HASSTRERROR */
987c2aa98e2SPeter Wemm #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
988c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
989c2aa98e2SPeter Wemm 	extern int sys_nerr;
9903299c2f1SGregory Neil Shapiro #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
991c2aa98e2SPeter Wemm 
992c2aa98e2SPeter Wemm 	/*
993c2aa98e2SPeter Wemm 	**  Handle special network error codes.
994c2aa98e2SPeter Wemm 	**
995c2aa98e2SPeter Wemm 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
996c2aa98e2SPeter Wemm 	*/
997c2aa98e2SPeter Wemm 
998c2aa98e2SPeter Wemm 	dnsmsg = NULL;
999c2aa98e2SPeter Wemm 	switch (errnum)
1000c2aa98e2SPeter Wemm 	{
1001c2aa98e2SPeter Wemm 	  case ETIMEDOUT:
1002c2aa98e2SPeter Wemm 	  case ECONNRESET:
1003c2aa98e2SPeter Wemm 		bp = buf;
1004c2aa98e2SPeter Wemm #if HASSTRERROR
100512ed1c7cSGregory Neil Shapiro 		err = strerror(errnum);
100612ed1c7cSGregory Neil Shapiro 		if (err == NULL)
100712ed1c7cSGregory Neil Shapiro 		{
1008951742c4SGregory Neil Shapiro 			(void) sm_snprintf(errbuf, sizeof(errbuf),
100912ed1c7cSGregory Neil Shapiro 					   "Error %d", errnum);
101012ed1c7cSGregory Neil Shapiro 			err = errbuf;
101112ed1c7cSGregory Neil Shapiro 		}
101212ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
10133299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1014c2aa98e2SPeter Wemm 		if (errnum >= 0 && errnum < sys_nerr)
101512ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp, sys_errlist[errnum],
101612ed1c7cSGregory Neil Shapiro 					  SPACELEFT(buf, bp));
1017c2aa98e2SPeter Wemm 		else
101812ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
101912ed1c7cSGregory Neil Shapiro 				"Error %d", errnum);
10203299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1021c2aa98e2SPeter Wemm 		bp += strlen(bp);
1022c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1023c2aa98e2SPeter Wemm 		{
1024c2aa98e2SPeter Wemm 			if (errnum == ETIMEDOUT)
1025c2aa98e2SPeter Wemm 			{
102612ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
102712ed1c7cSGregory Neil Shapiro 					" with ");
1028c2aa98e2SPeter Wemm 				bp += strlen(bp);
1029c2aa98e2SPeter Wemm 			}
1030c2aa98e2SPeter Wemm 			else
1031c2aa98e2SPeter Wemm 			{
1032c2aa98e2SPeter Wemm 				bp = buf;
103312ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
1034c2aa98e2SPeter Wemm 					"Connection reset by ");
1035c2aa98e2SPeter Wemm 				bp += strlen(bp);
1036c2aa98e2SPeter Wemm 			}
103712ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp,
103812ed1c7cSGregory Neil Shapiro 					shortenstring(CurHostName, MAXSHORTSTR),
103912ed1c7cSGregory Neil Shapiro 					SPACELEFT(buf, bp));
1040c2aa98e2SPeter Wemm 			bp += strlen(buf);
1041c2aa98e2SPeter Wemm 		}
1042c2aa98e2SPeter Wemm 		if (SmtpPhase != NULL)
1043c2aa98e2SPeter Wemm 		{
104412ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
104512ed1c7cSGregory Neil Shapiro 				" during %s", SmtpPhase);
1046c2aa98e2SPeter Wemm 		}
10473299c2f1SGregory Neil Shapiro 		return buf;
1048c2aa98e2SPeter Wemm 
1049c2aa98e2SPeter Wemm 	  case EHOSTDOWN:
1050c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1051c2aa98e2SPeter Wemm 			break;
1052951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
1053c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
10543299c2f1SGregory Neil Shapiro 		return buf;
1055c2aa98e2SPeter Wemm 
1056c2aa98e2SPeter Wemm 	  case ECONNREFUSED:
1057c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1058c2aa98e2SPeter Wemm 			break;
1059951742c4SGregory Neil Shapiro 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
1060c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
10613299c2f1SGregory Neil Shapiro 		return buf;
1062c2aa98e2SPeter Wemm 
1063c2aa98e2SPeter Wemm #if NAMED_BIND
1064c2aa98e2SPeter Wemm 	  case HOST_NOT_FOUND + E_DNSBASE:
1065c2aa98e2SPeter Wemm 		dnsmsg = "host not found";
1066c2aa98e2SPeter Wemm 		break;
1067c2aa98e2SPeter Wemm 
1068c2aa98e2SPeter Wemm 	  case TRY_AGAIN + E_DNSBASE:
1069c2aa98e2SPeter Wemm 		dnsmsg = "host name lookup failure";
1070c2aa98e2SPeter Wemm 		break;
1071c2aa98e2SPeter Wemm 
1072c2aa98e2SPeter Wemm 	  case NO_RECOVERY + E_DNSBASE:
1073c2aa98e2SPeter Wemm 		dnsmsg = "non-recoverable error";
1074c2aa98e2SPeter Wemm 		break;
1075c2aa98e2SPeter Wemm 
1076c2aa98e2SPeter Wemm 	  case NO_DATA + E_DNSBASE:
1077c2aa98e2SPeter Wemm 		dnsmsg = "no data known";
1078c2aa98e2SPeter Wemm 		break;
10793299c2f1SGregory Neil Shapiro #endif /* NAMED_BIND */
1080c2aa98e2SPeter Wemm 
1081c2aa98e2SPeter Wemm 	  case EPERM:
1082c2aa98e2SPeter Wemm 		/* SunOS gives "Not owner" -- this is the POSIX message */
1083c2aa98e2SPeter Wemm 		return "Operation not permitted";
1084c2aa98e2SPeter Wemm 
1085c2aa98e2SPeter Wemm 	/*
1086c2aa98e2SPeter Wemm 	**  Error messages used internally in sendmail.
1087c2aa98e2SPeter Wemm 	*/
1088c2aa98e2SPeter Wemm 
1089c2aa98e2SPeter Wemm 	  case E_SM_OPENTIMEOUT:
1090c2aa98e2SPeter Wemm 		return "Timeout on file open";
1091c2aa98e2SPeter Wemm 
1092c2aa98e2SPeter Wemm 	  case E_SM_NOSLINK:
1093c2aa98e2SPeter Wemm 		return "Symbolic links not allowed";
1094c2aa98e2SPeter Wemm 
1095c2aa98e2SPeter Wemm 	  case E_SM_NOHLINK:
1096c2aa98e2SPeter Wemm 		return "Hard links not allowed";
1097c2aa98e2SPeter Wemm 
1098c2aa98e2SPeter Wemm 	  case E_SM_REGONLY:
1099c2aa98e2SPeter Wemm 		return "Regular files only";
1100c2aa98e2SPeter Wemm 
1101c2aa98e2SPeter Wemm 	  case E_SM_ISEXEC:
1102c2aa98e2SPeter Wemm 		return "Executable files not allowed";
1103c2aa98e2SPeter Wemm 
1104c2aa98e2SPeter Wemm 	  case E_SM_WWDIR:
1105c2aa98e2SPeter Wemm 		return "World writable directory";
1106c2aa98e2SPeter Wemm 
1107c2aa98e2SPeter Wemm 	  case E_SM_GWDIR:
1108c2aa98e2SPeter Wemm 		return "Group writable directory";
1109c2aa98e2SPeter Wemm 
1110c2aa98e2SPeter Wemm 	  case E_SM_FILECHANGE:
1111c2aa98e2SPeter Wemm 		return "File changed after open";
1112c2aa98e2SPeter Wemm 
1113c2aa98e2SPeter Wemm 	  case E_SM_WWFILE:
1114c2aa98e2SPeter Wemm 		return "World writable file";
1115c2aa98e2SPeter Wemm 
1116c2aa98e2SPeter Wemm 	  case E_SM_GWFILE:
1117c2aa98e2SPeter Wemm 		return "Group writable file";
11183299c2f1SGregory Neil Shapiro 
11193299c2f1SGregory Neil Shapiro 	  case E_SM_GRFILE:
11203299c2f1SGregory Neil Shapiro 		return "Group readable file";
11213299c2f1SGregory Neil Shapiro 
11223299c2f1SGregory Neil Shapiro 	  case E_SM_WRFILE:
11233299c2f1SGregory Neil Shapiro 		return "World readable file";
1124c2aa98e2SPeter Wemm 	}
1125c2aa98e2SPeter Wemm 
1126c2aa98e2SPeter Wemm 	if (dnsmsg != NULL)
1127c2aa98e2SPeter Wemm 	{
1128c2aa98e2SPeter Wemm 		bp = buf;
1129951742c4SGregory Neil Shapiro 		bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
1130c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1131c2aa98e2SPeter Wemm 		{
113212ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
113312ed1c7cSGregory Neil Shapiro 				shortenstring(CurHostName, MAXSHORTSTR), ": ");
1134c2aa98e2SPeter Wemm 			bp += strlen(bp);
1135c2aa98e2SPeter Wemm 		}
113612ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1137c2aa98e2SPeter Wemm 		return buf;
1138c2aa98e2SPeter Wemm 	}
1139c2aa98e2SPeter Wemm 
114012ed1c7cSGregory Neil Shapiro #if LDAPMAP
11413299c2f1SGregory Neil Shapiro 	if (errnum >= E_LDAPBASE)
11423299c2f1SGregory Neil Shapiro 		return ldap_err2string(errnum - E_LDAPBASE);
11433299c2f1SGregory Neil Shapiro #endif /* LDAPMAP */
11443299c2f1SGregory Neil Shapiro 
1145c2aa98e2SPeter Wemm #if HASSTRERROR
114612ed1c7cSGregory Neil Shapiro 	err = strerror(errnum);
114712ed1c7cSGregory Neil Shapiro 	if (err == NULL)
114812ed1c7cSGregory Neil Shapiro 	{
1149951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
115012ed1c7cSGregory Neil Shapiro 		return buf;
115112ed1c7cSGregory Neil Shapiro 	}
115212ed1c7cSGregory Neil Shapiro 	return err;
11533299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1154c2aa98e2SPeter Wemm 	if (errnum > 0 && errnum < sys_nerr)
11553299c2f1SGregory Neil Shapiro 		return sys_errlist[errnum];
1156c2aa98e2SPeter Wemm 
1157951742c4SGregory Neil Shapiro 	(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
11583299c2f1SGregory Neil Shapiro 	return buf;
11593299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1160c2aa98e2SPeter Wemm }
1161