/*
 * Copyright (c) 2003-2005 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: map.h,v 1.63 2006/11/13 00:42:04 ca Exp $
 */

#ifndef SM_MAP_H
#define SM_MAP_H 1

#include "sm/generic.h"
#include "sm/types.h"
#include "sm/magic.h"
#include "sm/cstr.h"
#include "sm/str-int.h"
#include "sm/rdstr.h"
#include "sm/time.h"
#include "sm/map-str.h"
#if MTA_USE_PTHREADS
#include "sm/pthread.h"
#endif

/*
XXX Missing:
flags the specify who is responsible for memory allocation:
DB should allocate key/data
caller allocates key/data (and preserves it)

what about persistence?
there should be some flags the specify what a DB type can offer,
e.g., DB close removes all data, maybe whether DB can't/won't allocate data.
there should be also something that specifies the type of data that is
stored, currently it is sm_str_P for BDB but char * for BHT.
*/

#if 0
typedef void	*(*sm_map_key_alloc_F)(size_t size, void *app_ctx);
typedef void	 (*sm_map_key_free_F)(void *ptr, void *app_ctx);
typedef void	*(*sm_map_data_alloc_F)(size_t size, void *app_ctx);
typedef void	 (*sm_map_data_free_F)(void *ptr, void *app_ctx);
#endif /* 0 */

struct sm_map_entry_S
{
	sm_map_key_T	 sm_map_entry_key;
	sm_map_data_T	 sm_map_entry_data;
};

struct sm_map_cursor_S
{
	uint32_t	 sm_map_cursor_state;
	void		*sm_map_cursor_val;
};

/* XXX should one of these be 0 (to act as default)? */
#define SMAP_MODE_RDONLY	0x01
#define SMAP_MODE_WRONLY	0x02
#define SMAP_MODE_RDWR		0x04
#define SMAP_MODE_CREATE	0x08

/* sm map option, rest defined in implementation specific include files */
#define SMPO_END	0x0000	/* end of options (vararg) [must be 0] */

/*
**  Some "generic" map open/setopt options
**  Use a type marker: 0: int, 1: void *
**  This is required to properly access the vararg and the data
**  stored in sm_map_opt_T (see libsmmap/map.h).
**  Note: short/char are expanded to int, so it's not necessary to have
**  type markers for those.
*/

#define SMPO_INT	0x0000
#define SMPO_PTR	0x0001

#define SMPO_CACHE_SIZE	(0x0010|SMPO_INT)
#define SMPO_HASH_NELEM	(0x0020|SMPO_INT)
#define SMPO_MAX_ELEM	(0x0030|SMPO_INT)

#define SMPO_PORT	(0x0040|SMPO_INT) /* port for socket map etc */
#define SMPO_IPV4	(0x0050|SMPO_INT) /* IPv4 address */
#define SMPO_SOCKPATH	(0x0060|SMPO_PTR) /* path to Unix domain socket */
#define SMPO_MAP	(0x0070|SMPO_PTR) /* sequence map: map to use */
#define SMPO_MAPNAME	(0x0080|SMPO_PTR) /* sequence map: map name to use */
#define SMPO_TMOUT	(0x0090|SMPO_INT) /* timeout for lookups */
#define SMPO_CAPS	(0x00A0|SMPO_INT) /* capabilities */

#define SMPO_STR	(0x0100|SMPO_PTR) /* str to use for str map */

#define SMPO_INIT_CB	(0x0200|SMPO_PTR) /* init cb function (hash map) */

#define SMPO_TYPE_MASK	0x0000F
#define SMPO_GET_TYPE(opt)	((opt) & SMPO_TYPE_MASK)

#if 0
/* defines for sm_map_open() varargs: type and value, as well as end marker */
#define SM_MAPOPEN_INT	1
#define SM_MAPOPEN_UINT	2
#define SM_MAPOPEN_STR	3
#define SM_MAPOPEN_CSTR	4
#define SM_MAPOPEN_BUF	5
#define SM_MAPOPEN_END	8
#endif /* 0 */

/* user supplied function to initialize a map, called from open */
typedef sm_ret_T	(*sm_map_init_cb_F)(void *app_ctx);

/* ------------------------------------------------------------ */
/* function prototypes */
/* basic map function */
sm_ret_T sm_map_create(sm_maps_P _maps, sm_cstr_P _type, uint32_t _flags, sm_map_P *_map);
sm_ret_T sm_map_open(sm_maps_P _maps, const sm_cstr_P _name, const sm_cstr_P _type, uint32_t _flags, const char *_path, int _mode, sm_map_P *_pmap, ...);
sm_ret_T sm_map_close(sm_map_P _map, uint32_t _flags);
sm_ret_T sm_map_destroy(sm_map_P _map, uint32_t flags);
sm_ret_T sm_map_reopen(sm_map_P _map, uint32_t flags, ...);
sm_ret_T sm_map_setopt(sm_map_P _map, ...);
sm_ret_T sm_map_getopt(sm_map_P _map, int _which, void *_valp);

sm_ret_T sm_map_lookup(sm_map_P _map, uint32_t _flags, sm_map_key_P _key, sm_map_data_P _data);
sm_ret_T sm_map_add(sm_map_P _map, sm_map_key_P _key, sm_map_data_P _data, uint _flags);
sm_ret_T sm_map_rm(sm_map_P _map, sm_map_key_P _key);
sm_ret_T sm_map_rewrite(sm_map_P _map, uint32_t _flags, sm_str_P _old, sm_str_P _new);

/* specific lookup function */
sm_ret_T sm_map_lookup_ip(sm_map_P _map, sm_str_P _ip, sm_str_P _tag, uint32_t _flags, sm_str_P _rhs);
sm_ret_T sm_map_lookup_domain(sm_map_P _map, sm_rdstr_P _domain, sm_str_P _tag, uint32_t _flags, sm_str_P _rhs);
sm_ret_T sm_map_lookup_addr(sm_map_P _map, sm_str_P _user, sm_str_P _detail, sm_str_P _domain, sm_str_P _tag, uchar delim, uint32_t _flags, sm_str_P _rhs);

/* ------------------------------------------------------------ */
/* flags for map (this isn't correct yet) */
#define SMMAP_FL_NONE		0x00000000u
#define SMMAP_FL_CREATED	0x00000001u
#define SMMAP_FL_OPEN		0x00000002u
#define SMMAP_FL_OPENBOGUS	0x00000004u
#define SMMAP_FL_CLOSING	0x00000008u
#define SMMAP_FL_CLOSED		0x00000010u
#define SMMAP_FL_ALLOCKEY	0x00000020u
#define SMMAP_FL_ALLOCDATA	0x00000040u
#define SMMAP_FL_FREEKEY	0x00000080u
#define SMMAP_FL_FREEDATA	0x00000100u
#define SMMAP_FL_CLOSEFREEKEY	0x00000200u
#define SMMAP_FL_CLOSEFREEDATA	0x00000400u
#define SMMAP_FL_VALID		0x00000800u
#define SMMAP_FL_INCLNULL	0x00001000u
#define SMMAP_FL_OPTIONAL	0x00002000u
#define SMMAP_FL_NOFOLDCASE	0x00004000u
#define SMMAP_FL_MATCHONLY	0x00008000u
#define SMMAP_FL_WRITABLE	0x00010000u
#define SMMAP_FL_ALIAS		0x00020000u
#define SMMAP_FL_TRY0NUL	0x00040000u
#define SMMAP_FL_TRY1NUL	0x00080000u
#define SMMAP_FL_LOCKED		0x00100000u
#define SMMAP_FL_KEEPQUOTES	0x00200000u
#define SMMAP_FL_NODEFER	0x00400000u
#define SMMAP_FL_SINGLEMATCH	0x00800000u

#define SMMAP_SET_FL(map, fl)	(map)->sm_map_flags |= (fl)
#define SMMAP_CLR_FL(map, fl)	(map)->sm_map_flags &= ~(fl)
#define SMMAP_IS_FL(map, fl)	(((map)->sm_map_flags & (fl)) != 0)

/*
**  Capabilities of a map.
**  What about the placement of '@'? Should that also be reflected here?
**  (after user or before domain)
*/

#define SMMAP_CAPS_NONE		0x00000000u
#define SMMAP_CAPS_DYNAMIC	0x00000001u /* dynamic close/open */
#define SMMAP_CAPS_DOMAIN	0x00000010u /* contains domain part */
#define SMMAP_CAPS_LOCALPART	0x00000020u /* contains local parts */
#define SMMAP_CAPS_DETAIL	0x00000040u /* may contains +detail */
#define SMMAP_CAPS_TAG		0x00000080u /* tag */
#define SMMAP_CAPS_IPV4		0x00000100u /* IPv4 */
#define SMMAP_CAPS_IPV6		0x00000200u /* IPv6 */
#define SMMAP_CAPS_LTMASK	0x000003F0u /* mask for lookup types */

#define SMMAP_CAPS_LTALL	(SMMAP_CAPS_DOMAIN|SMMAP_CAPS_LOCALPART|\
	SMMAP_CAPS_DETAIL|SMMAP_CAPS_TAG|\
	SMMAP_CAPS_IPV4|SMMAP_CAPS_IPV6)

#define SMMAP_SET_CAPS(map, caps)	(map)->sm_map_caps |= (caps)
#define SMMAP_CLR_CAPS(map, caps)	(map)->sm_map_caps &= ~(caps)
#define SMMAP_IS_CAPS(map, caps)	(((map)->sm_map_caps & (caps)) != 0)

/*
**  Flags for lookup/add/rm etc
**  There are different kinds:
**  - those which describe actions (what to do)
**  - those which describe features (what kind of key etc)
*/

#define SMMAP_FL_LWR_KEY	0x00000001u	/* change key to lower case */

/*
**  Type of key (for lookup/add/rm etc)
**  NOTE: this is also used by capabilities! The values MUST be identical!
*/

#define SMMAP_FL_HAS_DOMAIN	SMMAP_CAPS_DOMAIN	/* contains domain */
#define SMMAP_FL_HAS_LOCALPART	SMMAP_CAPS_LOCALPART	/* contains localpart */
#define SMMAP_FL_HAS_DETAIL	SMMAP_CAPS_DETAIL	/* contains +detail */
#define SMMAP_FL_HAS_TAG	SMMAP_CAPS_TAG		/* has tag */
#define SMMAP_FL_HAS_IPV4	SMMAP_CAPS_IPV4		/* IPv4 address */
#define SMMAP_FL_HAS_IPV6	SMMAP_CAPS_IPV6		/* IPv6 address */

#define SMMAP_FL_HAS_LTALL	(SMMAP_FL_HAS_DOMAIN|SMMAP_FL_HAS_LOCALPART|\
	SMMAP_FL_HAS_DETAIL|SMMAP_FL_HAS_TAG|\
	SMMAP_FL_HAS_IPV4|SMMAP_FL_HAS_IPV6)

#define SMMAP_LT_M_CAPS(map, lookuptype)	\
	(((map)->sm_map_caps & (lookuptype & SMMAP_CAPS_LTMASK)) != 0)

/* ------------------------------------------------------- */
/* lookup flags (for abstraction layer: sm_map_lookup_*()) */
#define SMMAP_LFL_NONE		0x00000000u
#define SMMAP_LFL_FULL		0x00000001u /* full (exact) lookup */
#define SMMAP_LFL_DETPLUS	0x00000002u /* user++ lookup */
#define SMMAP_LFL_DETSTAR	0x00000004u /* user+* lookup */
#define SMMAP_LFL_STAR		0x00000008u /* user* lookup */
#define SMMAP_LFL_USER		0x00000010u /* user lookup */
#define SMMAP_LFL_DOMAIN	0x00000020u /* just domain (wo localpart) */
#define SMMAP_LFL_LOCAL		0x00000040u /* just localpart (wo domain) */
#define SMMAP_LFL_DOTSUBDOM	0x00000200u /* .sub.domain */
#define SMMAP_LFL_DOT		0x00000400u /* just . (for default if no tag) */
#define SMMAP_LFL_IMPLDET	0x00000800u /* user+detail matches user */

#define SMMAP_LFL_NOAT		0x00001000u /* don't put @ after user */
#define SMMAP_LFL_TAG		0x00002000u /* just tag (if not NULL) */

#define SMMAP_LFL_REPL		0x00004000u /* replace %n with wildcard match */

#define SMMAP_LFL_MCR_REPL	0x00008000u /* use macro replacement ${name} */

#define SMMAP_LFL_SUBNETS	0x00010000u /* IP address: lookup all subnets */


#define SMMAP_LFL_ALL	0x000007ffu	/* default lookups */
#define SMMAP_LFL_ALIAS	(SMMAP_LFL_FULL|SMMAP_LFL_DETPLUS|SMMAP_LFL_DETSTAR|SMMAP_LFL_STAR|SMMAP_LFL_USER|SMMAP_LFL_NOAT|SMMAP_LFL_LOCAL)
#define SMMAP_LFL_ALIASWODET	(SMMAP_LFL_FULL|SMMAP_LFL_STAR|SMMAP_LFL_USER|SMMAP_LFL_NOAT|SMMAP_LFL_LOCAL)
#define SMMAP_LFL_DET	(SMMAP_LFL_DETPLUS|SMMAP_LFL_DETSTAR)
#define SMMAP_LFL_VIRTUSER	(SMMAP_LFL_FULL|SMMAP_LFL_DETPLUS|SMMAP_LFL_DETSTAR|SMMAP_LFL_USER|SMMAP_LFL_DOTSUBDOM|SMMAP_LFL_LOCAL)
#define SMMAP_LFL_MT	(SMMAP_LFL_DOMAIN|SMMAP_LFL_DOTSUBDOM|SMMAP_LFL_DOT)

#define SMMAP_IS_LFL(flags, fl)	(((flags) & (fl)) != 0)

/* map lookup return values */
#define SM_MAP_FOUND	SM_SUCCESS

/*
**  return codes from lookup functions:
**	SM_E_NOMAP: no map defined
**	SM_E_NOTIMPL: (lookup) function not defined
**	ENOENT: missing some internal entry, e.g., a context pointer
**	SM_E_UNAVAIL: feature/capability unavailable
**	SM_E_NOTFOUND: no matching entry found
**	SM_E_TEMPMAP: temporary lookup error
**	SM_E_PERMMAP: permanent lookup error
**	SM_E_OVFLW_NS: buffer not big enough for result
**		(usually handled internally by map layer)
**	ENOMEM: out of memory
**	SM_E_PR_ERR: protocol error (server response was bogus)
*/

/* entry found, but result doesn't fit into provided data str */
#define SM_MAP_DATA2BIG sm_error_temp(SM_EM_MAP, SM_E_OVFLW_NS)
#define SM_MAP_NOTFOUND	sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND)
#define SM_MAP_TEMPMAP	sm_error_temp(SM_EM_MAP, SM_E_TEMPMAP)
#define SM_MAP_PERMMAP	sm_error_perm(SM_EM_MAP, SM_E_PERMMAP)

/* map_add flags */
#define SMMAP_AFL_NONE		0x0000u
#define SMMAP_AFL_UNIQUE	0x0001u	/* unique keys */

#if SM_MAP_CHECK
# define SM_IS_MAP(map)		SM_REQUIRE_ISA((map), SM_MAP_MAGIC)
#else
# define SM_IS_MAP(map)		SM_REQUIRE((map) != NULL)
#endif

#define SM_IS_KEY(key)		SM_IS_BUF(key)
#define SM_IS_DATA(data)	SM_IS_BUF(data)

sm_ret_T sm_mapname_find(sm_maps_P _maps, const sm_cstr_P _map_name, sm_map_P *_pmap);
sm_ret_T sm_mapname_findc(sm_maps_P _maps, const char *_map_name, sm_map_P *_pmap);

#endif /* SM_MAP_H */


syntax highlighted by Code2HTML, v. 0.9.1