/*
 * Copyright (c) 2004, 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-edbi-0.c,v 1.10 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/edb.h"
#include "sm/edbcnf.h"
#include "sm/actdb-int.h"
#define QMGR_DEBUG_DEFINE 1
#include "sm/qmgrdbg.h"
#include "edb-int.h"

/*
**  Write some DEFEDB entries and read them back to check whether it worked.
**  Interactive to perform some other operations.
**  This is mostly a program to play around and see what happens, it
**  does not run as a test program.
*/

#define RCPT_MAX_LEN	256

/* Options for test; use bitmap? */
#define OPT_NO_DEL	1
#define OPT_INTER	0

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[RCPT_MAX_LEN];

	/* 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), "<a-%d@b.c>", index);
	str = sm_str_scpy0(NULL, buf, RCPT_MAX_LEN);
	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, RCPT_MAX_LEN);
	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 /* AQ_TA_CHECK */
	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_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 /* 0 */
	return SM_SUCCESS;
}

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[RCPT_MAX_LEN];

	/* 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), "<x-%d@y.z>", index);
	str = sm_str_scpy0(NULL, mail_pa, RCPT_MAX_LEN);
	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 /* AQ_TA_CHECK */
	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
edbi0(int opts)
{
	sm_ret_T ret;
	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;
	int i;

	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;
	ret = edb_open(NULL, NULL, NULL, &edb_ctx);
	SM_TEST(ret == SM_SUCCESS);
	if (sm_is_err(ret))
		return;
	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;

	/* 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 (opts == OPT_NO_DEL)
		goto done;

	if (opts == OPT_INTER)
	{
		bool stop;
		int c;

		stop = false;
		while ((c = getchar()) != EOF && !stop)
		{
			switch (c)
			{
			  case 'c':
				ret = edb_ctx->edb_bdbenv->txn_checkpoint(
						edb_ctx->edb_bdbenv,
/*
  kbyte
	If the kbyte parameter is non-zero, a checkpoint will be done
	if more than kbyte kilobytes of log data have been written
	since the last checkpoint.
   min
	If the min parameter is non-zero, a checkpoint will be done if
	more than min minutes have passed since the last checkpoint.
*/
					/* u_int32_t kbyte, u_int32_t min */
						0, 0, 0);
				if (ret != 0)
					edb_ctx->edb_bdbenv->err(
						edb_ctx->edb_bdbenv, ret,
						"checkpoint");
				break;
			  case 's':
				stop = true;
				break;
			  default:
				break;
			}
		}
	}

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

int
main(int argc, char *argv[])
{
	int opts, c;

	opts = 0;
	while ((c = getopt(argc, argv, "d")) != -1)
	{
		switch (c)
		{
		  case 'd':
			opts = OPT_NO_DEL;
			break;
		  default:
/*
			usage(argv[0]);
*/
			return 1;
		}
	}

	sm_test_begin(argc, argv, "test edb 0");

	/* Ignore result, directory may already exist */
	(void) mkdir(EDB_HOME, 0700);
	edbi0(opts);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1