/*
 * 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_IDSTR(id, "@(#)$Id: t-idb-1.c,v 1.31 2007/06/18 04:42:31 ca Exp $")

#include "sm/io.h"
#include "sm/mta.h"
#include "sm/cstr.h"
#include "sm/cdb.h"
#include "sm/ibdb.h"
#include "sm/qmgr.h"
#include "sm/memops.h"
#include "sm/test.h"
#include "sm/sysexits.h"

#define FNAME	"ibd"
#define IBDBSIZE	(8 * 1024)
#define INIT_SEQ	1
static int init_seq = INIT_SEQ;

static int debug = 0;

/*
**  ToDo:
**	- more consistency checks for read data.
**	- cleanup files.
*/

/*
**  TESTIDB -- write INCEDB records
**
**	Parameters:
**		base_dir -- name of base directory (can be NULL)
**		iter -- number of iterations (transactions)
**		maxs -- maximum size of an INCEDB file
**
**	Returns:
**		usual sm_error code.
*/

static int
testidb(const char *base_dir, int iter, int maxs)
{
	int i, j, nrcpts;
	sm_ret_T ret;
	ibdb_ctx_P ibdb_ctx;
	ibdb_ta_P ta;
	ibdb_rcpt_P rcpt;
	sessta_id_T id;
	sessta_id_T da_id;
	char cdb[32];
	id_count_T id_count;
	ibdb_req_hd_T ibdb_req_hd, ibdb_req_hd_c;

	id_count = time(NULLT);
	ret = ibdb_open(base_dir, FNAME, SM_IO_WRONLY, init_seq, maxs,
			IBDB_OFL_WRITE, NULLPTR, &ibdb_ctx);
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return ret;

	rcpt = NULL;
	ta = (ibdb_ta_P) sm_zalloc(sizeof(*ta));
	SM_TEST(ta != NULL);
	if (ta == NULL)
		goto end;
	ta->ibt_ta_id = id;
	ta->ibt_mail_pa = sm_str_new(NULL, 256, 256);
	SM_TEST(ta->ibt_mail_pa != NULL);
	if (ta->ibt_mail_pa == NULL)
		goto end;

	rcpt = (ibdb_rcpt_P) sm_zalloc(sizeof(*rcpt));
	SM_TEST(rcpt != NULL);
	if (rcpt == NULL)
		goto end;
	rcpt->ibr_ta_id = id;
	rcpt->ibr_pa = sm_str_new(NULL, 256, 256);
	SM_TEST(rcpt->ibr_pa != NULL);
	if (rcpt->ibr_pa == NULL)
		goto end;

	for (i = 0; i < iter; i++)
	{
		id_count++;
		IBDBREQL_INIT(&(ibdb_req_hd));
		sm_snprintf(id, SMTP_STID_SIZE, SMTPS_STID_FORMAT, id_count, 2);
		sm_str_clr(ta->ibt_mail_pa);
		ret = sm_strprintf(ta->ibt_mail_pa, "sender-%d@some.domain", i);
		ret = sm_snprintf(cdb, sizeof(cdb), "cdb%010d", i);
		ta->ibt_cdb_id = sm_cstr_scpyn((const uchar *) cdb, strlen(cdb));
		SM_TEST(ta->ibt_cdb_id != NULL);
		if (ta->ibt_cdb_id == NULL)
			goto end;
		nrcpts = ta->ibt_nrcpts = (i % 5) + 1;

		sm_snprintf(da_id, SMTP_STID_SIZE, SMTPC_STID_FORMAT,
				4, (uint) id_count, 3);
		for (j = 0; j < nrcpts; j++)
		{
			sm_str_clr(rcpt->ibr_pa);
			ret = sm_strprintf(rcpt->ibr_pa,
					"rcpt-%d-%d@other.Rcpt", i, j);
			rcpt->ibr_idx = (rcpt_idx_T) j;
			if (debug > 2)
			{
				sm_io_fprintf(smioout, "ADD RCPT: ");
				sm_io_fprintf(smioout, "ta_id=%s, ", rcpt->ibr_ta_id);
				sm_io_fprintf(smioout, "rcpt_pa=%s, ", sm_str_data(rcpt->ibr_pa));
				sm_io_fprintf(smioout, "rcpt_idx=%d, ", rcpt->ibr_idx);
				sm_io_fprintf(smioout, "\n");
				sm_io_flush(smioout);
			}

			ret = ibdb_rcpt_app(ibdb_ctx, rcpt, &ibdb_req_hd,
					IBDB_RCPT_NEW);
			SM_TEST(ret == SM_SUCCESS);
			if (ret != SM_SUCCESS)
				goto end;
		}
		ret = ibdb_ta_app(ibdb_ctx, ta, &ibdb_req_hd, IBDB_TA_NEW);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;

		ret = ibdb_wr_status(ibdb_ctx, &ibdb_req_hd);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;

		/* list to cancel */
		IBDBREQL_INIT(&(ibdb_req_hd_c));
		sm_str_clr(rcpt->ibr_pa);
		ret = sm_strprintf(rcpt->ibr_pa,
				"rcpt-%d-%d@Cancel.Rcpt", i, nrcpts);
		rcpt->ibr_idx = (rcpt_idx_T) nrcpts;
		ret = ibdb_rcpt_app(ibdb_ctx, rcpt, &ibdb_req_hd_c, IBDB_RCPT_NEW);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;
		sm_str_clr(ta->ibt_mail_pa);
		ret = sm_strprintf(ta->ibt_mail_pa, "sender-%d@cancel.domain", i);
		ret = ibdb_ta_app(ibdb_ctx, ta, &ibdb_req_hd_c, IBDB_TA_NEW);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;
		ret = ibdb_req_cancel(ibdb_ctx, &ibdb_req_hd_c);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;

		ret = ibdb_wr_status(ibdb_ctx, &ibdb_req_hd_c);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			goto end;

		for (j = 0; j < nrcpts; j++)
		{
			sm_str_clr(rcpt->ibr_pa);
			ret = sm_strprintf(rcpt->ibr_pa,
					"rcpt-%d-%d@other.Rcpt", i, j);
			rcpt->ibr_idx = (rcpt_idx_T) j;
			if (debug > 2)
			{
				sm_io_fprintf(smioout, "REM RCPT: ");
				sm_io_fprintf(smioout, "ta_id=%s, ", rcpt->ibr_ta_id);
				sm_io_fprintf(smioout, "rcpt_pa=%s, ", sm_str_data(rcpt->ibr_pa));
				sm_io_fprintf(smioout, "rcpt_idx=%d, ", rcpt->ibr_idx);
				sm_io_fprintf(smioout, "\n");
				sm_io_flush(smioout);
			}

			ret = ibdb_rcpt_status(ibdb_ctx, rcpt, IBDB_RCPT_DONE,
					IBDB_FL_NOROLL, THR_LOCK_UNLOCK);
			SM_TEST(ret == SM_SUCCESS);
			if (ret != SM_SUCCESS)
				goto end;
		}

		sm_str_clr(ta->ibt_mail_pa);
		ret = sm_strprintf(ta->ibt_mail_pa, "sender-%d@some.domain", i);
		ret = ibdb_ta_status(ibdb_ctx, ta, IBDB_TA_DONE, IBDB_FL_NONE,
				0, THR_LOCK_UNLOCK);
		SM_TEST(ret == SM_SUCCESS);
		if (ret != SM_SUCCESS)
			break;
		sm_cstr_free(ta->ibt_cdb_id);
	}

  end:
	if (ta != NULL)
	{
		SM_STR_FREE(ta->ibt_mail_pa);
		sm_free(ta);
	}
	if (rcpt != NULL)
	{
		SM_STR_FREE(rcpt->ibr_pa);
		sm_free(rcpt);
	}
	ret = ibdb_close(ibdb_ctx);
	SM_TEST(ret == SM_SUCCESS);
	sm_io_flush(smioout);
	return ret;
}

/*
**  TESTIDBR -- read INCEDB records
**
**	Parameters:
**		base_dir -- name of base directory (can be NULL)
**		iter -- number of iterations (transactions)
**		maxs -- maximum size of an INCEDB file
**
**	Returns:
**		usual sm_error code.
*/

static sm_ret_T
testidbr(const char *base_dir, int iter, int maxs)
{
	int i, j, nrcpts, status;
	ibdbr_ctx_P ibdbrc;
	ibdb_ta_P ta;
	ibdb_rcpt_P rcpt;
	ibdb_hdrmod_P ibdb_hdrmod;
	sessta_id_T id;
	id_count_T id_count;
	sm_str_P str;
	sm_ret_T ret;

	ret = ibdbr_open(base_dir, FNAME, SM_IO_RDONLY, init_seq, maxs,
			IBDB_OFL_WRITE, &ibdbrc);
	if (sm_is_err(ret) && sm_error_value(ret) == ENOENT)
		return SM_SUCCESS;
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return ret;

	str = NULL;
	rcpt = NULL;
	ta = (ibdb_ta_P) sm_zalloc(sizeof(*ta));
	SM_TEST(ta != NULL);
	if (ta == NULL)
		goto end;
	ta->ibt_ta_id = id;
	ta->ibt_mail_pa = sm_str_new(NULL, 256, 256);
	SM_TEST(ta->ibt_mail_pa != NULL);
	if (ta->ibt_mail_pa == NULL)
		goto end;
	ibdb_hdrmod = (ibdb_hdrmod_P) sm_zalloc(sizeof(*ibdb_hdrmod));
	SM_TEST(ibdb_hdrmod != NULL);
	if (ibdb_hdrmod == NULL)
		goto end;

	rcpt = (ibdb_rcpt_P) sm_zalloc(sizeof(*rcpt));
	SM_TEST(rcpt != NULL);
	if (rcpt == NULL)
		goto end;
	rcpt->ibr_ta_id = id;
	rcpt->ibr_pa = sm_str_new(NULL, 256, 256);
	SM_TEST(rcpt->ibr_pa != NULL);
	if (rcpt->ibr_pa == NULL)
		goto end;

	str = sm_str_new(NULL, 256, 256);
	SM_TEST(str != NULL);
	if (str == NULL)
		goto end;

	id_count = 0;
	for (i = 0; i < iter; i++)
	{
		id_count++;

		nrcpts = (i % 5) + 1;
		for (j = 0; j < nrcpts; j++)
		{
			sm_str_clr(str);
			ret = sm_strprintf(str,
					"rcpt-%d-%d@other.Rcpt", i, j);

			ret = ibdbr_get(ibdbrc, rcpt, ta, ibdb_hdrmod, &status);
			SM_TEST(ret == RT_IBDB_RCPT);
			if (sm_is_err(ret))
				goto end;
			SM_TEST(sm_memeq(sm_str_getdata(str),
				sm_str_getdata(rcpt->ibr_pa),
				sm_str_getlen(rcpt->ibr_pa)));
			SM_TEST(rcpt->ibr_idx == (rcpt_idx_T) j);
		}

		ret = ibdbr_get(ibdbrc, rcpt, ta, ibdb_hdrmod, &status);
		SM_TEST(ret == RT_IBDB_TA);
		if (sm_is_err(ret) || ret != RT_IBDB_TA)
			break;
		SM_CSTR_FREE(ta->ibt_cdb_id);

		for (j = 0; j < nrcpts; j++)
		{
			sm_str_clr(str);
			ret = sm_strprintf(str,
					"rcpt-%d-%d@other.Rcpt", i, j);

			ret = ibdbr_get(ibdbrc, rcpt, ta, ibdb_hdrmod
					, &status);
			SM_TEST(ret == RT_IBDB_RCPT);
			if (sm_is_err(ret))
				goto end;
			SM_TEST(sm_memeq(sm_str_getdata(str),
				sm_str_getdata(rcpt->ibr_pa),
				sm_str_getlen(rcpt->ibr_pa)));
		}

		ret = ibdbr_get(ibdbrc, rcpt, ta, ibdb_hdrmod, &status);
		SM_TEST(ret == RT_IBDB_TA);
		if (sm_is_err(ret) || ret != RT_IBDB_TA)
			break;
		SM_CSTR_FREE(ta->ibt_cdb_id);
	}

  end:
	if (ta != NULL)
	{
		SM_STR_FREE(ta->ibt_mail_pa);
		sm_free(ta);
	}
	if (rcpt != NULL)
	{
		SM_STR_FREE(rcpt->ibr_pa);
		sm_free(rcpt);
	}
	SM_STR_FREE(str);
	ret = ibdbr_close(ibdbrc);
	SM_TEST(ret == SM_SUCCESS);
	return ret;
}

int
main(int argc, char *argv[])
{
	int iter, c, maxs;
	sm_ret_T ret;
	bool readonly;
	char *base_dir;

	base_dir = NULL;
	iter = 100;
	maxs = IBDBSIZE;
	readonly = false;
	while ((c = getopt(argc, argv, "b:d:i:m:Hr")) != -1)
	{
		switch (c)
		{
		  case 'b':
			base_dir = strdup(optarg);
			if (NULL == base_dir)
				return EX_OSERR;
			break;
		  case 'd':
			debug = strtol(optarg, NULL, 0);
			break;
#if SM_HEAP_CHECK
		  case 'H':
			SmHeapCheck = atoi(optarg);
			break;
#endif /* SM_HEAP_CHECK */
		  case 'i':
			iter = strtol(optarg, NULL, 0);
			break;
		  case 'm':
			maxs = strtol(optarg, NULL, 0);
			break;
		  case 'r':
			readonly = true;
			break;
#if 0
		  default:
			usage(argv[0]);
			return(1);
#endif /* 0 */
		}
	}

	sm_test_begin(argc, argv, "test idb-1");
	if (readonly)
		ret = SM_SUCCESS;
	else
		ret = testidb(base_dir, iter, maxs);
	if (ret == SM_SUCCESS)
		ret = testidbr(base_dir, iter, maxs);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1