/*
 * Copyright (c) 2002-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: edb.h,v 1.53 2007/06/18 04:42:30 ca Exp $
 */

#ifndef SM_EDB_H
#define SM_EDB_H 1

#include "sm/generic.h"
#include "sm/types.h"
#include "sm/magic.h"
#include "sm/str.h"
#include "sm/time.h"
#include "sm/mta.h"
#include "sm/io.h"
#include "sm/log.h"
#include "sm/rcb.h"
#include "sm/bdb.h"
#include "sm/pthread.h"
#include "sm/actdb.h"
#include "sm/queue.h"
#include "sm/edbdef.h"
#include "sm/edbcnf.h"

#ifndef SM_REQL_FLE
#define SM_REQL_FLE 0
#endif

/* Abstraction layer for deferred envelope database (disk only) */

#if 0

XXX Use same data as AQ?

/*
from db.func.tex:

*/

#endif /* 0 */

/*
**  Default and maximum size for an RCB which is used to hold ta/rcpt
**  information for transferring AQ data to/from EDB.
**  Note: if the default size is rather large, then a lot of space is
**	wasted. If it is too small, then it could happen that an
**	encoding/decoding fails because it runs out of memory.
**	XXX need to gather some statistics (and count some bytes...)
**  The last entry is the "minimum" size for a rcpt RCB: about 96 bytes
**  default data and up to 256 bytes of address rounded to the next
**  multiple of 2.
*/

#define EDB_RC_SZ	(8 * 1024)
#define EDB_RC_MAXSZ	(64 * 1024)
#define EDB_RC_SMALLSZ	512

typedef struct edb_ctx_S	edb_ctx_T, *edb_ctx_P;
typedef struct edb_req_S	edb_req_T, *edb_req_P;
#if 0
typedef struct edb_ta_S		edb_ta_T, *edb_ta_P;
typedef struct edb_rcpt_S	edb_rcpt_T, *edb_rcpt_P;
#endif /* 0 */

/* Berkeley DB cursor */
typedef DBC	edb_cursor_T, *edb_cursor_P;

/* Use enum? */
#define EDB_REQ_TA	0x01
#define EDB_REQ_RCPT	0x02
#define EDB_REQ_VRS	0x04
#define EDB_REQ_TA_DEL	0x11
#define EDB_REQ_RCPT_DEL	0x12

/* request flags */
#define EDB_RQF_NONE	0x00u
#define EDB_RQF_SMALL	0x01u	/* get a "small" rcb */
#define EDB_RQF_ALLOC	0x02u	/* alloc rcb even if there are some in list */
#define EDB_RQF_FREE	0x04u	/* free rcb instead of putting it into a list */
#if SM_REQL_FLE
#define EDB_RQF_EMERG	0x08u	/* get an "emergency" rcb */
#endif

/*
**  struct to store "requests", i.e., a list of changes for DEFEDB.
**  These changes will be committed in a single transaction.
**  An RCB stores the data for the DB entry, req_id is the key,
**  its content depends on the request type: it's either a
**  - transaction ID		or a
**  - recipient ID
*/

struct edb_req_S
{
	uint                            edb_req_type;
	smtp_id_T                       edb_req_id;
	sm_rcb_P                        edb_req_rcb;
	SIMPLEQ_ENTRY(edb_req_S)        edb_req_link;
};

#define EDBREQL_INIT(edb_req_hd)	SIMPLEQ_INIT(edb_req_hd)
#define EDBREQL_FIRST(edb_req_hd)	SIMPLEQ_FIRST(edb_req_hd)
#define EDBREQL_END(edb_req_hd)		SIMPLEQ_END(edb_req_hd)
#define EDBREQL_EMPTY(edb_req_hd)	SIMPLEQ_EMPTY(edb_req_hd)
#define EDBREQL_NEXT(edb_req)		SIMPLEQ_NEXT(edb_req, edb_req_link)
#define EDBREQL_PRE(edb_req_hd, edb_req) SIMPLEQ_INSERT_HEAD(edb_req_hd, edb_req, edb_req_link)
#define EDBREQL_APP(edb_req_hd, edb_req) SIMPLEQ_INSERT_TAIL(edb_req_hd, edb_req, edb_req_link)
#define EDBREQL_REMOVE(edb_req_hd) SIMPLEQ_REMOVE_HEAD(edb_req_hd, edb_req_link)

#define SM_IS_EDBREQL(edb_req_hd)	SM_ASSERT((edb_req_hd) != NULL)

typedef SIMPLEQ_HEAD(, edb_req_S)	edb_req_hd_T, *edb_req_hd_P;

#if 0
/*
**  No extra data structures for EDB rcpts/tas, the data is transferred
**  using AQ structures to avoid extra copying.
*/

/*
**  XXX need:
**	delivery agent
**	host(list) for connection (pre-MX?)
*/

// struct edb_rcpt_S
// {
// 	sessta_id_T		 edbr_ss_ta_id;	/* ta id in SMTPS */
// 	sm_str_P		 edbr_pa;	/* printable addr */
// 	smtp_status_T		 edbr_status;	/* status */
// 	uint			 edbr_flags;	/* flags */
// 	rcpt_idx_T		 edbr_idx;	/* rcpt idx */
// 	uint			 edbr_tries;	/* deliver attemts */
// 	uint32_t		 edbr_srv_ipv4;	/* XXX HACK! */
// 	time_T			 edbr_st_time;	/* start time (rcvd) */
// 	time_T			 edbr_last_try;
// 	time_T			 edbr_next_try;
// 
// 	/* XXX parameters? */
// };
// 
// 
// /* transaction context */
// struct edb_ta_S
// {
// 	sessta_id_T	 edbta_ta_id;	/* ta id in SMTPS */
// 	sm_str_P	 edbta_mail_pa;	/* printable addr */
// 	uint		 edbta_rcpts_tot;	/* total number recipients */
// 	uint		 edbta_rcpts_left;	/* rcpts still to deliver */
// 	uint		 edbta_state;
// 	size_t		 edbta_msg_size;	/* KB */
// 	cdb_id_P	 edbta_cdb_id;
// 
// 	/* XXX other times? */
// 	time_T		 edbta_st_time;	/* start time (received) */
// };
#endif /* 0 */

sm_ret_T edb_open(edb_cnf_P _edb_cnf, const char *_base_path, sm_log_ctx_P _lctx, edb_ctx_P *_edb);
sm_ret_T edb_close(edb_ctx_P _edb);
sm_ret_T edb_rcpt_app(edb_ctx_P _edb_ctx, aq_rcpt_P _aq_rcpt, edb_req_hd_P _edb_req_hd, int _status);
sm_ret_T edb_ta_app(edb_ctx_P _edb_ctx, aq_ta_P _aq_ta, edb_req_hd_P _edb_req_hd, int _status);
sm_ret_T edb_wr_status(edb_ctx_P _edb_ctx, edb_req_hd_P _edb_req_hd);
sm_ret_T edb_rd_req(edb_ctx_P _edb_ctx, edb_req_P _edb_req);

sm_ret_T edb_req_new(edb_ctx_P _edb_ctx, uint32_t _flags, edb_req_P *_pedb_req, bool _lockit);
sm_ret_T edb_req_rel(edb_ctx_P _edb_ctx, edb_req_P _edb_req, uint32_t _flags, thr_lock_T _locktype);

sm_ret_T edb_rcpt_dec(edb_req_P _edb_req, aq_rcpt_P _aq_rcpt);
sm_ret_T edb_ta_dec(edb_req_P _edb_req, aq_ta_P _aq_ta);

sm_ret_T edb_rd_open(edb_ctx_P _edb_ctx, edb_cursor_P *_pedb_cursor);
sm_ret_T edb_rd_close(edb_ctx_P _edb_ctx, edb_cursor_P _edb_cursor);
sm_ret_T edb_rd_next(edb_ctx_P _edb_ctx, edb_cursor_P _edb_cursor, edb_req_P _edb_req);
sm_ret_T edb_get_type(edb_req_P _edb_req);

sm_ret_T edb_ta_rm(edb_ctx_P _edb_ctx, sessta_id_T _ta_id);
sm_ret_T edb_rcpt_rm(edb_ctx_P _edb_ctx, rcpt_id_T _rcpt_id);
sm_ret_T edb_ta_rm_req(edb_ctx_P _edb_ctx, sessta_id_T _ta_id, edb_req_hd_P _edb_req_hd);
sm_ret_T edb_rcpt_rm_req(edb_ctx_P _edb_ctx, rcpt_id_T _rcpt_id, edb_req_hd_P _edb_req_hd);

sm_ret_T edb_req_free(edb_req_P _edb_req);
sm_ret_T edb_reql_free(edb_ctx_P _edb_ctx, edb_req_hd_P _edb_reql);

sm_ret_T edb_reql_init(edb_ctx_P _edb_ctx, edb_req_hd_P _edb_reql, thr_lock_T _locktype);

sm_ret_T edb_chkpt(edb_ctx_P _edb_ctx);

sm_ret_T edb_status(edb_ctx_P _edb_ctx, sm_file_T *_fp);

#endif /* SM_EDB_H */


syntax highlighted by Code2HTML, v. 0.9.1