/* * 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. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: t-edb-0.c,v 1.52 2007/06/18 04:42:31 ca Exp $") #include "sm/assert.h" #include "sm/magic.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/test.h" #include "sm/mta.h" #include "sm/hdrmod.h" #include "sm/edb.h" #include "sm/edbcnf.h" #include "sm/actdb-int.h" #define QMGR_DEBUG_DEFINE 1 #include "sm/qmgrdbg.h" /* ** Write some DEFEDB entries and read them back to check whether it worked. */ /* Options for test */ #define OPT_NO_DEL 0x01 #define OPT_HDRMOD_P 0x02 #define OPT_HDRMOD_A 0x04 #define OPT_HDRMOD_R 0x08 static uint opts; #define SMT_HDR_PRE_1 "Header1: Prepend 1\r\n" #define SMT_HDR_APP_1 "Header2: Append 2\r\n\tline 2\r\n line3\r\n" static sm_ret_T cmp_aq_rcpt(aq_rcpt_P aq_rcpt, aq_rcpt_P aq_rcpt_rd) { SM_TEST(sm_memeq(aq_rcpt->aqr_ss_ta_id, aq_rcpt_rd->aqr_ss_ta_id, SMTP_STID_SIZE)); SM_TEST(sm_memeq(sm_str_data(aq_rcpt->aqr_pa), sm_str_data(aq_rcpt_rd->aqr_pa), sm_str_getlen(aq_rcpt->aqr_pa))); if (aq_rcpt->aqr_msg != NULL && aq_rcpt_rd->aqr_msg != NULL) { SM_TEST(sm_memeq(sm_str_data(aq_rcpt->aqr_msg), sm_str_data(aq_rcpt_rd->aqr_msg), sm_str_getlen(aq_rcpt->aqr_msg))); } SM_TEST(aq_rcpt->aqr_addrs[0].aqra_ipv4 == aq_rcpt_rd->aqr_addrs[0].aqra_ipv4); SM_TEST(aq_rcpt->aqr_da_idx == aq_rcpt_rd->aqr_da_idx); SM_TEST(aq_rcpt->aqr_st_time == aq_rcpt_rd->aqr_st_time); SM_TEST(aq_rcpt->aqr_idx == aq_rcpt_rd->aqr_idx); SM_TEST(aq_rcpt->aqr_status == aq_rcpt_rd->aqr_status); SM_TEST(aq_rcpt->aqr_tries == aq_rcpt_rd->aqr_tries); SM_TEST(aq_rcpt->aqr_next_try == aq_rcpt_rd->aqr_next_try); SM_TEST(aq_rcpt->aqr_last_try == aq_rcpt_rd->aqr_last_try); return SM_SUCCESS; } static sm_ret_T chg_rcpt(aq_rcpt_P aq_rcpt, int ta, int pid, int index) { sessta_id_T ta_id; sm_str_P str; sm_ret_T ret; char buf[MAXADDRLEN]; /* lots of stuff just to get a valid aq_rcpt entry... */ ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); SESSTA_COPY(aq_rcpt->aqr_ss_ta_id, ta_id); sm_snprintf(buf, sizeof(buf), "", index); str = sm_str_scpy0(NULL, buf, sizeof(buf)); if (aq_rcpt->aqr_pa != NULL) sm_str_free(aq_rcpt->aqr_pa); aq_rcpt->aqr_pa = str; sm_snprintf(buf, sizeof(buf), "451 Just some text %d", index); str = sm_str_scpy0(NULL, buf, sizeof(buf)); if (aq_rcpt->aqr_msg != NULL) sm_str_free(aq_rcpt->aqr_msg); aq_rcpt->aqr_msg = str; /* would require htonl, but not really needed here */ aq_rcpt->aqr_addrs[0].aqra_ipv4 = 0x7f000001; aq_rcpt->aqr_addrs[0].aqra_expt = 0x7fffffff; aq_rcpt->aqr_addrs[0].aqra_pref = 1; aq_rcpt->aqr_addr_max = 1; aq_rcpt->aqr_da_idx = 0; aq_rcpt->aqr_st_time = 123456; aq_rcpt->aqr_idx = index; aq_rcpt->aqr_status = AQR_ST_NEW; aq_rcpt->aqr_tries = 3; aq_rcpt->aqr_last_try = 123567; aq_rcpt->aqr_next_try = 123789; return ret; } static sm_ret_T chg_req_rcpt(edb_req_P edb_req, int ta, int pid, int index) { sessta_id_T ta_id; sm_ret_T ret; ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); sm_snprintf(edb_req->edb_req_id, sizeof(edb_req->edb_req_id), SMTP_RCPTID_FORMAT, ta_id, index); edb_req->edb_req_type = EDB_REQ_RCPT; return ret; } static aq_rcpt_P new_rcpt(void) { aq_rcpt_P aq_rcpt; aq_rcpt = (aq_rcpt_P) sm_zalloc(sizeof(*aq_rcpt)); SM_TEST(aq_rcpt != NULL); if (aq_rcpt == NULL) return NULL; aq_rcpt->aqr_addrs = (aq_raddr_P) sm_malloc(sizeof(*(aq_rcpt->aqr_addrs))); if (aq_rcpt->aqr_addrs == NULL) return NULL; #if AQ_RCPT_CHECK aq_rcpt->sm_magic = SM_AQ_RCPT_MAGIC; #endif return aq_rcpt; } static sm_ret_T chg_req_ta(edb_req_P edb_req, int ta, int pid) { sm_ret_T ret; ret = SM_SUCCESS; sm_snprintf(edb_req->edb_req_id, sizeof(edb_req->edb_req_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); edb_req->edb_req_type = EDB_REQ_TA; return ret; } static sm_ret_T cmp_aq_ta(aq_ta_P aq_ta, aq_ta_P aq_ta_rd) { sm_hdrmod_P sm_hdrmod; SM_TEST(sm_memeq(sm_str_data(aq_ta->aqt_mail->aqm_pa), sm_str_data(aq_ta_rd->aqt_mail->aqm_pa), sm_str_getlen(aq_ta->aqt_mail->aqm_pa))); #if 0 SM_TEST(aq_rcpt->aqr_status == aq_rcpt_rd->aqr_status); #endif sm_hdrmod = NULL; if (SM_IS_FLAG(opts, OPT_HDRMOD_P)) { sm_hdrmod = HDRMODL_FIRST(aq_ta->aqt_hdrmodhd); SM_TEST_E(!HDRMODL_EMPTY(aq_ta->aqt_hdrmodhd)); SM_TEST_E(sm_hdrmod != NULL); SM_TEST_E(SM_HM_TYPE_PREPEND == sm_hdrmod->sm_hm_type); SM_TEST_E(sm_hdrmod->sm_hm_hdr != NULL); SM_TEST_E(strcmp((const char *) sm_cstr_data(sm_hdrmod->sm_hm_hdr), SMT_HDR_PRE_1) == 0); } if (SM_IS_FLAG(opts, OPT_HDRMOD_R)) { if (sm_hdrmod != NULL) sm_hdrmod = HDRMODL_NEXT(sm_hdrmod); else sm_hdrmod = HDRMODL_FIRST(aq_ta->aqt_hdrmodhd); SM_TEST_E(sm_hdrmod != NULL); SM_TEST_E(SM_HM_TYPE_REMOVE == sm_hdrmod->sm_hm_type); SM_TEST_E(2 == sm_hdrmod->sm_hm_pos); SM_TEST_E(NULL == sm_hdrmod->sm_hm_hdr); } if (SM_IS_FLAG(opts, OPT_HDRMOD_A)) { if (sm_hdrmod != NULL) sm_hdrmod = HDRMODL_NEXT(sm_hdrmod); else sm_hdrmod = HDRMODL_FIRST(aq_ta->aqt_hdrmodhd); SM_TEST_E(sm_hdrmod != NULL); SM_TEST_E(SM_HM_TYPE_APPEND == sm_hdrmod->sm_hm_type); SM_TEST_E(sm_hdrmod->sm_hm_hdr != NULL); SM_TEST_E(strcmp((const char *) sm_cstr_data(sm_hdrmod->sm_hm_hdr), SMT_HDR_APP_1) == 0); } return SM_SUCCESS; error: return -1; } static sm_ret_T chg_ta(aq_ta_P aq_ta, int ta, int pid, int index) { sessta_id_T ta_id; sm_str_P str; sm_ret_T ret; char mail_pa[MAXADDRLEN]; /* lots of stuff just to get a valid aq_ta entry... */ ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); SESSTA_COPY(aq_ta->aqt_ss_ta_id, ta_id); sm_snprintf(mail_pa, sizeof(mail_pa), "", index); str = sm_str_scpy0(NULL, mail_pa, sizeof(mail_pa)); aq_ta->aqt_mail->aqm_pa = str; aq_ta->aqt_st_time = 123457; aq_ta->aqt_rcpts_tot = 4; /* total number recipients */ aq_ta->aqt_rcpts_left = 4; /* rcpts still to deliver */ aq_ta->aqt_rcpts_temp = 1; aq_ta->aqt_rcpts_perm = 0; aq_ta->aqt_rcpts_ar = 4; aq_ta->aqt_state = 400; aq_ta->aqt_cdb_id = sm_cstr_scpyn((const uchar *) ta_id, SMTP_STID_SIZE); SM_TEST(aq_ta->aqt_cdb_id != NULL); return ret; } static aq_ta_P new_ta(void) { aq_ta_P aq_ta; aq_ta = (aq_ta_P) sm_zalloc(sizeof(*aq_ta)); SM_TEST(aq_ta != NULL); if (aq_ta == NULL) return NULL; aq_ta->aqt_mail = (aq_mail_P) sm_malloc(sizeof(*(aq_ta->aqt_mail))); SM_TEST(aq_ta->aqt_mail != NULL); if (aq_ta->aqt_mail == NULL) return NULL; #if AQ_TA_CHECK aq_ta->sm_magic = SM_AQ_TA_MAGIC; #endif return aq_ta; } static void free_rcpt(aq_rcpt_P aq_rcpt) { if (aq_rcpt == NULL) return; if (aq_rcpt->aqr_pa != NULL) SM_STR_FREE(aq_rcpt->aqr_pa); sm_free(aq_rcpt); } static void free_ta(aq_ta_P aq_ta) { if (aq_ta == NULL) return; if (aq_ta->aqt_mail != NULL) { SM_STR_FREE(aq_ta->aqt_mail->aqm_pa); SM_FREE(aq_ta->aqt_mail); } SM_CSTR_FREE(aq_ta->aqt_cdb_id); sm_free(aq_ta); } static void edb0(void) { sm_ret_T ret; int i; edb_ctx_P edb_ctx; aq_ctx_P aq_ctx; aq_ctx_T aq_ctx_s; aq_rcpt_P aq_rcpt; aq_rcpt_P aq_rcpt_rd; aq_ta_P aq_ta; aq_ta_P aq_ta_rd; smtp_status_T rcpt_st; edb_req_P edb_req; sm_hdrmod_P sm_hdrmod; char *str; edb_ctx = NULL; aq_ctx = &aq_ctx_s; edb_req = NULL; aq_ta = NULL; aq_ta_rd = NULL; aq_rcpt = NULL; aq_rcpt_rd = NULL; sm_hdrmod = NULL; ret = edb_open(NULL, NULL, NULL, &edb_ctx); SM_TEST_ERR(ret); ret = aq_open(NULL, &aq_ctx, 256, 0); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; aq_rcpt = new_rcpt(); SM_TEST(aq_rcpt != NULL); if (aq_rcpt == NULL) goto error; aq_rcpt_rd = new_rcpt(); SM_TEST(aq_rcpt_rd != NULL); if (aq_rcpt_rd == NULL) goto error; aq_ta = new_ta(); SM_TEST(aq_ta != NULL); if (aq_ta == NULL) goto error; aq_ta_rd = new_ta(); SM_TEST(aq_ta_rd != NULL); if (aq_ta_rd == NULL) goto error; if (SM_IS_FLAG(opts, OPT_HDRMOD_P)) { ret = sm_hdrmod_new(&aq_ta->aqt_hdrmodhd, true, &sm_hdrmod); SM_TEST_ERR(ret); SM_TEST_E(sm_hdrmod != NULL); str = SMT_HDR_PRE_1; sm_hdrmod->sm_hm_hdr = sm_cstr_scpyn0((const uchar *)str, strlen(str)); SM_TEST(sm_hdrmod->sm_hm_hdr != NULL); sm_hdrmod->sm_hm_type = SM_HM_TYPE_PREPEND; } if (SM_IS_FLAG(opts, OPT_HDRMOD_R)) { ret = sm_hdrmod_new(&aq_ta->aqt_hdrmodhd, true, &sm_hdrmod); SM_TEST_ERR(ret); SM_TEST_E(sm_hdrmod != NULL); sm_hdrmod->sm_hm_type = SM_HM_TYPE_REMOVE; sm_hdrmod->sm_hm_pos = 2; } if (SM_IS_FLAG(opts, OPT_HDRMOD_A)) { ret = sm_hdrmod_new(&aq_ta->aqt_hdrmodhd, true, &sm_hdrmod); SM_TEST_ERR(ret); SM_TEST_E(sm_hdrmod != NULL); str = SMT_HDR_APP_1; sm_hdrmod->sm_hm_hdr = sm_cstr_scpyn0((const uchar *)str, strlen(str)); SM_TEST(sm_hdrmod->sm_hm_hdr != NULL); sm_hdrmod->sm_hm_type = SM_HM_TYPE_APPEND; } /* no entries */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); ret = chg_ta(aq_ta, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_ta_app(edb_ctx, aq_ta, NULL, 450); SM_TEST(ret == SM_SUCCESS); ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; ret = chg_rcpt(aq_rcpt, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); rcpt_st = 451; ret = edb_rcpt_app(edb_ctx, aq_rcpt, NULL, rcpt_st); SM_TEST(ret == SM_SUCCESS); ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; /* add some recipient data */ for (i = 0; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); rcpt_st = 452 + i; ret = edb_rcpt_app(edb_ctx, aq_rcpt, NULL, rcpt_st); SM_TEST(ret == SM_SUCCESS); } /* write it out */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; ret = edb_req_new(edb_ctx, EDB_RQF_NONE, &edb_req, false); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; /* read ta data back and compare */ ret = chg_req_ta(edb_req, 0, 1); SM_TEST(ret == SM_SUCCESS); ret = chg_ta(aq_ta, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_ta_dec(edb_req, aq_ta_rd); SM_TEST(ret == SM_SUCCESS); aq_ta->aqt_state = 400; ret = cmp_aq_ta(aq_ta, aq_ta_rd); SM_TEST(ret == SM_SUCCESS); /* read rcpt data back and compare */ ret = chg_req_rcpt(edb_req, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = chg_rcpt(aq_rcpt, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_dec(edb_req, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); aq_rcpt->aqr_status = 451; ret = cmp_aq_rcpt(aq_rcpt, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); /* read rcpt data back and compare */ for (i = 0; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); aq_rcpt->aqr_status = 452 + i; ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_dec(edb_req, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); ret = cmp_aq_rcpt(aq_rcpt, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); SM_STR_FREE(aq_rcpt->aqr_pa); } if (SM_IS_FLAG(opts, OPT_NO_DEL)) goto done; /* Delete rcpts: directly */ for (i = 0; i < 2; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_rm(edb_ctx, edb_req->edb_req_id); SM_TEST(ret == SM_SUCCESS); } /* Delete rcpts: add requests */ for (i = 2; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_rm_req(edb_ctx, edb_req->edb_req_id, NULL); SM_TEST(ret == SM_SUCCESS); } /* Delete rcpts: commit requests */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); done: free_rcpt(aq_rcpt); free_rcpt(aq_rcpt_rd); free_ta(aq_ta); free_ta(aq_ta_rd); ret = edb_req_rel(edb_ctx, edb_req, 0, THR_NO_LOCK); SM_TEST(ret == SM_SUCCESS); ret = aq_close(aq_ctx); SM_TEST(ret == SM_SUCCESS); ret = edb_close(edb_ctx); SM_TEST(ret == SM_SUCCESS); return; error: /* always close db */ ret = edb_close(edb_ctx); SM_TEST(ret == SM_SUCCESS); return; } static sm_ret_T usage(const char *prg) { fprintf(stderr, "usage: %s [options]\n" "-d: do not delete entries\n" , prg); return 1; } int main(int argc, char *argv[]) { int c; opts = 0; while ((c = getopt(argc, argv, "adpr")) != -1) { switch (c) { case 'a': opts |= OPT_HDRMOD_A; break; case 'd': opts |= OPT_NO_DEL; break; case 'p': opts |= OPT_HDRMOD_P; break; case 'r': opts |= OPT_HDRMOD_R; break; default: usage(argv[0]); return 1; } } /* just in case... (e.g., an older version ran before) */ (void) unlink(EDB_HOME "/log.0000000001"); (void) unlink(EDB_NAME_RD); sm_test_begin(argc, argv, "test edb 0"); /* Ignore result, directory may already exist */ (void) mkdir(EDB_HOME, 0700); edb0(); return sm_test_end(); }