/*
 * Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 *	$Id: error.h,v 1.75 2007/01/11 05:13:48 ca Exp $
 */

#ifndef SM_ERROR_H
#define SM_ERROR_H 1

#include "sm/generic.h"
#include "sm/types.h"
#if HAVE_ERRNO_H
# include <errno.h>
#endif

/* need a 32bit signed integer */
typedef	int32_t		sm_error_T;
typedef	int32_t		sm_ret_T;
#define SM_RET_MAX	INT32_MAX

/* not an error, but a useful return code for some functions */
#define SM_NOMATCH 1
#define SM_NOTDONE 2 /* operation not performed because it wasn't necessary */

/*
**  layout:
**	bit 31		1 (if error)
**	bit 30-24	module (7bit: 0..127)
**	bit 23-16	type (8bit: 0..255)
**	bit 15- 0	number (similar to errno) (16bit)
**
**  less bits for type, more for module?
**
**  Note: Berkeley DB uses negative error numbers: -30800 -30999
**  hence we cast the value to int16_t and then to int to preserve the sign.
*/

#define SM_ERR_HIGH_BIT		0x80000000
#define SM_ERR_MODULE_BITS	0x0000007f
#define SM_ERR_TYPE_BITS	0x000000ff
#define SM_ERR_VALUE_BITS	0x0000ffff
#define SM_ERR_MODULE_OFF	24
#define SM_ERR_TYPE_OFF		16
#define SM_ERR_VALUE_OFF	 0	/* if changed: see below! */

#define sm_error_module(err)	(((err) >> SM_ERR_MODULE_OFF) & SM_ERR_MODULE_BITS)
#define sm_error_type(err)	(((err) >> SM_ERR_TYPE_OFF) & SM_ERR_TYPE_BITS)
#define sm_error_value(err)	((sm_ret_T)((int16_t)(err)))

#define sm_error_gen(mod, type, value)	((sm_ret_T)(SM_ERR_HIGH_BIT |\
	((((mod) & SM_ERR_MODULE_BITS) << SM_ERR_MODULE_OFF) |\
	 (((type) & SM_ERR_TYPE_BITS) << SM_ERR_TYPE_OFF) |\
	 ((value) & SM_ERR_VALUE_BITS))))

/* everything is fine... */
/* #define SM_SUCCESS	0	defined in generic.h */

/* error types, notice checks down below: require order */
#define SM_ERR_NONE	0
#define SM_ERR_INFO	1	/* make this "compliant" with EOF? */
#define SM_ERR_WARN	2
#define SM_ERR_TEMP	3
#define SM_ERR_PERM	4
/* more? */
/*
**  For example:
**  SM_ERR_SOFT_LIMIT
**  SM_ERR_HARD_LIMIT
**  SM_ERR_CONF_LIMIT
**
*/

/* No an error iff the high bit is not set */
#define sm_is_success(err)	(((err) & SM_ERR_HIGH_BIT) == 0)
#define sm_is_err(err)	(((err) & SM_ERR_HIGH_BIT) != 0)
/* Note: this can also be just a warning or info! */

/*
**  XXX This doesn't really work if we want to "merge" error values
**	and others, i.e,. if error values must have SM_ERR_HIGH_BIT set.
**	Do we want that?
**  XXX See above! Requires ordering! Maybe use bitmask?
*/

/* these checks are not ok unless you already know it's an error */
#define sm_is_temp_err(err)	(sm_error_type(err) == SM_ERR_TEMP)
#define sm_is_perm_err(err)	(sm_error_type(err) == SM_ERR_PERM)
#define sm_is_warn_err(err)	(sm_error_type(err) == SM_ERR_WARN)
#define sm_is_error(err)	(sm_error_type(err) > SM_ERR_WARN)
#define sm_is_ok(err)		(sm_error_type(err) <= SM_ERR_WARN)

/* these checks are ok */
#define SM_IS_TEMP_ERR(err)	(sm_is_err(err) && sm_error_type(err) == SM_ERR_TEMP)
#define SM_IS_PERM_ERR(err)	(sm_is_err(err) && sm_error_type(err) == SM_ERR_PERM)
#define SM_IS_ERROR(err)	(sm_is_err(err) && sm_error_type(err) > SM_ERR_WARN)
#define SM_IS_OK(err)		(sm_is_success(err) || sm_error_type(err) <= SM_ERR_WARN)

#define sm_error_info(mod, value)	sm_error_gen(mod, SM_ERR_INFO, (value))
#define sm_error_warn(mod, value)	sm_error_gen(mod, SM_ERR_WARN, (value))
#define sm_error_temp(mod, value)	sm_error_gen(mod, SM_ERR_TEMP, (value))
#define sm_error_perm(mod, value)	sm_error_gen(mod, SM_ERR_PERM, (value))

#define sm_err_info(value)	sm_error_gen(0, SM_ERR_INFO, (value))
#define sm_err_warn(value)	sm_error_gen(0, SM_ERR_WARN, (value))
#define sm_err_temp(value)	sm_error_gen(0, SM_ERR_TEMP, (value))
#define sm_err_perm(value)	sm_error_gen(0, SM_ERR_PERM, (value))

/*
**  Where to start? This is the same value as in sm8/include/errstring.h
**  Make sure these offsets match the error codes used below!
**
**  NOTE: if you make additions here, then change also libmta/smerr2txt.c
*/

#define SM_ERR_BASE	256
#define DNS_ERR_BASE	(SM_ERR_BASE + 64)
#define R2821_BASE	512

/* sm specific error codes */
#define SM_E_NOMORE	(SM_ERR_BASE + 1)	/* no "next" entry */
#define SM_E_UNEXPECTED	(SM_ERR_BASE + 2)	/* unexpected error */

/*
**  Input parameter out of range (too large or too small).
**  This applies to scalar values that must be within a certain range
**  which might be configured at runtime.
*/

#define SM_E_RANGE	(SM_ERR_BASE + 3)

/*
**  Too big: an input parameter is too large, e.g., a string is too long.
**  This applies to non-scalar values (as opposed to SM_E_RANGE) which
**  must be within a certain range that is known a-priori.
*/

#define SM_E_2BIG	(SM_ERR_BASE + 4)

/*
**  Object (e.g., cache, array, hash table) is "full": no entries can be added;
*/

#define SM_E_FULL	(SM_ERR_BASE + 5)

/*
**  Operation would cause overflow of some variable, e.g., integer overflow.
**  This applies to scalar values (SC)
*/

#define SM_E_OVFLW_SC	(SM_ERR_BASE + 6)

/*
**  Operation would cause overflow of some buffer.
**  This applies to non-scalar values (NS)
*/

#define SM_E_OVFLW_NS	(SM_ERR_BASE + 7)

#define SM_E_NOTFOUND	(SM_ERR_BASE + 8)	/* object not found */

/* startup failed (need more detail!) */
#define SM_E_STARTFAIL	(SM_ERR_BASE + 9)
#define SM_E_SYNTAX	(SM_ERR_BASE + 10)
#define SM_E_USAGE	(SM_ERR_BASE + 11)

/* do not start the system; e.g., option like -? has been used */
#define SM_E_DONTSTART	(SM_ERR_BASE + 12)

/*
**  Version (compile/run time) mismatch; this applies to
**  libraries as well as data (e.g., persistent databases).
*/

#define SM_E_VER_MIX	(SM_ERR_BASE + 13)

#define SM_E_NO_AR	(SM_ERR_BASE + 14)	/* no AR available */
#define SM_E_NO_DA	(SM_ERR_BASE + 15)	/* no DA available */
#define SM_E_NO_DA_FREE	(SM_ERR_BASE + 16)	/* no DA free */

/* protocol version mismatch */
#define SM_E_PR_V_MISM	(SM_ERR_BASE + 17)

/* protocol error, e.g., unexpected RT or wrong length */
#define SM_E_PR_ERR	(SM_ERR_BASE + 18)

/* RCB too long or length doesn't match data (protocol error) */
#define SM_E_RCB2LONG	(SM_ERR_BASE + 19)

/* especially for map lookups */
#define SM_E_TEMPMAP	(SM_ERR_BASE + 20) /* temporary map lookup failure */
#define SM_E_PERMMAP	(SM_ERR_BASE + 21) /* permanent map lookup failure */
#define SM_E_CLOSEDMAP	(SM_ERR_BASE + 22) /* map closed (why?) */
#define SM_E_NOMAP	(SM_ERR_BASE + 23) /* map is NULL */
#define SM_E_NOTIMPL	(SM_ERR_BASE + 24) /* required function is NULL */
/* others? */

/* MX list is empty after removal of local addresses */
#define SM_E_MXEMPTY	(SM_ERR_BASE + 25)

/* talking to myself */
#define SM_E_TTMYSELF	(SM_ERR_BASE + 26)

/* alias expansion in AR failed */
#define SM_E_ALIASEXP	(SM_ERR_BASE + 27)

/* aliases nested too deep */
#define SM_E_ALIAS_REC	(SM_ERR_BASE + 28)

/* DNS: answer came from different IP address */
#define SM_E_IP_MISM	(SM_ERR_BASE + 29)

#define SM_E_NOSIG	(SM_ERR_BASE + 30)	/* BATV: no signature */
#define SM_E_EXPIRED	(SM_ERR_BASE + 31)	/* expired */

#define SM_E_RSR_PRB	(SM_ERR_BASE + 32)	/* resource problem */
#define SM_E_ILL_PIPE	(SM_ERR_BASE + 33)	/* invalid use of PIPELINING */
#define SM_E_RD		(SM_ERR_BASE + 34)	/* read error */
#define SM_E_EOF	(SM_ERR_BASE + 35)	/* read error: EOF */
#define SM_E_WR		(SM_ERR_BASE + 36)	/* write error */

#define SM_E_BARE_NL	(SM_ERR_BASE + 37)	/* bare NL '\n' in input */

/* connection to other module has been closed (EOF) */
#define SM_E_CONN_CLSD	(SM_ERR_BASE + 38)

/* communication context id mismatch (see smtps/s2q.c) */
#define SM_E_WRONG_ID	(SM_ERR_BASE + 39)
#define SM_SSL_ERROR_SYSCALL	(SM_ERR_BASE + 40)
#define SM_SSL_ERROR_SSL	(SM_ERR_BASE + 41)
#define SM_SSL_ERROR_GENERIC	(SM_ERR_BASE + 42)

#define SM_E_UNAVAIL	(SM_ERR_BASE + 43)

#define SM_E_LASTCODE	SM_E_UNAVAIL

/* check for consistency! */
#if DNS_ERR_BASE <= SM_E_LASTCODE
ERROR: fix error numbers: _DNS_ERR_BASE <= _SM_E_LASTCODE
#endif

#define E_CONFBASE	(SM_ERR_BASE + 45)	/* base for sm-conf errors */

/* check for consistency! */
#if E_CONFBASE <= SM_E_LASTCODE
ERROR: fix error numbers: _E_CONFBASE <= _SM_E_LASTCODE
#endif

/* SM_CONF_ERR values */
#define SM_C_E_NEWLINE_IN_STRING	(E_CONFBASE + 1)
#define SM_C_E_EOF_IN_STRING	(E_CONFBASE + 2)
#define SM_C_E_BAD_CHAR		(E_CONFBASE + 3)
#define SM_C_E_NO_MEMORY	(E_CONFBASE + 4)
#define SM_C_E_HEX_EXPECTED	(E_CONFBASE + 5)
#define SM_C_E_CHAR_OVERFLOW	(E_CONFBASE + 6)
#define SM_C_E_INVALID		(E_CONFBASE + 7)
#define SM_C_E_READ		(E_CONFBASE + 8)
#define SM_C_E_READ_OPEN	(E_CONFBASE + 9)
#define SM_C_E_READ_CLOSE	(E_CONFBASE + 10)
#define SM_C_E_EOF		(E_CONFBASE + 11)
#define SM_C_E_SYNTAX		(E_CONFBASE + 12)
#define SM_C_E_NOT_FOUND	(E_CONFBASE + 13)
#define SM_C_E_ALREADY		(E_CONFBASE + 14)
#define SM_C_E_TYPE		(E_CONFBASE + 15)
#define SM_C_E_NUL_IN_STRING	(E_CONFBASE + 16)
#define SM_C_E_TOO_MANY		(E_CONFBASE + 17)

/* check for consistency! use last SM_C_E_code here! */
#if DNS_ERR_BASE <= SM_C_E_TOO_MANY
ERROR: fix error numbers: _DNS_ERR_BASE <= _SM_C_E_TOO_MANY
#endif

#if 0
#define E_LDAPBASE	(E_PSEUDOBASE + 70)	/* base for LDAP errors */
#endif

/*
**  Modules
**  How fine grained should this be? Just on the library level?
**  Down to function level? In that case the module field needs to be larger.
**  Should the be somehow related to the logging context/modules?
**  For example, the DNS library has its own error codes (see above, starting
**  at DNS_ERR_BASE). Having also a DNS error module seems like overkill, but
**  the DNS module can also return "generic" errors, e.g., ENOMEM.
**  Note: any change here must be reflected in libmta/smerr2txt.c, e_modules
*/

#define SM_EM_NONE	0
#define SM_EM_AQ	1
#define SM_EM_IQDB	2
#define SM_EM_IBDB	3
#define SM_EM_EDB	4
#define SM_EM_CDB	5
#define SM_EM_DA	6
#define SM_EM_OCC	7
#define SM_EM_DNS	8
#define SM_EM_SMTPC	9
#define SM_EM_SMTPS	10
#define SM_EM_MAPS	11
#define SM_EM_MAP	12
#define SM_EM_BDB	13	/* Berkeley DB related */

/*
**  state threads: sm I/O layer (not really returned to application because
**  I/O errors are "hidden" and just indicated with a flag in sm I/O)
*/

#define SM_EM_STTHRIO	14

/* state threads (not yet used) */
#define SM_EM_STTHR	15
#define SM_EM_EVTHR	16
#define SM_EM_RECCOM	17
#define SM_EM_HT	18	/* hash table */
#define SM_EM_RSC	19	/* Restricted Size Cache */
#define SM_EM_STR	20	/* str */
#define SM_EM_RCB	21	/* RCB */

#define SM_EM_TLS	22	/* TLS library */
#define SM_EM_SASL	23	/* SASL library */

#define SM_EM_NET	24	/* network related */
#define SM_EM_IO	25	/* sm I/O related */
#define SM_EM_LOG	26	/* log related */
#define SM_EM_ADDR	27	/* RFC 2821 address parsing */
#define SM_EM_IP	28	/* IP address parsing */

/* inside QMGR */
#define SM_EM_Q_Q2AR	32	/* QMGR -> AR */
#define SM_EM_Q_AR2Q	33	/* AR -> QMGR */
#define SM_EM_Q_Q2SS	34	/* QMGR -> SMTPS */
#define SM_EM_Q_SS2Q	35	/* SMTPS -> QMGR */
#define SM_EM_Q_Q2SC	36	/* QMGR -> SMTPC */
#define SM_EM_Q_SC2Q	37	/* SMTPC -> QMGR */
#define SM_EM_Q_RDIBDB	38	/* read IBDB */
#define SM_EM_Q_IQDB	39	/* IQDB */
#define SM_EM_Q_IBDB	40	/* IBDB */
#define SM_EM_Q_EDBC	41	/* EDB cache */
#define SM_EM_Q_DSN	42	/* bounce handling */
#define SM_EM_Q_START	43	/* QMGR startup */
#define SM_EM_Q_CTL2Q	44	/* CONTROL -> QMGR */
#define SM_EM_Q_CONF	45	/* QMGR configuration */
#define SM_EM_Q_CLEAN	46	/* QMGR cleanup functions */
#define SM_EM_Q_SCHED	47	/* QMGR scheduler */
#define SM_EM_Q		48	/* other QMGR functions */

/* inside SMAR */
#define SM_EM_AR_Q2AR	60	/* QMGR -> AR */
#define SM_EM_AR_AR2Q	61	/* AR -> QMGR */
#define SM_EM_AR_DNSW	62	/* DNS Write */
#define SM_EM_AR_DNSR	63	/* DNS Read */
#define SM_EM_AR_DNSD	63	/* DNS Decode */
#define SM_EM_AR_WAIT	64	/* internal wait for async function */
#define SM_EM_AR	65	/* other AR functions */

#define SM_EM_CONF	66	/* sm-conf */

#define SM_EM_PMILTER	67	/* libpmilter */
#define SM_EM_THR	68	/* threads */
#define SM_EM_BATV	69	/* BATV */

#define SM_EM_UTIL	127	/* utility programs */
/* maximum: 127 */

#if 0
#define SM_EM_x	2
#endif

#define SM_CNF_E_NEWLINE_IN_STRING	sm_error_perm(SM_EM_CONF, SM_C_E_NEWLINE_IN_STRING)
#define SM_CNF_E_EOF_IN_STRING	sm_error_perm(SM_EM_CONF, SM_C_E_EOF_IN_STRING)
#define SM_CNF_E_BAD_CHAR	sm_error_perm(SM_EM_CONF, SM_C_E_BAD_CHAR)
#define SM_CNF_E_NO_MEMORY	sm_error_temp(SM_EM_CONF, SM_C_E_NO_MEMORY)
#define SM_CNF_E_HEX_EXPECTED	sm_error_perm(SM_EM_CONF, SM_C_E_HEX_EXPECTED)
#define SM_CNF_E_CHAR_OVERFLOW	sm_error_perm(SM_EM_CONF, SM_C_E_CHAR_OVERFLOW)
#define SM_CNF_E_INVALID	sm_error_perm(SM_EM_CONF, SM_C_E_INVALID)
#define SM_CNF_E_READ		sm_error_perm(SM_EM_CONF, SM_C_E_READ)
#define SM_CNF_E_READ_OPEN	sm_error_perm(SM_EM_CONF, SM_C_E_READ_OPEN)
#define SM_CNF_E_READ_CLOSE	sm_error_perm(SM_EM_CONF, SM_C_E_READ_CLOSE)
#define SM_CNF_E_EOF		sm_error_perm(SM_EM_CONF, SM_C_E_EOF)
#define SM_CNF_E_SYNTAX		sm_error_perm(SM_EM_CONF, SM_C_E_SYNTAX)
#define SM_CNF_E_NOT_FOUND	sm_error_perm(SM_EM_CONF, SM_C_E_NOT_FOUND)
#define SM_CNF_E_ALREADY	sm_error_perm(SM_EM_CONF, SM_C_E_ALREADY)
#define SM_CNF_E_TYPE		sm_error_perm(SM_EM_CONF, SM_C_E_TYPE)
#define SM_CNF_E_NUL_IN_STRING	sm_error_perm(SM_EM_CONF, SM_C_E_NUL_IN_STRING)
#define SM_CNF_E_TOO_MANY	sm_error_perm(SM_EM_CONF, SM_C_E_TOO_MANY)


#define SM_ETXT_UNKNOWN	"Unknown"
char	*smerr2txt(sm_error_T _err);
char	*smmod2txt(sm_error_T _err);
sm_ret_T errno2err(int _err, int _module);
int	 smerr2txt_r(sm_error_T _err, char *_strerrbuf, size_t _buflen);

#if defined(ELAST)
# define sm_sys_nerr (ELAST + 1)
#elif HAVE_SYS_NERR
# define sm_sys_nerr sys_nerr
#else
# define sm_sys_nerr SM_ERR_BASE
#endif

#endif /* SM_ERROR_H */


syntax highlighted by Code2HTML, v. 0.9.1