/*
* 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: ibdb.h,v 1.70 2007/06/18 04:42:30 ca Exp $
*/
#ifndef SM_IDB_H
#define SM_IDB_H 1
#include "sm/generic.h"
#include "sm/str.h"
#include "sm/io.h"
#include "sm/mta.h"
#include "sm/cstr.h"
#include "sm/cdb.h"
#include "sm/queue.h"
#include "sm/pthread.h"
#include "sm/fs.h"
#include "sm/hdrmod.h"
/* Abstraction layer for ibdb (Incoming DB, disk backup) */
/*
** Questions:
** - Do we want to use sm_io_*() or do we access the FS directly?
** - Size of io buffer: same as size of file? That might be too big.
** - How to avoid I/O? Write a list of RCBs and write their buffers
** directly (using vwrite())? That's ugly because it's too much
** buffering: first in RCB, then in sm_io buffer, then OS...
*/
#if 0
ibdb_open(IN name, IN mode, IN size, OUT status, OUT ibdb-handle):
open an incoming envelope database.
ibdb_close(IN ibdb-handle, OUT status):
close an incoming envelope database.
ibdb_ta_add(IN ibdb-handle, IN sender-env-info, IN ta-id, OUT status):
write envelope data
ibdb_ta_rm(IN ibdb-handle, IN ta-id, OUT status):
remove an envelope from the EDB
ibdb_ta_discard(IN ibdb-handle, IN ta-id, OUT status):
discard envelope
ibdb_rcpt_add(IN ibdb-handle, IN ta-id, IN rcpt-env-info, OUT status):
add a new recipient (RCPT command).
ibdb_rcpt_rm(IN ibdb-handle, IN ta-id, IN rcpt-id, IN rpct-status,
OUT status):
remove a recipient (mail has been taken care of).
ibdb_commit(IN ibdb-handle, OUT status):
commit envelope information to stable storage.
recovery functions:
ibdb_readprep(IN ibdb-handle, OUT cursor, OUT status):
prepare to read through EDB.
ibdb_getnext(IN cursor, OUT status, OUT record):
Get next entry from EDB.
ibdb_readclose(IN ibdb-handle, IN cursor, OUT status):
stop reading through EDB.
Data:
Sender (transaction):
transaction-id & transaction identifier
start-time & start time of transaction
sender-spec & address incl. ESMTP extensions
cdb-id & CDB identifier (obtained from cdb?)
n-rcpts & reference count for cdb-id
ESMTP sender extensions (substructure of the structure above)
size & size of mail content (SIZE=)
bodytype & type of body
envid & envelope id
ret & DSN return information (FULL, HDRS)
auth & AUTH parameter
by & Deliverby specification
Per recipient (transaction):
transaction-id & transaction identifier
rcpt-spec & address incl. ESMTP extensions
& and maybe a unique id (per session/transaction?)
ESMTP Recipient extensions (substructure of the structure above):
notify & DSN parameters (SUCCESS, FAILURE, WARNING)
orcpt & original recipient
#endif /* 0 */
/* IBDB record types */
/* #define RT_CONT 0x80000000 * continues in next record */
/*
** should these types contain a type specifier?
** For example:
** 0x04 uint32_t
** 0x02 str
** 0x01 uchar *
** That might help to write generic(?) en/decode functions.
** However, how can we (un)pack into(from) an unknown struct?
** Could we do some hacking with offsetof()? I doubt it.
*/
#define RT_IBDB_TA 0x0100 /* transaction record (sender) */
#define RT_IBDB_TAID 0x0101 /* transaction ID */
#define RT_IBDB_CDBID 0x0102 /* CDB ID */
#define RT_IBDB_NRCPTS 0x0103 /* nrcpts */
#define RT_IBDB_MAIL 0x0104 /* sender address */
#define RT_IBDB_TA_ST 0x0110 /* transaction status */
#define IBDB_TA_NEW 0x0000 /* new transaction */
#define IBDB_TA_DONE 0x0010 /* transaction done */
/* more detailled status: */
#define IBDB_TA_DELIV 0x0011 /* delivered */
#define IBDB_TA_TEMP 0x0012 /* deferred (in defedb) */
#define IBDB_TA_PERM 0x0013 /* deferred (in defedb) */
#define IBDB_TA_CANCEL 0x0020 /* cancelled */
#define idbd_ta_done(status) (((status) & 0x00f0) == IBDB_TA_DONE)
#define idbd_ta_cancelled(status) (((status) & 0x00f0) == IBDB_TA_CANCEL)
#define RT_IBDB_RCPT 0x0200 /* recipient record */
#define RT_IBDB_RCPT_ST 0x0210 /* recipient status */
#define RT_IBDB_RCPT_IDX 0x0212 /* recipient index */
#define RT_IBDB_RCPT_PA 0x0213 /* recipient printable address */
#define IBDB_RCPT_NEW 0x0000 /* new transaction */
#define IBDB_RCPT_DONE 0x0010 /* transaction done */
/* more detailled status: */
#define IBDB_RCPT_DELIV 0x0011 /* delivered */
#define IBDB_RCPT_TEMP 0x0012 /* deferred (in defedb) */
#define IBDB_RCPT_PERM 0x0013 /* deferred (in defedb) */
#define idbd_rcpt_done(status) (((status) & 0x00f0) == IBDB_RCPT_DONE)
#define RT_IBDB_HDRMOD 0x0300 /* header modification record */
#define RT_IBDB_HM_TAID 0x0301 /* transaction ID */
#define RT_IBDB_HM_TYPE 0x0303 /* type */
#define RT_IBDB_HM_POS 0x0305 /* position */
#define RT_IBDB_HM_HDR 0x0306 /* header */
#define RT_IBDB_VERS_R 0x0400 /* version record */
#define RT_IBDB_VERS_N 0x0403 /* version number */
/* current version (16 bits major/8 bits minor/8 bits patchlevel) */
#define IBDB_VERSION 0x00010100
#define IBDB_VRS_MAJ(v) ((v) & 0x7FFF0000)
#define IBDB_VRS_MIN(v) ((v) & 0x0000FF00)
#define IBDB_VRS_PL(v) ((v) & 0x000000FF)
#define IBDB_VRS_COMPAT(new, old) (((new) == (old)) || \
(IBDB_VRS_MAJ(new) == IBDB_VRS_MAJ(old) && \
IBDB_VRS_MIN(new) >= IBDB_VRS_MIN(old)))
#define IBDB_REC_SIZE 512 /* size of one record */
#define IBDB_MINBUF_SIZE 512 /* minimum size of file buffer */
#define IBDB_BUF_SIZE 8192 /* size of file buffer if none if provided */
/* for testing; currently not used anywhere */
#define IBDB_MAXSIZE (10 * 1024)
/* flags for IBDB status updates */
#define IBDB_FL_NONE 0x00U
#define IBDB_FL_NOROLL 0x01U /* no roll-over */
#define IBDB_FL_CLEAN 0x02U /* call cleanup */
#define IBDB_IS_FLAG(flags, fl) (((flags) & (fl)) != 0)
#define ibdb_is_noroll(fl) (((fl) & IBDB_FL_NOROLL) != 0)
/* flags for IBDB open() */
#define IBDB_OFL_WRITE 0x01U /* open write ("normal") IBDB */
#define IBDB_OFL_RCVR 0x02U /* open recovery IBDB */
#define IBDB_OFL_CLEAN 0x04U /* open cleanup IBDB */
#define IBDB_IS_OPEN_FLAG(flags, fl) (((flags) & (fl)) != 0)
typedef struct ibdb_ctx_S ibdb_ctx_T, *ibdb_ctx_P;
typedef struct ibdbr_ctx_S ibdbr_ctx_T, *ibdbr_ctx_P;
/* Define sender and recipient records */
/*
** XXX: Really use sessta_id_P (that is, just a pointer) here?
** It may be pointed elsewhere (to another string).
** It's ok for writing, but reading?
**
** How about omitting the struct completely and just call the functions
** with these parameters? The data is not used for anything else
** but storing data in a file. For reading back this is actually not
** the best since it mostly contains pointers instead of storage space.
*/
struct ibdb_ta_S
{
sessta_id_P ibt_ta_id;
sm_str_P ibt_mail_pa; /* printable version of MAIL address */
cdb_id_P ibt_cdb_id;
uint ibt_nrcpts; /* number of valid recipients */
/* The next entries are only used by recovery program */
uint ibt_rcpts_left; /* rcpts still to deliver */
uint ibt_rcpts_temp; /* rcpts temp failed */
uint ibt_rcpts_perm; /* rcpts perm failed */
sm_hdrmodhd_P ibt_hdrmodhd;
/*
** May need other data, e.g.,
** time: can be retrieved from timestamp on file (ctime?)
*/
};
struct ibdb_rcpt_S
{
sessta_id_P ibr_ta_id;
sm_str_P ibr_pa; /* printable version of RCPT address */
rcpt_idx_T ibr_idx; /* RCPT index */
};
typedef struct ibdb_ta_S ibdb_ta_T, *ibdb_ta_P;
typedef struct ibdb_rcpt_S ibdb_rcpt_T, *ibdb_rcpt_P;
struct ibdb_hdrmod_S
{
sessta_id_P ibh_ta_id;
sm_hm_type_T ibh_type; /* can this be mapped to an int? */
uint ibh_pos;
sm_cstr_P ibh_hdr;
};
typedef struct ibdb_hdrmod_S ibdb_hdrmod_T, *ibdb_hdrmod_P;
/*
** List of requests for group updates after getting delivery status
** which has been written to DEFEDB.
*/
/* Use enum? */
#define IBDB_REQ_TA 0x01
#define IBDB_REQ_RCPT 0x02
#define IBDB_REQ_HDRMOD 0x04
typedef struct ibdb_req_S ibdb_req_T, *ibdb_req_P;
/* this is a "merge" (union) of all IBDB structures */
struct ibdb_req_S
{
uint ibdb_req_type;
int ibdb_req_status;
sessta_id_T ibdb_req_ss_ta_id; /* SMTPS transaction id */
sm_str_P ibdb_req_addr_pa; /* MAIL/RCPT address */
cdb_id_P ibdb_req_cdb_id;
uint ibdb_req_nrcpts;
rcpt_idx_T ibdb_req_rcpt_idx; /* RCPT index */
/* note: this could be a union with cdb_id_P as it's the same type */
sm_cstr_P ibdb_req_hdr;
SIMPLEQ_ENTRY(ibdb_req_S) ibdb_req_link;
};
#define ibh_req_hdr ibdb_req_hdr
#define ibh_req_pos ibdb_req_nrcpts
#define ibh_req_type ibdb_req_status
typedef SIMPLEQ_HEAD(, ibdb_req_S) ibdb_req_hd_T, *ibdb_req_hd_P;
#define IBDBREQL_INIT(ibdb_req_hd) SIMPLEQ_INIT(ibdb_req_hd)
#define IBDBREQL_FIRST(ibdb_req_hd) SIMPLEQ_FIRST(ibdb_req_hd)
#define IBDBREQL_END(ibdb_req_hd) SIMPLEQ_END(ibdb_req_hd)
#define IBDBREQL_EMPTY(ibdb_req_hd) SIMPLEQ_EMPTY(ibdb_req_hd)
#define IBDBREQL_NEXT(ibdb_req) SIMPLEQ_NEXT(ibdb_req, ibdb_req_link)
#define IBDBREQL_PRE(ibdb_req_hd, ibdb_req) SIMPLEQ_INSERT_HEAD(ibdb_req_hd, ibdb_req, ibdb_req_link)
#define IBDBREQL_APP(ibdb_req_hd, ibdb_req) SIMPLEQ_INSERT_TAIL(ibdb_req_hd, ibdb_req, ibdb_req_link)
#define IBDBREQL_REMOVE(ibdb_req_hd) SIMPLEQ_REMOVE_HEAD(ibdb_req_hd, ibdb_req_link)
#define SM_IS_IBDBREQL(ibdb_req_hd) SM_ASSERT((ibdb_req_hd) != NULL)
/* Function prototypes */
sm_ret_T ibdb_open(const char *_base_dir, const char *_name, int _mode, uint32_t _seq, size_t _size, uint _flags, fs_ctx_P _fs_ctx, ibdb_ctx_P *_ibdb_handle);
sm_ret_T ibdb_ta_status(ibdb_ctx_P _ibdbc, ibdb_ta_P _ta, int _status, uint _flags, rcpt_idx_T _rcpt_idx_high, thr_lock_T _locktype);
sm_ret_T ibdb_rcpt_status(ibdb_ctx_P _ibdbc, ibdb_rcpt_P _rcpt, int _status, uint _flags, thr_lock_T _locktype);
sm_ret_T ibdb_commit(ibdb_ctx_P _ibdbc);
sm_ret_T ibdb_close(ibdb_ctx_P _ibdbc);
sm_ret_T ibdb_rcpt_app(ibdb_ctx_P _ibdb_ctx, ibdb_rcpt_P _ibdb_rcpt, ibdb_req_hd_P _ibdb_req_hd, int _status);
sm_ret_T ibdb_ta_app(ibdb_ctx_P _ibdb_ctx, ibdb_ta_P _ibdb_ta, ibdb_req_hd_P _ibdb_req_hd, int _status);
sm_ret_T ibdb_req_cancel(ibdb_ctx_P _ibdb_ctx, ibdb_req_hd_P _ibdb_req_hd);
sm_ret_T ibdb_wr_status(ibdb_ctx_P _ibdb_ctx, ibdb_req_hd_P _ibdb_req_hd);
sm_ret_T ibdb_hdrmod_wr(ibdb_ctx_P _ibdb_ctx, ibdb_hdrmod_P _ibdb_hdrmod, uint _flags, thr_lock_T _locktype);
sm_ret_T ibdb_hdrmod_app(ibdb_ctx_P _ibdb_ctx, ibdb_hdrmod_P _ibdb_hdrmod, ibdb_req_hd_P _ibdb_req_hd);
sm_ret_T ibdb_hdrmodl_wr(ibdb_ctx_P _ibdb_ctx, sm_hdrmodhd_P _sm_hdrmodhd, sessta_id_T _ta_id, uint _flags, thr_lock_T _locktype);
sm_ret_T ibdbr_get(ibdbr_ctx_P _ibdbr_ctx, ibdb_rcpt_P _rcpt, ibdb_ta_P _ta
, ibdb_hdrmod_P ibdb_hdrmod, int *_status);
sm_ret_T ibdbr_open(const char *_base_dir, const char *_name, int _mode, uint32_t _seq, size_t _size, uint _flags, ibdbr_ctx_P *_ibdbr_handle);
sm_ret_T ibdbr_close(ibdbr_ctx_P _ibdbr_ctx);
sm_ret_T ibdbr_rcpt_free(ibdb_rcpt_P _ibdb_rcpt);
sm_ret_T ibdbr_rcpt_new(ibdb_rcpt_P *_pibdb_rcpt);
sm_ret_T ibdbr_ta_free(ibdb_ta_P _ibdb_ta);
sm_ret_T ibdbr_ta_new(ibdb_ta_P *_pibdb_ta);
sm_ret_T ibdbr_hdrmod_free(ibdb_hdrmod_P _ibdb_hdrmod);
sm_ret_T ibdbr_hdrmod_new(ibdb_hdrmod_P *_pibdb_hdrmod);
sm_ret_T ibdbr_unlink(ibdbr_ctx_P _ibdbr_ctx, uint32_t _first, uint32_t _last);
sm_ret_T ibdbf_get_seq(const char *_base_dir, char *_name, uint _flags, uint32_t *_first, uint32_t *_last);
sm_ret_T ibdb_clean(ibdb_ctx_P _ibdb_ctx, thr_lock_T _locktype);
sm_ret_T ibdbc_show_seq(ibdb_ctx_P _ibdb_ctx, thr_lock_T _locktype, sm_file_T *_fp);
sm_ret_T ibdb_fs_getfree(ibdb_ctx_P _ibdb_ctx, ulong *_pkbfree);
sm_ret_T ibdb_stats(ibdb_ctx_P _ibdb_ctx, sm_file_T *_fp);
/* IBDB recovery */
#define SM_IBDB_NO_RCVR 1 /* no recovery necessary: no IBDB */
#define SM_IBDB_RCVR_EXISTS 2
/* more parameters? */
sm_ret_T ibdbrcvr_open(void);
sm_ret_T ibdbrcvr_close(void);
#endif /* SM_IDB_H */
syntax highlighted by Code2HTML, v. 0.9.1