/*
 * 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-conf-0.c,v 1.14 2005/07/11 02:42:02 ca Exp $")

#include "sm/error.h"
#include "sm/sysexits.h"
#include "sm/memops.h"
#include "sm/string.h"
#include "sm/net.h"
#include "sm/maps.h"
#include "sm/mapc.h"
#include "sm/map.h"
#include "sm/mapconf.h"
#include "map.h"
#include "sm/sm-conf.h"
#include <stdio.h>

#include "sm/mapcnf.h"
#define SM_MAPCNFDEF 1
#include "sm/mapcnfdef.h"

/*
**  test program: maps and libconf.
*/


static sm_ret_T
mapsetup(map_decl_P mapdef, sm_maps_P *pmaps)
{
	sm_ret_T	ret;

	SM_REQUIRE(mapdef != NULL);
	SM_REQUIRE(pmaps != NULL);
	*pmaps = NULL;
	ret = sm_maps_init(pmaps);
	if (*pmaps == NULL)
		return -1;
	if (sm_is_err(ret))
		goto error;
	ret = sm_maps_create(*pmaps);
	if (sm_is_err(ret))
		goto error;

	ret = sm_mapconfopen(mapdef, *pmaps, NULL);
	return ret;

  error:
	return ret;
}

static sm_ret_T
maplookup(FILE *fp, sm_maps_P maps, const char *mapname, const char *lookup, sm_str_P detail, uchar delim, uint32_t flags)
{
	sm_ret_T ret;
	sm_map_P map;
	sm_cstr_P mname;
	sm_str_P lhs, rhs;
	char *s;

	SM_REQUIRE(fp != NULL);
	SM_REQUIRE(maps != NULL);
	SM_REQUIRE(mapname != NULL);
	SM_REQUIRE(lookup != NULL);

	lhs = rhs = NULL;
	map = NULL;
	mname = sm_cstr_scpyn0((const uchar *)mapname, strlen(mapname));
	if (mname == NULL)
		goto error;
	ret = sm_mapname_find(maps, mname, &map);
	if (ret != SM_SUCCESS)
		goto error;
	if (map == NULL)
		goto error;
	lhs = sm_str_new(NULL, 256, 1024);
	if (lhs == NULL)
		goto error;
	rhs = sm_str_new(NULL, 256, 1024);
	if (rhs == NULL)
		goto error;

	/* perform some operations ... */
	sm_str_clr(rhs);
	sm_str_clr(lhs);
	ret = sm_str_scat(lhs, lookup);
	if (sm_is_err(ret))
		goto error;
	if (detail != NULL)
		ret = sm_map_lookup_addr(map, lhs, detail, NULL, NULL, delim,
					flags, rhs);
	else
		ret = sm_map_lookup(map, SMMAP_FL_NONE, lhs, rhs);
	if (sm_is_err(ret))
	{
		if (ret == sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND))
			fprintf(fp, "notfound\n");
		goto error;
	}
	s = (char *) sm_str_getdata(rhs);
	if (s != NULL)
		fprintf(fp, "result=\"%s\"\n", s);

	return ret;

  error:
	return -1;
}

static int
mapprtcnf(FILE *fp, map_decl_P mapdef)
{
	mapspec_P	md_maps;
	uint	n, i;

	if (mapdef == NULL)
	{
		fprintf(fp, "map == NULL\n");
		return -1;
	}
	for (n = 0; n < mapdef->mapdecl_n; n++)
	{
		md_maps = mapdef->mapdecl_maps + n;
		if (md_maps == NULL)
		{
			fprintf(fp, "mapdef[%d] == NULL\n", n);
			continue;
		}
#if 0
		fprintf(fp, "map = %p\n", md_maps);
#endif
		fprintf(fp, "map = %u\n", n);
		fprintf(fp, "kind= %d\n", md_maps->mst_kind);
		fprintf(fp, "type= %s\n", md_maps->mst_type);
		fprintf(fp, "name= %s\n", md_maps->mst_name);
		switch (md_maps->mst_kind)
		{
		  case MST_HASH:
			fprintf(fp, "file= %s\n",
				md_maps->mst_hash.mst_hash_fn);
			break;
		  case MST_SOCKET:
			fprintf(fp, "mapname= %s\n",
				md_maps->mst_socket.mst_socket_mapname);
			if (md_maps->mst_socket.mst_socket_path != NULL)
			{
				fprintf(fp, "path= %s\n",
					md_maps->mst_socket.mst_socket_path);
			}
			else
			{
				fprintf(fp, "ipv4= %x\n",
					(int) htonl(md_maps->mst_socket.mst_socket_ipv4));
				fprintf(fp, "port= %d\n",
					md_maps->mst_socket.mst_socket_port);
			}
			break;
		  case MST_SEQUENCE:
			for (i = 0; md_maps->mst_seq.mst_seq_maps[i] != NULL; i++)
			{
				fprintf(fp, "maps[%u]= %s\n", i,
					md_maps->mst_seq.mst_seq_maps[i]);
			}
			break;
		  default:
			break;
		}
		fprintf(fp, "\n");
	}
	return 0;
}

static int
process(char const *name, FILE *fp, int show, const char *mapname, const char *lookup, sm_str_P detail, uchar delim, uint32_t flags)
{
	sm_conf_T		*stream;
	int			err;
	sm_ret_T ret;
#if 0
	char const *service_name;
	size_t service_name_n;
	sm_conf_iterator_T service_iter;
#endif /* 0 */
	char const *e = NULL;
	sm_maps_P maps;
	map_decl_T s;
	char buf[SM_CONF_ERROR_BUFFER_SIZE];

	if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL)
	{
		fprintf(stderr, "error -- sm_conf_new() returns NULL!\n");
		return 1;
	}
	if ((err = sm_conf_read_FILE(stream, name, fp)) != 0)
	{
		fprintf(stderr, "%s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\n", e);

		sm_conf_destroy(stream);
		return 2;
	}

	sm_memzero(&s, sizeof(s));
	if ((err = sm_conf_scan(stream, maps_spec_defs, 0, &s)) != 0)
	{

		fprintf(stderr, "(while scanning) %s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\n", e);

		sm_conf_destroy(stream);
		return 3;
	}

	if (lookup == NULL || mapname == NULL)
		mapprtcnf(stdout, &s);
	else
	{
		maps = NULL;
		ret = mapsetup(&s, &maps);
		if (sm_is_err(ret))
			goto error;
		if (maps == NULL)
			goto error;
		ret = maplookup(stdout, maps, mapname, lookup, detail, delim,
				flags);
		if (sm_is_err(ret))
			goto error;
	}

#if 0
	sm_conf_destroy(stream);
#endif /* 0 */

	return 0;

  error:
	return -1;
}

static void
usage(char *prg)
{
	fprintf(stderr,
		"%s: usage: %s [options] configfile\n"
		"options:\n"
		" -l key     lookup key\n"
		" -m map     lookup key in map\n"
		"Note: -l and -m must be used together\n"
		"Default: only parse and print configfile\n"
		, prg, prg
		);
}


int
main(int argc, char **argv)
{
	int ai, c, ret;
	uchar delim;
	uint32_t flags;
	char *lookup, *mapname;
	sm_str_P detail;

	lookup = mapname = NULL;
	detail = NULL;
	delim = '+';
	flags = 0;
	while ((c = getopt(argc, argv, "?D:d:F:f:hl:m:")) != -1)
	{
		switch (c)
		{
		  case 'D':
			detail = sm_str_scpy0(NULL, optarg, 64);
			break;
		  case 'd':
			delim = (uchar) optarg[0];
			break;
		  case 'F':
			flags = strtoul(optarg, NULL, 0);
			break;
		  case 'f':
			ret = process(optarg, NULL, 0, mapname, lookup,
				detail, delim, flags);
			if (ret != 0)
				return ret;
			break;
		  case 'l':
			lookup = strdup(optarg);
			if (lookup == NULL)
				return EX_OSERR;
			break;
		  case 'm':
			mapname = strdup(optarg);
			if (mapname == NULL)
				return EX_OSERR;
			break;
		  case '?':
		  case 'h':
		  default:
			usage(argv[0]);
			exit(EX_USAGE);
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0)
		return process("*stdin*", stdin, 1, mapname, lookup,
				detail, delim, flags);

	for (ai = 0; ai < argc; ai++)
	{
		int ret;

		ret = process(argv[ai], NULL, 1, mapname, lookup,
				detail, delim, flags);
		if (ret != 0)
			return ret;
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1