/* * 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 */