/*
 * 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-rcpts-0.c,v 1.33 2006/11/09 01:53:49 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/heap.h"
#include "sm/test.h"
#include "sm/maps.h"
#include "sm/map.h"
#include "sm/mapclasses.h"
#include "sm/hostname.h"
#include "sm/bhtable.h"
#include "sm/io.h"
#include "sm/smardef.h"
#include "smar.h"
#include "t-init.h"
#define SMAR_LOG_DEFINES 1
#include "log.h"

/*
**  Test program for alias expansion.
**  This program is directly linked against the smar functions that
**  perform alias expansion, it does not communicate with an smar daemon.
**  This is done to allow for direct testing of one component instead
**  of the significantly more complicated part of communicating with
**  an smar daemon (which is done by other test programs).
*/

static int Verbose = 0;
int Loglevel = 0;
static bool List;
static bool ShowFlags = true;

#define TRS_FL_NORECERR	0x0001 /* ignore recursion error */

/*
**  PRINT_RCPT_CB -- Callback for bht_walk: print some smar_rcpt data.
**
**	Parameters:
**		entry -- bht entry
**		ctx -- ignored
**
**	Returns:
**		usual sm_error code
*/

/* ARGSUSED1 */
static sm_ret_T
print_rcpt_cb(bht_entry_P entry, void *ctx)
{
	smar_rcpt_P smar_rcpt;

	(void) ctx;
	SM_TEST(entry != NULL);
	if (entry == NULL)
		return -1;

	smar_rcpt = entry->bhe_value;
	SM_TEST(smar_rcpt != NULL);
	if (smar_rcpt == NULL)
		return -1;

	sm_io_fprintf(smioout, "address: %16S ", smar_rcpt->arr_pa);
	if (Verbose > 2)
	{
		sm_io_fprintf(smioout, "idx: %u, ", smar_rcpt->arr_idx);
		sm_io_fprintf(smioout, "owner: %u, ", smar_rcpt->arr_owner_idx);
	}
	if (ShowFlags)
		sm_io_fprintf(smioout, "flags: %x\n", smar_rcpt->arr_flags);
	else
		sm_io_fprintf(smioout, "\n");
	return SM_SUCCESS;
}

/*
**  PRINT_RCPT_L -- print some smar_rcpt data.
**
**	Parameters:
**		entry -- bht entry
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
print_rcpt_l(smar_rcpts_P smar_rcpts)
{
	smar_rcpt_P smar_rcpt;
	uint n;

	SM_TEST(smar_rcpts->arrs_lst_n <= smar_rcpts->arrs_ht_n);
	for (smar_rcpt = RCPTS_FIRST(smar_rcpts), n = 0;
	     smar_rcpt != RCPTS_END(smar_rcpts);
	     smar_rcpt = RCPTS_NEXT(smar_rcpt), ++n)
	{
		sm_io_fprintf(smioout, "address: %16S ",
			smar_rcpt->arr_pa);
		if (Verbose > 2)
		{
			sm_io_fprintf(smioout, "idx: %u, ",
				smar_rcpt->arr_idx);
			sm_io_fprintf(smioout, "owner: %u, ",
				smar_rcpt->arr_owner_idx);
		}
		if (ShowFlags)
			sm_io_fprintf(smioout, "flags: %x\n",
				smar_rcpt->arr_flags);
		else
			sm_io_fprintf(smioout, "\n");
	}
	SM_TEST(smar_rcpts->arrs_lst_n == n);
	return SM_SUCCESS;
}

/*
**  PRINT_OWNER_L -- print some smar_rcpt data.
**
**	Parameters:
**		entry -- bht entry
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
print_owner_l(smar_rcpts_P smar_rcpts)
{
	smar_rcpt_P smar_rcpt;
	uint n;

	if (Verbose > 2)
		sm_io_fprintf(smioout, "\nOwner-List:\n");
	for (smar_rcpt = OWNER_FIRST(smar_rcpts), n = 0;
	     smar_rcpt != OWNER_END(smar_rcpts);
	     smar_rcpt = OWNER_NEXT(smar_rcpt), ++n)
	{
#if 0
		sm_io_fprintf(smioout, "orig_pa: %16S ", smar_rcpt->arr_pa);
#endif
		sm_io_fprintf(smioout, "owner: %16S ", smar_rcpt->arr_owner_pa);
		if (Verbose > 2)
		{
			sm_io_fprintf(smioout, "idx: %u, ",
				smar_rcpt->arr_idx);
			sm_io_fprintf(smioout, "owner: %u, ",
				smar_rcpt->arr_owner_idx);
		}
		if (ShowFlags)
			sm_io_fprintf(smioout, "flags: %x\n",
				smar_rcpt->arr_flags);
		else
			sm_io_fprintf(smioout, "\n");
	}
	return SM_SUCCESS;
}


/*
**   T_RCPTS_0_INIT -- Initialize smar_ctx
**	See smar_init(), this is the part of it that is necessary for
**	looking up aliases.
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
t_rcpts_0_init(smar_ctx_P smar_ctx)
{
	return t_smar_0_init(smar_ctx, TSMARI_FL_MT|TSMARI_FL_ALIAS);
}

/*
**   T_RCPTS_0_FREE -- Free data in smar_ctx
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

static void
t_rcpts_0_free(smar_ctx_P smar_ctx)
{
	if (smar_ctx->smar_mt_map != NULL)
	{
		(void) sm_map_close(smar_ctx->smar_mt_map, 0);
		smar_ctx->smar_mt_map = NULL;
	}
	if (smar_ctx->smar_aliases != NULL)
	{
		(void) sm_map_close(smar_ctx->smar_aliases, 0);
		smar_ctx->smar_aliases = NULL;
	}
	if (smar_ctx->smar_maps != NULL)
	{
		(void) sm_maps_term(smar_ctx->smar_maps);
		smar_ctx->smar_maps = NULL;
	}
}

/*
**  T_RCPTS_0 -- Perform alias expansion
**
**	Parameters:
**		addr -- (printable) address to expand.
**
**	Returns:
**		none.
*/

static void
t_rcpts_0(char *addr, uint32_t cnflags, uint32_t rqflags, uint tflags, uint lflags, sm_str_P srch)
{
	sm_ret_T ret;
	sm_str_P str;
	smar_rcpts_P smar_rcpts;
	smar_rcpt_P smar_rcpt;
	smar_ctx_T smar_ctx;

	ret = t_rcpts_0_init(&smar_ctx);
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return;
	smar_ctx.smar_cnf.smar_cnf_alias_fl = cnflags;
	smar_ctx.smar_alias_lfl = SMMAP_LFL_ALIAS;
	ret = smar_init_map_lfl(&smar_ctx, smar_ctx.smar_cnf.smar_cnf_alias_fl,
				&smar_ctx.smar_alias_lfl);
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return;

	ret = smar_rcpt_new(&smar_rcpt);
	SM_TEST(ret == SM_SUCCESS);

	str = sm_str_new(NULL, MAXADDRLEN, MAXADDRLEN + 2);
	SM_TEST(str != NULL);
	if (str == NULL)
		return;
	ret = sm_str_scopy(str, addr);
	SM_TEST(ret == SM_SUCCESS);

	smar_rcpt->arr_pa = str;
	smar_rcpt->arr_timeout = 1;
	smar_rcpt->arr_rqflags = rqflags;
	sm_snprintf(smar_rcpt->arr_id, sizeof(smar_rcpt->arr_id),
		SMTP_RCPTID_FORMAT, "S00000000404763B601", (rcpt_idx_T)9876);

	ret = smar_rcpts_new(&smar_ctx, NULL, &smar_rcpts);
	SM_TEST(ret == SM_SUCCESS);
	smar_rcpts->arrs_flags = lflags;
	smar_rcpts->arrs_pa = srch;

	ret = smar_rcpt_expand(smar_rcpts, smar_rcpt, 0, 0, 0);
	SM_TEST(ret == SM_SUCCESS);

	if (ret == SM_SUCCESS)
	{
		if (SMARRS_IS_FLAG(smar_rcpts, SMARRS_FL_COMP))
		{
			if (Verbose > 1)
				sm_io_fprintf(smioout, "flags=%#x\n",
					smar_rcpts->arrs_flags);
			else
				sm_io_fprintf(smioout, "found=%d\n",
					SMARRS_IS_FLAG(smar_rcpts,
						SMARRS_FL_FOUND));
		}
		else if (List)
		{
			ret = smar_rcpts_t2l(smar_rcpts);
			SM_TEST(ret == SM_SUCCESS);
			ret = print_rcpt_l(smar_rcpts);
			SM_TEST(ret == SM_SUCCESS);
			ret = print_owner_l(smar_rcpts);
			SM_TEST(ret == SM_SUCCESS);
#if 0
			ret = smar_rcpt_free(smar_rcpt, NULL);
			SM_TEST(ret == SM_SUCCESS);
#endif
			smar_rcpt = NULL;
		}
		else
		{
			bht_walk(smar_rcpts->arrs_rcpts, print_rcpt_cb, NULL);
		}
		sm_io_flush(smioout);
	}
	else if (Verbose > 0)
		sm_io_fprintf(smioerr, "smar_rcpt_expand=%#X\n", ret);

	ret = smar_rcpts_free(smar_rcpts);
	SM_TEST(ret == SM_SUCCESS);

	t_rcpts_0_free(&smar_ctx);
}

/*
**  USAGE -- usage message
**
**	Parameters:
**		prg -- program name
**
**	Returns:
**		none
*/

static void
usage(const char *prg)
{
	sm_io_fprintf(smioerr, "usage: %s [options] addresses...\n"
		"-e       does address (-S) exist in list?\n"
		"-F       do not show flags\n"
		"-f flags set test flags\n"
		"-L       alias expansion for local addresses including domain\n"
		"-l       list\n"
		"-o       perform owner- expansion\n"
		"-r       alias expansion for all addresses\n"
		"-S addr  specify address (e.g., to find in list)\n"
		"-V       increase verbosity\n"
		, prg
		);
	return;
}

int
main(int argc, char *argv[])
{
	int c, i;
	uint32_t cnflags, rqflags;
	uint tflags, lflags;
	sm_str_P srch;

	List = false;
	rqflags = SMARRQ_FL_ALIAS;
	cnflags = SMARCNF_FL_MAP_LP;
	tflags = 0;
	lflags = 0;
	srch = NULL;
	while ((c = getopt(argc, argv, "d:eFf:LlorS:s:V")) != -1)
	{
		switch (c)
		{
		  case 'd':
#if SMAR_DEBUG
			smar_debug = (uint) strtoul(optarg, NULL, 0);
#endif
			break;
		  case 'e':
			lflags = SMARRS_FL_NOREC|SMARRS_FL_NOADD|SMARRS_FL_COMP;
			break;
		  case 'F':
			ShowFlags = false;
			break;
		  case 'f':
			tflags = (uint) strtoul(optarg, NULL, 0);
			break;
		  case 'l':
			List = true;
			break;
		  case 'L':
			cnflags = SMARCNF_FL_MAP_LD;
			break;
		  case 'o':
			rqflags |= SMARRQ_FL_OWNER;
			break;
		  case 'r':
			cnflags = SMARCNF_FL_MAP_ALL;
			break;
		  case 'S':
			srch = sm_str_scpy(NULL, optarg, 256);
			break;
		  case 's':
			lflags = (uint) strtoul(optarg, NULL, 0);
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			usage(argv[0]);
			return 1;
		}
	}

	sm_test_begin(argc, argv, "test rcpts 0");
	argc -= optind;
	argv += optind;
	if (argc > 0)
	{
		for (i = 0; i < argc; i++)
			t_rcpts_0(argv[i], cnflags, rqflags, tflags, lflags,
				srch);
	}
	else
		t_rcpts_0("<a@b.c>", cnflags, rqflags, tflags, lflags, srch);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1