xref: /freebsd/contrib/sendmail/src/err.c (revision da7d7b9c861cf98e912c0bd1e549752d2dae4fb6)
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 
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 */
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:
97*da7d7b9cSGregory 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;
130*da7d7b9cSGregory Neil Shapiro 	bool panic, exiting, keep;
1313299c2f1SGregory Neil Shapiro 	char *user;
1323299c2f1SGregory Neil Shapiro 	char *enhsc;
1333299c2f1SGregory Neil Shapiro 	char *errtxt;
134c2aa98e2SPeter Wemm 	struct passwd *pw;
135c2aa98e2SPeter Wemm 	char ubuf[80];
13612ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
137c2aa98e2SPeter Wemm 
138*da7d7b9cSGregory Neil Shapiro 	panic = exiting = keep = false;
13912ed1c7cSGregory Neil Shapiro 	switch (*fmt)
140c2aa98e2SPeter Wemm 	{
14112ed1c7cSGregory Neil Shapiro 	  case '!':
14212ed1c7cSGregory Neil Shapiro 		++fmt;
143*da7d7b9cSGregory Neil Shapiro 		panic = exiting = true;
14412ed1c7cSGregory Neil Shapiro 		break;
14512ed1c7cSGregory Neil Shapiro 	  case '@':
14612ed1c7cSGregory Neil Shapiro 		++fmt;
14712ed1c7cSGregory Neil Shapiro 		exiting = true;
14812ed1c7cSGregory Neil Shapiro 		break;
149*da7d7b9cSGregory Neil Shapiro 	  case '+':
150*da7d7b9cSGregory Neil Shapiro 		++fmt;
151*da7d7b9cSGregory Neil Shapiro 		keep = true;
152*da7d7b9cSGregory Neil Shapiro 		break;
15312ed1c7cSGregory Neil Shapiro 	  default:
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 */
185*da7d7b9cSGregory Neil Shapiro 	if (!panic && CurEnv != NULL && (!keep || CurEnv->e_message == 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 
482*da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
483*da7d7b9cSGregory Neil Shapiro /*
484*da7d7b9cSGregory Neil Shapiro **  EMESSAGE -- print message (not necessarily an error)
485*da7d7b9cSGregory Neil Shapiro **	(same as message() but requires reply code and enhanced status code)
486*da7d7b9cSGregory Neil Shapiro **
487*da7d7b9cSGregory Neil Shapiro **	Parameters:
488*da7d7b9cSGregory Neil Shapiro **		replycode -- SMTP reply code.
489*da7d7b9cSGregory Neil Shapiro **		enhsc -- enhanced status code.
490*da7d7b9cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- it can begin with
491*da7d7b9cSGregory Neil Shapiro **			an SMTP reply code.  If not, 050 is assumed.
492*da7d7b9cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
493*da7d7b9cSGregory Neil Shapiro **
494*da7d7b9cSGregory Neil Shapiro **	Returns:
495*da7d7b9cSGregory Neil Shapiro **		none
496*da7d7b9cSGregory Neil Shapiro **
497*da7d7b9cSGregory Neil Shapiro **	Side Effects:
498*da7d7b9cSGregory Neil Shapiro **		none.
499*da7d7b9cSGregory Neil Shapiro */
500*da7d7b9cSGregory Neil Shapiro 
501*da7d7b9cSGregory Neil Shapiro /*VARARGS3*/
502*da7d7b9cSGregory Neil Shapiro void
503*da7d7b9cSGregory Neil Shapiro # ifdef __STDC__
504*da7d7b9cSGregory Neil Shapiro emessage(const char *replycode, const char *enhsc, const char *msg, ...)
505*da7d7b9cSGregory Neil Shapiro # else /* __STDC__ */
506*da7d7b9cSGregory Neil Shapiro emessage(replycode, enhsc, msg, va_alist)
507*da7d7b9cSGregory Neil Shapiro 	const char *replycode;
508*da7d7b9cSGregory Neil Shapiro 	const char *enhsc;
509*da7d7b9cSGregory Neil Shapiro 	const char *msg;
510*da7d7b9cSGregory Neil Shapiro 	va_dcl
511*da7d7b9cSGregory Neil Shapiro # endif /* __STDC__ */
512*da7d7b9cSGregory Neil Shapiro {
513*da7d7b9cSGregory Neil Shapiro 	char *errtxt;
514*da7d7b9cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
515*da7d7b9cSGregory Neil Shapiro 
516*da7d7b9cSGregory Neil Shapiro 	errno = 0;
517*da7d7b9cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
518*da7d7b9cSGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, CurEnv->e_to, replycode, enhsc, 0, msg, ap);
519*da7d7b9cSGregory Neil Shapiro 	SM_VA_END(ap);
520*da7d7b9cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
521*da7d7b9cSGregory Neil Shapiro 
522*da7d7b9cSGregory Neil Shapiro 	/* save this message for mailq printing */
523*da7d7b9cSGregory Neil Shapiro 	switch (MsgBuf[0])
524*da7d7b9cSGregory Neil Shapiro 	{
525*da7d7b9cSGregory Neil Shapiro 	  case '4':
526*da7d7b9cSGregory Neil Shapiro 	  case '8':
527*da7d7b9cSGregory Neil Shapiro 		if (CurEnv->e_message != NULL)
528*da7d7b9cSGregory Neil Shapiro 			break;
529*da7d7b9cSGregory Neil Shapiro 		/* FALLTHROUGH */
530*da7d7b9cSGregory Neil Shapiro 
531*da7d7b9cSGregory Neil Shapiro 	  case '5':
532*da7d7b9cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
533*da7d7b9cSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
534*da7d7b9cSGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
535*da7d7b9cSGregory Neil Shapiro 		break;
536*da7d7b9cSGregory Neil Shapiro 	}
537*da7d7b9cSGregory Neil Shapiro }
538*da7d7b9cSGregory Neil Shapiro 
539*da7d7b9cSGregory Neil Shapiro /*
540*da7d7b9cSGregory Neil Shapiro **  EXTSC -- check and extract a status codes
541*da7d7b9cSGregory Neil Shapiro **
542*da7d7b9cSGregory Neil Shapiro **	Parameters:
543*da7d7b9cSGregory Neil Shapiro **		msg -- string with possible enhanced status code.
544*da7d7b9cSGregory Neil Shapiro **		delim -- delim for enhanced status code.
545*da7d7b9cSGregory Neil Shapiro **		replycode -- pointer to storage for SMTP reply code;
546*da7d7b9cSGregory Neil Shapiro **			must be != NULL and have space for at least
547*da7d7b9cSGregory Neil Shapiro **			4 characters.
548*da7d7b9cSGregory Neil Shapiro **		enhsc -- pointer to storage for enhanced status code;
549*da7d7b9cSGregory Neil Shapiro **			must be != NULL and have space for at least
550*da7d7b9cSGregory Neil Shapiro **			10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
551*da7d7b9cSGregory Neil Shapiro **
552*da7d7b9cSGregory Neil Shapiro **	Returns:
553*da7d7b9cSGregory Neil Shapiro **		-1  -- no SMTP reply code.
554*da7d7b9cSGregory Neil Shapiro **		>=3 -- offset of error text in msg.
555*da7d7b9cSGregory Neil Shapiro **		(<=4  -- no enhanced status code)
556*da7d7b9cSGregory Neil Shapiro */
557*da7d7b9cSGregory Neil Shapiro 
558*da7d7b9cSGregory Neil Shapiro int
559*da7d7b9cSGregory Neil Shapiro extsc(msg, delim, replycode, enhsc)
560*da7d7b9cSGregory Neil Shapiro 	const char *msg;
561*da7d7b9cSGregory Neil Shapiro 	int delim;
562*da7d7b9cSGregory Neil Shapiro 	char *replycode;
563*da7d7b9cSGregory Neil Shapiro 	char *enhsc;
564*da7d7b9cSGregory Neil Shapiro {
565*da7d7b9cSGregory Neil Shapiro 	int offset;
566*da7d7b9cSGregory Neil Shapiro 
567*da7d7b9cSGregory Neil Shapiro 	SM_REQUIRE(replycode != NULL);
568*da7d7b9cSGregory Neil Shapiro 	SM_REQUIRE(enhsc != NULL);
569*da7d7b9cSGregory Neil Shapiro 	replycode[0] = '\0';
570*da7d7b9cSGregory Neil Shapiro 	enhsc[0] = '\0';
571*da7d7b9cSGregory Neil Shapiro 	if (msg == NULL)
572*da7d7b9cSGregory Neil Shapiro 		return -1;
573*da7d7b9cSGregory Neil Shapiro 	if (!ISSMTPREPLY(msg))
574*da7d7b9cSGregory Neil Shapiro 		return -1;
575*da7d7b9cSGregory Neil Shapiro 	sm_strlcpy(replycode, msg, 4);
576*da7d7b9cSGregory Neil Shapiro 	if (msg[3] == '\0')
577*da7d7b9cSGregory Neil Shapiro 		return 3;
578*da7d7b9cSGregory Neil Shapiro 	offset = 4;
579*da7d7b9cSGregory Neil Shapiro 	if (isenhsc(msg + 4, delim))
580*da7d7b9cSGregory Neil Shapiro 		offset = extenhsc(msg + 4, delim, enhsc) + 4;
581*da7d7b9cSGregory Neil Shapiro 	return offset;
582*da7d7b9cSGregory Neil Shapiro }
583*da7d7b9cSGregory Neil Shapiro #endif /* _FFR_PROXY */
5846f9c8e5bSGregory Neil Shapiro 
58512ed1c7cSGregory Neil Shapiro /*
586c2aa98e2SPeter Wemm **  NMESSAGE -- print message (not necessarily an error)
587c2aa98e2SPeter Wemm **
588c2aa98e2SPeter Wemm **	Just like "message" except it never puts the to... tag on.
589c2aa98e2SPeter Wemm **
590c2aa98e2SPeter Wemm **	Parameters:
59112ed1c7cSGregory Neil Shapiro **		msg -- the message (sm_io_printf fmt) -- if it begins
592c2aa98e2SPeter Wemm **			with a three digit SMTP reply code, that is used,
593c2aa98e2SPeter Wemm **			otherwise 050 is assumed.
59412ed1c7cSGregory Neil Shapiro **		(others) -- sm_io_printf arguments
595c2aa98e2SPeter Wemm **
596c2aa98e2SPeter Wemm **	Returns:
597c2aa98e2SPeter Wemm **		none
598c2aa98e2SPeter Wemm **
599c2aa98e2SPeter Wemm **	Side Effects:
600c2aa98e2SPeter Wemm **		none.
601c2aa98e2SPeter Wemm */
602c2aa98e2SPeter Wemm 
603c2aa98e2SPeter Wemm /*VARARGS1*/
604c2aa98e2SPeter Wemm void
605c2aa98e2SPeter Wemm #ifdef __STDC__
606c2aa98e2SPeter Wemm nmessage(const char *msg, ...)
6073299c2f1SGregory Neil Shapiro #else /* __STDC__ */
608c2aa98e2SPeter Wemm nmessage(msg, va_alist)
609c2aa98e2SPeter Wemm 	const char *msg;
610c2aa98e2SPeter Wemm 	va_dcl
6113299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
612c2aa98e2SPeter Wemm {
6133299c2f1SGregory Neil Shapiro 	char *errtxt;
61412ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
615c2aa98e2SPeter Wemm 
616c2aa98e2SPeter Wemm 	errno = 0;
61712ed1c7cSGregory Neil Shapiro 	SM_VA_START(ap, msg);
6183299c2f1SGregory Neil Shapiro 	errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
6193299c2f1SGregory Neil Shapiro 			(char *) NULL, 0, msg, ap);
62012ed1c7cSGregory Neil Shapiro 	SM_VA_END(ap);
62112ed1c7cSGregory Neil Shapiro 	putoutmsg(MsgBuf, false, false);
622c2aa98e2SPeter Wemm 
623c2aa98e2SPeter Wemm 	/* save this message for mailq printing */
624c2aa98e2SPeter Wemm 	switch (MsgBuf[0])
625c2aa98e2SPeter Wemm 	{
626c2aa98e2SPeter Wemm 	  case '4':
627c2aa98e2SPeter Wemm 	  case '8':
628c2aa98e2SPeter Wemm 		if (CurEnv->e_message != NULL)
629c2aa98e2SPeter Wemm 			break;
6303299c2f1SGregory Neil Shapiro 		/* FALLTHROUGH */
631c2aa98e2SPeter Wemm 
632c2aa98e2SPeter Wemm 	  case '5':
63312ed1c7cSGregory Neil Shapiro 		if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
634c0c4794dSGregory Neil Shapiro 			sm_free(CurEnv->e_message);
635951742c4SGregory Neil Shapiro 		CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
636c2aa98e2SPeter Wemm 		break;
637c2aa98e2SPeter Wemm 	}
638c2aa98e2SPeter Wemm }
63912ed1c7cSGregory Neil Shapiro /*
640c2aa98e2SPeter Wemm **  PUTOUTMSG -- output error message to transcript and channel
641c2aa98e2SPeter Wemm **
642c2aa98e2SPeter Wemm **	Parameters:
643c2aa98e2SPeter Wemm **		msg -- message to output (in SMTP format).
64412ed1c7cSGregory Neil Shapiro **		holdmsg -- if true, don't output a copy of the message to
645c2aa98e2SPeter Wemm **			our output channel.
64612ed1c7cSGregory Neil Shapiro **		heldmsg -- if true, this is a previously held message;
647c2aa98e2SPeter Wemm **			don't log it to the transcript file.
648c2aa98e2SPeter Wemm **
649c2aa98e2SPeter Wemm **	Returns:
650c2aa98e2SPeter Wemm **		none.
651c2aa98e2SPeter Wemm **
652c2aa98e2SPeter Wemm **	Side Effects:
653c2aa98e2SPeter Wemm **		Outputs msg to the transcript.
654c2aa98e2SPeter Wemm **		If appropriate, outputs it to the channel.
655c2aa98e2SPeter Wemm **		Deletes SMTP reply code number as appropriate.
656c2aa98e2SPeter Wemm */
657c2aa98e2SPeter Wemm 
6583299c2f1SGregory Neil Shapiro static void
659c2aa98e2SPeter Wemm putoutmsg(msg, holdmsg, heldmsg)
660c2aa98e2SPeter Wemm 	char *msg;
661c2aa98e2SPeter Wemm 	bool holdmsg;
662c2aa98e2SPeter Wemm 	bool heldmsg;
663c2aa98e2SPeter Wemm {
664c2aa98e2SPeter Wemm 	char msgcode = msg[0];
665951742c4SGregory Neil Shapiro 	char *errtxt = msg;
666951742c4SGregory Neil Shapiro 	char *id;
667c2aa98e2SPeter Wemm 
668c2aa98e2SPeter Wemm 	/* display for debugging */
669c2aa98e2SPeter Wemm 	if (tTd(54, 8))
67012ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
671c2aa98e2SPeter Wemm 			heldmsg ? " (held)" : "");
672c2aa98e2SPeter Wemm 
673c2aa98e2SPeter Wemm 	/* map warnings to something SMTP can handle */
674c2aa98e2SPeter Wemm 	if (msgcode == '6')
675c2aa98e2SPeter Wemm 		msg[0] = '5';
676c2aa98e2SPeter Wemm 	else if (msgcode == '8')
677c2aa98e2SPeter Wemm 		msg[0] = '4';
678951742c4SGregory Neil Shapiro 	id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
679c2aa98e2SPeter Wemm 
680c2aa98e2SPeter Wemm 	/* output to transcript if serious */
681c2aa98e2SPeter Wemm 	if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
682c2aa98e2SPeter Wemm 	    strchr("45", msg[0]) != NULL)
68312ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
68412ed1c7cSGregory Neil Shapiro 				     msg);
685c2aa98e2SPeter Wemm 
68612ed1c7cSGregory Neil Shapiro 	if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
687951742c4SGregory Neil Shapiro 		sm_syslog(LOG_INFO, id,
68812ed1c7cSGregory Neil Shapiro 			  "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
68912ed1c7cSGregory Neil Shapiro 			  heldmsg ? " (held)" : "");
690c2aa98e2SPeter Wemm 
691c2aa98e2SPeter Wemm 	if (msgcode == '8')
692c2aa98e2SPeter Wemm 		msg[0] = '0';
693c2aa98e2SPeter Wemm 
694c2aa98e2SPeter Wemm 	/* output to channel if appropriate */
695c2aa98e2SPeter Wemm 	if (!Verbose && msg[0] == '0')
696c2aa98e2SPeter Wemm 		return;
697c2aa98e2SPeter Wemm 	if (holdmsg)
698c2aa98e2SPeter Wemm 	{
699c2aa98e2SPeter Wemm 		/* save for possible future display */
700c2aa98e2SPeter Wemm 		msg[0] = msgcode;
7013299c2f1SGregory Neil Shapiro 		if (HeldMessageBuf[0] == '5' && msgcode == '4')
7023299c2f1SGregory Neil Shapiro 			return;
703951742c4SGregory Neil Shapiro 		(void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
704c2aa98e2SPeter Wemm 		return;
705c2aa98e2SPeter Wemm 	}
706c2aa98e2SPeter Wemm 
70712ed1c7cSGregory Neil Shapiro 	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
708c2aa98e2SPeter Wemm 
709c2aa98e2SPeter Wemm 	if (OutChannel == NULL)
710c2aa98e2SPeter Wemm 		return;
711c2aa98e2SPeter Wemm 
7123299c2f1SGregory Neil Shapiro 	/* find actual text of error (after SMTP status codes) */
7133299c2f1SGregory Neil Shapiro 	if (ISSMTPREPLY(errtxt))
7143299c2f1SGregory Neil Shapiro 	{
7153299c2f1SGregory Neil Shapiro 		int l;
7163299c2f1SGregory Neil Shapiro 
7173299c2f1SGregory Neil Shapiro 		errtxt += 4;
7183299c2f1SGregory Neil Shapiro 		l = isenhsc(errtxt, ' ');
7193299c2f1SGregory Neil Shapiro 		if (l <= 0)
7203299c2f1SGregory Neil Shapiro 			l = isenhsc(errtxt, '\0');
7213299c2f1SGregory Neil Shapiro 		if (l > 0)
7223299c2f1SGregory Neil Shapiro 			errtxt += l + 1;
7233299c2f1SGregory Neil Shapiro 	}
7243299c2f1SGregory Neil Shapiro 
725c2aa98e2SPeter Wemm 	/* if DisConnected, OutChannel now points to the transcript */
726c2aa98e2SPeter Wemm 	if (!DisConnected &&
727c2aa98e2SPeter Wemm 	    (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
72812ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
72912ed1c7cSGregory Neil Shapiro 				     msg);
730c2aa98e2SPeter Wemm 	else
73112ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
73212ed1c7cSGregory Neil Shapiro 				     errtxt);
733c2aa98e2SPeter Wemm 	if (TrafficLogFile != NULL)
73412ed1c7cSGregory Neil Shapiro 		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
73512ed1c7cSGregory Neil Shapiro 				     "%05d >>> %s\n", (int) CurrentPid,
73612ed1c7cSGregory Neil Shapiro 				     (OpMode == MD_SMTP || OpMode == MD_DAEMON)
73712ed1c7cSGregory Neil Shapiro 					? msg : errtxt);
73812ed1c7cSGregory Neil Shapiro #if !PIPELINING
73912ed1c7cSGregory Neil Shapiro 	/* XXX can't flush here for SMTP pipelining */
740c2aa98e2SPeter Wemm 	if (msg[3] == ' ')
74112ed1c7cSGregory Neil Shapiro 		(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
74212ed1c7cSGregory Neil Shapiro 	if (!sm_io_error(OutChannel) || DisConnected)
743c2aa98e2SPeter Wemm 		return;
744c2aa98e2SPeter Wemm 
745c2aa98e2SPeter Wemm 	/*
746c2aa98e2SPeter Wemm 	**  Error on output -- if reporting lost channel, just ignore it.
747c2aa98e2SPeter Wemm 	**  Also, ignore errors from QUIT response (221 message) -- some
748c2aa98e2SPeter Wemm 	**	rude servers don't read result.
749c2aa98e2SPeter Wemm 	*/
750c2aa98e2SPeter Wemm 
75112ed1c7cSGregory Neil Shapiro 	if (InChannel == NULL || sm_io_eof(InChannel) ||
75212ed1c7cSGregory Neil Shapiro 	    sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
753c2aa98e2SPeter Wemm 		return;
754c2aa98e2SPeter Wemm 
755c2aa98e2SPeter Wemm 	/* can't call syserr, 'cause we are using MsgBuf */
75612ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
757c2aa98e2SPeter Wemm 	if (LogLevel > 0)
758951742c4SGregory Neil Shapiro 		sm_syslog(LOG_CRIT, id,
759c2aa98e2SPeter Wemm 			  "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
76012ed1c7cSGregory Neil Shapiro 			  CURHOSTNAME,
76112ed1c7cSGregory Neil Shapiro 			  shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
76212ed1c7cSGregory Neil Shapiro #endif /* !PIPELINING */
763c2aa98e2SPeter Wemm }
76412ed1c7cSGregory Neil Shapiro /*
765c2aa98e2SPeter Wemm **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
766c2aa98e2SPeter Wemm **
767c2aa98e2SPeter Wemm **	Parameters:
768c2aa98e2SPeter Wemm **		msg -- the message to output.
769c2aa98e2SPeter Wemm **
770c2aa98e2SPeter Wemm **	Returns:
771c2aa98e2SPeter Wemm **		none.
772c2aa98e2SPeter Wemm **
773c2aa98e2SPeter Wemm **	Side Effects:
774c2aa98e2SPeter Wemm **		Sets the fatal error bit in the envelope as appropriate.
775c2aa98e2SPeter Wemm */
776c2aa98e2SPeter Wemm 
7773299c2f1SGregory Neil Shapiro static void
778c2aa98e2SPeter Wemm puterrmsg(msg)
779c2aa98e2SPeter Wemm 	char *msg;
780c2aa98e2SPeter Wemm {
781c2aa98e2SPeter Wemm 	char msgcode = msg[0];
782c2aa98e2SPeter Wemm 
783c2aa98e2SPeter Wemm 	/* output the message as usual */
78412ed1c7cSGregory Neil Shapiro 	putoutmsg(msg, HoldErrs, false);
785c2aa98e2SPeter Wemm 
786c2aa98e2SPeter Wemm 	/* be careful about multiple error messages */
787c2aa98e2SPeter Wemm 	if (OnlyOneError)
78812ed1c7cSGregory Neil Shapiro 		HoldErrs = true;
789c2aa98e2SPeter Wemm 
790c2aa98e2SPeter Wemm 	/* signal the error */
791c2aa98e2SPeter Wemm 	Errors++;
792c2aa98e2SPeter Wemm 
793c2aa98e2SPeter Wemm 	if (CurEnv == NULL)
794c2aa98e2SPeter Wemm 		return;
795c2aa98e2SPeter Wemm 
796c2aa98e2SPeter Wemm 	if (msgcode == '6')
797c2aa98e2SPeter Wemm 	{
798c2aa98e2SPeter Wemm 		/* notify the postmaster */
799c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_PM_NOTIFY;
800c2aa98e2SPeter Wemm 	}
801c2aa98e2SPeter Wemm 	else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
802c2aa98e2SPeter Wemm 	{
803c2aa98e2SPeter Wemm 		/* mark long-term fatal errors */
804c2aa98e2SPeter Wemm 		CurEnv->e_flags |= EF_FATALERRS;
805c2aa98e2SPeter Wemm 	}
806c2aa98e2SPeter Wemm }
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 **
8183299c2f1SGregory Neil Shapiro **	Side Effects:
8193299c2f1SGregory Neil Shapiro **		none.
8203299c2f1SGregory Neil Shapiro */
8213299c2f1SGregory Neil Shapiro int
8223299c2f1SGregory Neil Shapiro isenhsc(s, delim)
8233299c2f1SGregory Neil Shapiro 	const char *s;
8243299c2f1SGregory Neil Shapiro 	int delim;
8253299c2f1SGregory Neil Shapiro {
8263299c2f1SGregory Neil Shapiro 	int l, h;
8273299c2f1SGregory Neil Shapiro 
8283299c2f1SGregory Neil Shapiro 	if (s == NULL)
8293299c2f1SGregory Neil Shapiro 		return 0;
8303299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8313299c2f1SGregory Neil Shapiro 		return 0;
8323299c2f1SGregory Neil Shapiro 	h = 0;
8333299c2f1SGregory Neil Shapiro 	l = 2;
8343299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8353299c2f1SGregory Neil Shapiro 		++h;
8363299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
8373299c2f1SGregory Neil Shapiro 		return 0;
8383299c2f1SGregory Neil Shapiro 	l += h + 1;
8393299c2f1SGregory Neil Shapiro 	h = 0;
8403299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8413299c2f1SGregory Neil Shapiro 		++h;
8423299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
8433299c2f1SGregory Neil Shapiro 		return 0;
8443299c2f1SGregory Neil Shapiro 	return l + h;
8453299c2f1SGregory Neil Shapiro }
84612ed1c7cSGregory Neil Shapiro /*
8473299c2f1SGregory Neil Shapiro **  EXTENHSC -- check and extract an enhanced status code
8483299c2f1SGregory Neil Shapiro **
8493299c2f1SGregory Neil Shapiro **	Parameters:
8503299c2f1SGregory Neil Shapiro **		s -- string with possible enhanced status code.
8513299c2f1SGregory Neil Shapiro **		delim -- delim for enhanced status code.
8523299c2f1SGregory Neil Shapiro **		e -- pointer to storage for enhanced status code.
8533299c2f1SGregory Neil Shapiro **			must be != NULL and have space for at least
8543299c2f1SGregory Neil Shapiro **			10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
8553299c2f1SGregory Neil Shapiro **
8563299c2f1SGregory Neil Shapiro **	Returns:
8573299c2f1SGregory Neil Shapiro **		0  -- no enhanced status code.
8583299c2f1SGregory Neil Shapiro **		>4 -- length of enhanced status code.
8593299c2f1SGregory Neil Shapiro **
8603299c2f1SGregory Neil Shapiro **	Side Effects:
8613299c2f1SGregory Neil Shapiro **		fills e with enhanced status code.
8623299c2f1SGregory Neil Shapiro */
86312ed1c7cSGregory Neil Shapiro 
8643299c2f1SGregory Neil Shapiro int
8653299c2f1SGregory Neil Shapiro extenhsc(s, delim, e)
8663299c2f1SGregory Neil Shapiro 	const char *s;
8673299c2f1SGregory Neil Shapiro 	int delim;
8683299c2f1SGregory Neil Shapiro 	char *e;
8693299c2f1SGregory Neil Shapiro {
8703299c2f1SGregory Neil Shapiro 	int l, h;
8713299c2f1SGregory Neil Shapiro 
8723299c2f1SGregory Neil Shapiro 	if (s == NULL)
8733299c2f1SGregory Neil Shapiro 		return 0;
8743299c2f1SGregory Neil Shapiro 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8753299c2f1SGregory Neil Shapiro 		return 0;
8763299c2f1SGregory Neil Shapiro 	h = 0;
8773299c2f1SGregory Neil Shapiro 	l = 2;
8783299c2f1SGregory Neil Shapiro 	e[0] = s[0];
8793299c2f1SGregory Neil Shapiro 	e[1] = '.';
8803299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8813299c2f1SGregory Neil Shapiro 	{
8823299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
8833299c2f1SGregory Neil Shapiro 		++h;
8843299c2f1SGregory Neil Shapiro 	}
8853299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != '.')
8863299c2f1SGregory Neil Shapiro 		return 0;
8873299c2f1SGregory Neil Shapiro 	e[l + h] = '.';
8883299c2f1SGregory Neil Shapiro 	l += h + 1;
8893299c2f1SGregory Neil Shapiro 	h = 0;
8903299c2f1SGregory Neil Shapiro 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8913299c2f1SGregory Neil Shapiro 	{
8923299c2f1SGregory Neil Shapiro 		e[l + h] = s[l + h];
8933299c2f1SGregory Neil Shapiro 		++h;
8943299c2f1SGregory Neil Shapiro 	}
8953299c2f1SGregory Neil Shapiro 	if (h == 0 || s[l + h] != delim)
8963299c2f1SGregory Neil Shapiro 		return 0;
8973299c2f1SGregory Neil Shapiro 	e[l + h] = '\0';
8983299c2f1SGregory Neil Shapiro 	return l + h;
8993299c2f1SGregory Neil Shapiro }
90012ed1c7cSGregory Neil Shapiro /*
901c2aa98e2SPeter Wemm **  FMTMSG -- format a message into buffer.
902c2aa98e2SPeter Wemm **
903c2aa98e2SPeter Wemm **	Parameters:
9043299c2f1SGregory Neil Shapiro **		eb -- error buffer to get result -- MUST BE MsgBuf.
905c2aa98e2SPeter Wemm **		to -- the recipient tag for this message.
9063299c2f1SGregory Neil Shapiro **		num -- default three digit SMTP reply code.
9073299c2f1SGregory Neil Shapiro **		enhsc -- enhanced status code.
908c2aa98e2SPeter Wemm **		en -- the error number to display.
909c2aa98e2SPeter Wemm **		fmt -- format of string.
9103299c2f1SGregory Neil Shapiro **		ap -- arguments for fmt.
911c2aa98e2SPeter Wemm **
912c2aa98e2SPeter Wemm **	Returns:
9133299c2f1SGregory Neil Shapiro **		pointer to error text beyond status codes.
914c2aa98e2SPeter Wemm **
915c2aa98e2SPeter Wemm **	Side Effects:
916c2aa98e2SPeter Wemm **		none.
917c2aa98e2SPeter Wemm */
918c2aa98e2SPeter Wemm 
9193299c2f1SGregory Neil Shapiro static char *
9203299c2f1SGregory Neil Shapiro fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
921c2aa98e2SPeter Wemm 	register char *eb;
922c2aa98e2SPeter Wemm 	const char *to;
923c2aa98e2SPeter Wemm 	const char *num;
9243299c2f1SGregory Neil Shapiro 	const char *enhsc;
925c2aa98e2SPeter Wemm 	int eno;
926c2aa98e2SPeter Wemm 	const char *fmt;
92712ed1c7cSGregory Neil Shapiro 	SM_VA_LOCAL_DECL
928c2aa98e2SPeter Wemm {
929c2aa98e2SPeter Wemm 	char del;
930c2aa98e2SPeter Wemm 	int l;
931951742c4SGregory Neil Shapiro 	int spaceleft = sizeof(MsgBuf);
9323299c2f1SGregory Neil Shapiro 	char *errtxt;
933c2aa98e2SPeter Wemm 
934c2aa98e2SPeter Wemm 	/* output the reply code */
9353299c2f1SGregory Neil Shapiro 	if (ISSMTPCODE(fmt))
936c2aa98e2SPeter Wemm 	{
937c2aa98e2SPeter Wemm 		num = fmt;
938c2aa98e2SPeter Wemm 		fmt += 4;
939c2aa98e2SPeter Wemm 	}
940c2aa98e2SPeter Wemm 	if (num[3] == '-')
941c2aa98e2SPeter Wemm 		del = '-';
942c2aa98e2SPeter Wemm 	else
943c2aa98e2SPeter Wemm 		del = ' ';
94412ed1c7cSGregory Neil Shapiro 	if (SoftBounce && num[0] == '5')
94512ed1c7cSGregory Neil Shapiro 	{
94612ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
94712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
94812ed1c7cSGregory Neil Shapiro 	}
94912ed1c7cSGregory Neil Shapiro 	else
95012ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
951c2aa98e2SPeter Wemm 	eb += 4;
952c2aa98e2SPeter Wemm 	spaceleft -= 4;
953c2aa98e2SPeter Wemm 
9543299c2f1SGregory Neil Shapiro 	if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
9553299c2f1SGregory Neil Shapiro 	{
9563299c2f1SGregory Neil Shapiro 		/* copy enh.status code including trailing blank */
9573299c2f1SGregory Neil Shapiro 		l++;
95812ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, fmt, l + 1);
9593299c2f1SGregory Neil Shapiro 		eb += l;
9603299c2f1SGregory Neil Shapiro 		spaceleft -= l;
9613299c2f1SGregory Neil Shapiro 		fmt += l;
9623299c2f1SGregory Neil Shapiro 	}
9633299c2f1SGregory Neil Shapiro 	else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
9643299c2f1SGregory Neil Shapiro 	{
9653299c2f1SGregory Neil Shapiro 		/* copy enh.status code */
96612ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(eb, enhsc, l + 1);
9673299c2f1SGregory Neil Shapiro 		eb[l] = ' ';
9683299c2f1SGregory Neil Shapiro 		eb[++l] = '\0';
9693299c2f1SGregory Neil Shapiro 		eb += l;
9703299c2f1SGregory Neil Shapiro 		spaceleft -= l;
9713299c2f1SGregory Neil Shapiro 	}
97212ed1c7cSGregory Neil Shapiro 	if (SoftBounce && eb[-l] == '5')
97312ed1c7cSGregory Neil Shapiro 	{
97412ed1c7cSGregory Neil Shapiro 		/* replace 5 by 4 */
97512ed1c7cSGregory Neil Shapiro 		eb[-l] = '4';
97612ed1c7cSGregory Neil Shapiro 	}
9773299c2f1SGregory Neil Shapiro 	errtxt = eb;
9783299c2f1SGregory Neil Shapiro 
979c2aa98e2SPeter Wemm 	/* output the file name and line number */
980c2aa98e2SPeter Wemm 	if (FileName != NULL)
981c2aa98e2SPeter Wemm 	{
98212ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
983c2aa98e2SPeter Wemm 				   shortenstring(FileName, 83), LineNumber);
984c2aa98e2SPeter Wemm 		eb += (l = strlen(eb));
985c2aa98e2SPeter Wemm 		spaceleft -= l;
986c2aa98e2SPeter Wemm 	}
987c2aa98e2SPeter Wemm 
98856477e1eSGregory Neil Shapiro 	/*
98956477e1eSGregory Neil Shapiro 	**  output the "to" address only if it is defined and one of the
99056477e1eSGregory Neil Shapiro 	**  following codes is used:
99156477e1eSGregory Neil Shapiro 	**  050 internal notices, e.g., alias expansion
99256477e1eSGregory Neil Shapiro 	**  250 Ok
99356477e1eSGregory Neil Shapiro 	**  252 Cannot VRFY user, but will accept message and attempt delivery
99456477e1eSGregory Neil Shapiro 	**  450 Requested mail action not taken: mailbox unavailable
99556477e1eSGregory Neil Shapiro 	**  550 Requested action not taken: mailbox unavailable
99656477e1eSGregory Neil Shapiro 	**  553 Requested action not taken: mailbox name not allowed
99756477e1eSGregory Neil Shapiro 	**
99856477e1eSGregory Neil Shapiro 	**  Notice: this still isn't "the right thing", this code shouldn't
99956477e1eSGregory Neil Shapiro 	**	(indirectly) depend on CurEnv->e_to.
100056477e1eSGregory Neil Shapiro 	*/
100156477e1eSGregory Neil Shapiro 
1002c2aa98e2SPeter Wemm 	if (to != NULL && to[0] != '\0' &&
100356477e1eSGregory Neil Shapiro 	    (strncmp(num, "050", 3) == 0 ||
100456477e1eSGregory Neil Shapiro 	     strncmp(num, "250", 3) == 0 ||
100556477e1eSGregory Neil Shapiro 	     strncmp(num, "252", 3) == 0 ||
100656477e1eSGregory Neil Shapiro 	     strncmp(num, "450", 3) == 0 ||
100756477e1eSGregory Neil Shapiro 	     strncmp(num, "550", 3) == 0 ||
100856477e1eSGregory Neil Shapiro 	     strncmp(num, "553", 3) == 0))
1009c2aa98e2SPeter Wemm 	{
101012ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2,
101112ed1c7cSGregory Neil Shapiro 				   shortenstring(to, MAXSHORTSTR), "... ");
1012c2aa98e2SPeter Wemm 		spaceleft -= strlen(eb);
1013c2aa98e2SPeter Wemm 		while (*eb != '\0')
1014c2aa98e2SPeter Wemm 			*eb++ &= 0177;
1015c2aa98e2SPeter Wemm 	}
1016c2aa98e2SPeter Wemm 
1017c2aa98e2SPeter Wemm 	/* output the message */
101812ed1c7cSGregory Neil Shapiro 	(void) sm_vsnprintf(eb, spaceleft, fmt, ap);
1019c2aa98e2SPeter Wemm 	spaceleft -= strlen(eb);
1020c2aa98e2SPeter Wemm 	while (*eb != '\0')
1021c2aa98e2SPeter Wemm 		*eb++ &= 0177;
1022c2aa98e2SPeter Wemm 
1023c2aa98e2SPeter Wemm 	/* output the error code, if any */
1024c2aa98e2SPeter Wemm 	if (eno != 0)
102512ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
10263299c2f1SGregory Neil Shapiro 
10273299c2f1SGregory Neil Shapiro 	return errtxt;
1028c2aa98e2SPeter Wemm }
102912ed1c7cSGregory Neil Shapiro /*
1030c2aa98e2SPeter Wemm **  BUFFER_ERRORS -- arrange to buffer future error messages
1031c2aa98e2SPeter Wemm **
1032c2aa98e2SPeter Wemm **	Parameters:
1033c2aa98e2SPeter Wemm **		none
1034c2aa98e2SPeter Wemm **
1035c2aa98e2SPeter Wemm **	Returns:
1036c2aa98e2SPeter Wemm **		none.
1037c2aa98e2SPeter Wemm */
1038c2aa98e2SPeter Wemm 
1039c2aa98e2SPeter Wemm void
1040c2aa98e2SPeter Wemm buffer_errors()
1041c2aa98e2SPeter Wemm {
1042c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
104312ed1c7cSGregory Neil Shapiro 	HoldErrs = true;
1044c2aa98e2SPeter Wemm }
104512ed1c7cSGregory Neil Shapiro /*
1046c2aa98e2SPeter Wemm **  FLUSH_ERRORS -- flush the held error message buffer
1047c2aa98e2SPeter Wemm **
1048c2aa98e2SPeter Wemm **	Parameters:
1049c2aa98e2SPeter Wemm **		print -- if set, print the message, otherwise just
1050c2aa98e2SPeter Wemm **			delete it.
1051c2aa98e2SPeter Wemm **
1052c2aa98e2SPeter Wemm **	Returns:
1053c2aa98e2SPeter Wemm **		none.
1054c2aa98e2SPeter Wemm */
1055c2aa98e2SPeter Wemm 
1056c2aa98e2SPeter Wemm void
1057c2aa98e2SPeter Wemm flush_errors(print)
1058c2aa98e2SPeter Wemm 	bool print;
1059c2aa98e2SPeter Wemm {
1060c2aa98e2SPeter Wemm 	if (print && HeldMessageBuf[0] != '\0')
106112ed1c7cSGregory Neil Shapiro 		putoutmsg(HeldMessageBuf, false, true);
1062c2aa98e2SPeter Wemm 	HeldMessageBuf[0] = '\0';
106312ed1c7cSGregory Neil Shapiro 	HoldErrs = false;
1064c2aa98e2SPeter Wemm }
106512ed1c7cSGregory Neil Shapiro /*
106612ed1c7cSGregory Neil Shapiro **  SM_ERRSTRING -- return string description of error code
1067c2aa98e2SPeter Wemm **
1068c2aa98e2SPeter Wemm **	Parameters:
1069c2aa98e2SPeter Wemm **		errnum -- the error number to translate
1070c2aa98e2SPeter Wemm **
1071c2aa98e2SPeter Wemm **	Returns:
1072c2aa98e2SPeter Wemm **		A string description of errnum.
1073c2aa98e2SPeter Wemm **
1074c2aa98e2SPeter Wemm **	Side Effects:
1075c2aa98e2SPeter Wemm **		none.
1076c2aa98e2SPeter Wemm */
1077c2aa98e2SPeter Wemm 
1078c2aa98e2SPeter Wemm const char *
107912ed1c7cSGregory Neil Shapiro sm_errstring(errnum)
1080c2aa98e2SPeter Wemm 	int errnum;
1081c2aa98e2SPeter Wemm {
1082c2aa98e2SPeter Wemm 	char *dnsmsg;
1083c2aa98e2SPeter Wemm 	char *bp;
1084c2aa98e2SPeter Wemm 	static char buf[MAXLINE];
108512ed1c7cSGregory Neil Shapiro #if HASSTRERROR
108612ed1c7cSGregory Neil Shapiro 	char *err;
108712ed1c7cSGregory Neil Shapiro 	char errbuf[30];
108812ed1c7cSGregory Neil Shapiro #endif /* HASSTRERROR */
1089c2aa98e2SPeter Wemm #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
1090c2aa98e2SPeter Wemm 	extern char *sys_errlist[];
1091c2aa98e2SPeter Wemm 	extern int sys_nerr;
10923299c2f1SGregory Neil Shapiro #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
1093c2aa98e2SPeter Wemm 
1094c2aa98e2SPeter Wemm 	/*
1095c2aa98e2SPeter Wemm 	**  Handle special network error codes.
1096c2aa98e2SPeter Wemm 	**
1097c2aa98e2SPeter Wemm 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
1098c2aa98e2SPeter Wemm 	*/
1099c2aa98e2SPeter Wemm 
1100c2aa98e2SPeter Wemm 	dnsmsg = NULL;
1101c2aa98e2SPeter Wemm 	switch (errnum)
1102c2aa98e2SPeter Wemm 	{
1103c2aa98e2SPeter Wemm 	  case ETIMEDOUT:
1104c2aa98e2SPeter Wemm 	  case ECONNRESET:
1105c2aa98e2SPeter Wemm 		bp = buf;
1106c2aa98e2SPeter Wemm #if HASSTRERROR
110712ed1c7cSGregory Neil Shapiro 		err = strerror(errnum);
110812ed1c7cSGregory Neil Shapiro 		if (err == NULL)
110912ed1c7cSGregory Neil Shapiro 		{
1110951742c4SGregory Neil Shapiro 			(void) sm_snprintf(errbuf, sizeof(errbuf),
111112ed1c7cSGregory Neil Shapiro 					   "Error %d", errnum);
111212ed1c7cSGregory Neil Shapiro 			err = errbuf;
111312ed1c7cSGregory Neil Shapiro 		}
111412ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
11153299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1116c2aa98e2SPeter Wemm 		if (errnum >= 0 && errnum < sys_nerr)
111712ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp, sys_errlist[errnum],
111812ed1c7cSGregory Neil Shapiro 					  SPACELEFT(buf, bp));
1119c2aa98e2SPeter Wemm 		else
112012ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
112112ed1c7cSGregory Neil Shapiro 				"Error %d", errnum);
11223299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1123c2aa98e2SPeter Wemm 		bp += strlen(bp);
1124c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1125c2aa98e2SPeter Wemm 		{
1126c2aa98e2SPeter Wemm 			if (errnum == ETIMEDOUT)
1127c2aa98e2SPeter Wemm 			{
112812ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
112912ed1c7cSGregory Neil Shapiro 					" with ");
1130c2aa98e2SPeter Wemm 				bp += strlen(bp);
1131c2aa98e2SPeter Wemm 			}
1132c2aa98e2SPeter Wemm 			else
1133c2aa98e2SPeter Wemm 			{
1134c2aa98e2SPeter Wemm 				bp = buf;
113512ed1c7cSGregory Neil Shapiro 				(void) sm_snprintf(bp, SPACELEFT(buf, bp),
1136c2aa98e2SPeter Wemm 					"Connection reset by ");
1137c2aa98e2SPeter Wemm 				bp += strlen(bp);
1138c2aa98e2SPeter Wemm 			}
113912ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(bp,
114012ed1c7cSGregory Neil Shapiro 					shortenstring(CurHostName, MAXSHORTSTR),
114112ed1c7cSGregory Neil Shapiro 					SPACELEFT(buf, bp));
1142c2aa98e2SPeter Wemm 			bp += strlen(buf);
1143c2aa98e2SPeter Wemm 		}
1144c2aa98e2SPeter Wemm 		if (SmtpPhase != NULL)
1145c2aa98e2SPeter Wemm 		{
114612ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(bp, SPACELEFT(buf, bp),
114712ed1c7cSGregory Neil Shapiro 				" during %s", SmtpPhase);
1148c2aa98e2SPeter Wemm 		}
11493299c2f1SGregory Neil Shapiro 		return buf;
1150c2aa98e2SPeter Wemm 
1151c2aa98e2SPeter Wemm 	  case EHOSTDOWN:
1152c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1153c2aa98e2SPeter Wemm 			break;
1154951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
1155c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
11563299c2f1SGregory Neil Shapiro 		return buf;
1157c2aa98e2SPeter Wemm 
1158c2aa98e2SPeter Wemm 	  case ECONNREFUSED:
1159c2aa98e2SPeter Wemm 		if (CurHostName == NULL)
1160c2aa98e2SPeter Wemm 			break;
1161951742c4SGregory Neil Shapiro 		(void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
1162c2aa98e2SPeter Wemm 			shortenstring(CurHostName, MAXSHORTSTR));
11633299c2f1SGregory Neil Shapiro 		return buf;
1164c2aa98e2SPeter Wemm 
1165c2aa98e2SPeter Wemm #if NAMED_BIND
1166c2aa98e2SPeter Wemm 	  case HOST_NOT_FOUND + E_DNSBASE:
1167c2aa98e2SPeter Wemm 		dnsmsg = "host not found";
1168c2aa98e2SPeter Wemm 		break;
1169c2aa98e2SPeter Wemm 
1170c2aa98e2SPeter Wemm 	  case TRY_AGAIN + E_DNSBASE:
1171c2aa98e2SPeter Wemm 		dnsmsg = "host name lookup failure";
1172c2aa98e2SPeter Wemm 		break;
1173c2aa98e2SPeter Wemm 
1174c2aa98e2SPeter Wemm 	  case NO_RECOVERY + E_DNSBASE:
1175c2aa98e2SPeter Wemm 		dnsmsg = "non-recoverable error";
1176c2aa98e2SPeter Wemm 		break;
1177c2aa98e2SPeter Wemm 
1178c2aa98e2SPeter Wemm 	  case NO_DATA + E_DNSBASE:
1179c2aa98e2SPeter Wemm 		dnsmsg = "no data known";
1180c2aa98e2SPeter Wemm 		break;
11813299c2f1SGregory Neil Shapiro #endif /* NAMED_BIND */
1182c2aa98e2SPeter Wemm 
1183c2aa98e2SPeter Wemm 	  case EPERM:
1184c2aa98e2SPeter Wemm 		/* SunOS gives "Not owner" -- this is the POSIX message */
1185c2aa98e2SPeter Wemm 		return "Operation not permitted";
1186c2aa98e2SPeter Wemm 
1187c2aa98e2SPeter Wemm 	/*
1188c2aa98e2SPeter Wemm 	**  Error messages used internally in sendmail.
1189c2aa98e2SPeter Wemm 	*/
1190c2aa98e2SPeter Wemm 
1191c2aa98e2SPeter Wemm 	  case E_SM_OPENTIMEOUT:
1192c2aa98e2SPeter Wemm 		return "Timeout on file open";
1193c2aa98e2SPeter Wemm 
1194c2aa98e2SPeter Wemm 	  case E_SM_NOSLINK:
1195c2aa98e2SPeter Wemm 		return "Symbolic links not allowed";
1196c2aa98e2SPeter Wemm 
1197c2aa98e2SPeter Wemm 	  case E_SM_NOHLINK:
1198c2aa98e2SPeter Wemm 		return "Hard links not allowed";
1199c2aa98e2SPeter Wemm 
1200c2aa98e2SPeter Wemm 	  case E_SM_REGONLY:
1201c2aa98e2SPeter Wemm 		return "Regular files only";
1202c2aa98e2SPeter Wemm 
1203c2aa98e2SPeter Wemm 	  case E_SM_ISEXEC:
1204c2aa98e2SPeter Wemm 		return "Executable files not allowed";
1205c2aa98e2SPeter Wemm 
1206c2aa98e2SPeter Wemm 	  case E_SM_WWDIR:
1207c2aa98e2SPeter Wemm 		return "World writable directory";
1208c2aa98e2SPeter Wemm 
1209c2aa98e2SPeter Wemm 	  case E_SM_GWDIR:
1210c2aa98e2SPeter Wemm 		return "Group writable directory";
1211c2aa98e2SPeter Wemm 
1212c2aa98e2SPeter Wemm 	  case E_SM_FILECHANGE:
1213c2aa98e2SPeter Wemm 		return "File changed after open";
1214c2aa98e2SPeter Wemm 
1215c2aa98e2SPeter Wemm 	  case E_SM_WWFILE:
1216c2aa98e2SPeter Wemm 		return "World writable file";
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 	  case E_SM_GWFILE:
1219c2aa98e2SPeter Wemm 		return "Group writable file";
12203299c2f1SGregory Neil Shapiro 
12213299c2f1SGregory Neil Shapiro 	  case E_SM_GRFILE:
12223299c2f1SGregory Neil Shapiro 		return "Group readable file";
12233299c2f1SGregory Neil Shapiro 
12243299c2f1SGregory Neil Shapiro 	  case E_SM_WRFILE:
12253299c2f1SGregory Neil Shapiro 		return "World readable file";
1226c2aa98e2SPeter Wemm 	}
1227c2aa98e2SPeter Wemm 
1228c2aa98e2SPeter Wemm 	if (dnsmsg != NULL)
1229c2aa98e2SPeter Wemm 	{
1230c2aa98e2SPeter Wemm 		bp = buf;
1231951742c4SGregory Neil Shapiro 		bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
1232c2aa98e2SPeter Wemm 		if (CurHostName != NULL)
1233c2aa98e2SPeter Wemm 		{
123412ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
123512ed1c7cSGregory Neil Shapiro 				shortenstring(CurHostName, MAXSHORTSTR), ": ");
1236c2aa98e2SPeter Wemm 			bp += strlen(bp);
1237c2aa98e2SPeter Wemm 		}
123812ed1c7cSGregory Neil Shapiro 		(void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1239c2aa98e2SPeter Wemm 		return buf;
1240c2aa98e2SPeter Wemm 	}
1241c2aa98e2SPeter Wemm 
124212ed1c7cSGregory Neil Shapiro #if LDAPMAP
1243*da7d7b9cSGregory Neil Shapiro 	if (errnum >= E_LDAPBASE - E_LDAP_SHIM)
12443299c2f1SGregory Neil Shapiro 		return ldap_err2string(errnum - E_LDAPBASE);
12453299c2f1SGregory Neil Shapiro #endif /* LDAPMAP */
12463299c2f1SGregory Neil Shapiro 
1247c2aa98e2SPeter Wemm #if HASSTRERROR
124812ed1c7cSGregory Neil Shapiro 	err = strerror(errnum);
124912ed1c7cSGregory Neil Shapiro 	if (err == NULL)
125012ed1c7cSGregory Neil Shapiro 	{
1251951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
125212ed1c7cSGregory Neil Shapiro 		return buf;
125312ed1c7cSGregory Neil Shapiro 	}
125412ed1c7cSGregory Neil Shapiro 	return err;
12553299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1256c2aa98e2SPeter Wemm 	if (errnum > 0 && errnum < sys_nerr)
12573299c2f1SGregory Neil Shapiro 		return sys_errlist[errnum];
1258c2aa98e2SPeter Wemm 
1259951742c4SGregory Neil Shapiro 	(void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
12603299c2f1SGregory Neil Shapiro 	return buf;
12613299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1262c2aa98e2SPeter Wemm }
1263