/*
 * Copyright (c) 2004-2006 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: smconf.c,v 1.31 2007/06/10 16:14:42 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/qmgrcomm.h"

#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"

#define SM_QMGRCNFDEF 1
#define SM_SCCNFDEF 1
#define SM_SMARCNFDEF 1
#define SM_MAPCNFDEF 1
#define SM_SSCNFDEF 1
#define SM_CONF_TIME_DEF 1
#define SM_CONF_LOG_DEF 1
#define SM_CONF_BYTE_DEF 1
#define SM_CONF_KBYTE_DEF 1
#define SM_GREYCNFDEF 1

#include "sm/qmgrcnf.h"
#include "sm/sccnf.h"
#include "sm/mapcnf.h"
#include "sm/smarcnf.h"
#include "sm/sscnf.h"
#include "sm/greycnf.h"

#include "sm/qmgrcnfdef.h"
#include "sm/sccnfdef.h"
#include "sm/mapcnfdef.h"
#include "sm/greycnfdef.h"
#include "sm/smarcnfdef.h"
#include "sm/sscnfdef.h"

static int Verbose = 0;
static bool Quiet = false;

typedef struct sm_cnf_S		sm_cnf_T, *sm_cnf_P;
struct sm_cnf_S
{
	char		*smc_smtpcsock;
	char		*smc_smtpssock;
	char		*smc_smarsock;
	char		*smc_cdb_base;
	char		*smc_hostname;
	qmgr_cnf_T	 smc_qmgr_cnf;
	sc_cnf_T	 smc_sc_cnf;
	smar_cnf_T	 smc_smar_cnf;
	ss_cnf_T	 smc_ss_cnf;
};

sm_conf_definition_T
smx_defs[] =
{

{ SM_CONF_DEF_MAGIC, "SMTPC_socket",	sm_conf_type_string,
	offsetof(sm_cnf_T, smc_smtpcsock),
	0,	smsmtpcsock,
	0, NULL, NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "SMTPS_socket",	sm_conf_type_string,
	offsetof(sm_cnf_T, smc_smtpssock),
	0,	smsmtpssock,
	0, NULL, NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "SMAR_socket",	sm_conf_type_string,
	offsetof(sm_cnf_T, smc_smarsock),
	0,	smarsock,
	0, NULL, NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "CDB_base_directory",	sm_conf_type_string,
	offsetof(sm_cnf_T, smc_cdb_base),
	0,	"",
	0, NULL, NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "hostname",		sm_conf_type_string,
	offsetof(sm_cnf_T, smc_hostname),	0,	NULL,
	0, NULL, NULL, NULL, NULL },

{ SM_CONF_DEF_MAGIC, "smar", sm_conf_type_section,
	offsetof(sm_cnf_T, smc_smar_cnf),
	0, /* sizeof(smar_cnf_T), */
	NULL, SM_CONF_FLAG_KEEP_DEFAULT, smar_defs,
	NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "smtpc", sm_conf_type_section,
	offsetof(sm_cnf_T, smc_sc_cnf),
	0, /* sizeof(sc_cnf_T), */
	NULL, SM_CONF_FLAG_KEEP_DEFAULT|SM_CONF_FLAG_MULTIPLE, sc_defs,
	NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "smtps", sm_conf_type_section,
	offsetof(sm_cnf_T, smc_ss_cnf),
	0, /* sizeof(ss_cnf_T), */
	NULL, SM_CONF_FLAG_KEEP_DEFAULT|SM_CONF_FLAG_MULTIPLE, ss_defs,
	NULL, NULL, NULL },
{ SM_CONF_DEF_MAGIC, "qmgr", sm_conf_type_section,
	offsetof(sm_cnf_T, smc_qmgr_cnf),
	0, /* sizeof(qmgr_cnf_T), */
	NULL, SM_CONF_FLAG_KEEP_DEFAULT, qmgr_defs,
	NULL, NULL, NULL },

/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL },
};

#define SM_SHOWTREE	0x01
#define SM_SHOWALL	0x02
#define SM_ALLOW_ANY_SECTION	0x04


/*
**  SM_READCONF -- Read configuration file
**
**	Parameters:
**		fn -- filename of configuration file
**		flags -- show tree/all?
**		name -- name of subsection (can be NULL)
**
**	Returns:
**		0 on success, everything else is an error
*/

static sm_ret_T
sm_readconf(const char *fn, uint flags, const char *name)
{
	int err;
	uint pflags;
	sm_conf_T *smc;
	FILE *fp;
	sm_cnf_T sm_cnf;
	sm_conf_node_T *root, *node;

	fp = NULL;
	sm_memzero(&sm_cnf, sizeof(sm_cnf));
	sm_cnf.smc_qmgr_cnf.sm_magic = SM_QMGR_CNF_MAGIC;
	sm_cnf.smc_sc_cnf.sm_magic = SM_SC_CNF_MAGIC;
	sm_cnf.smc_smar_cnf.sm_magic = SM_SMAR_CNF_MAGIC;
	sm_cnf.smc_ss_cnf.sm_magic = SM_SS_CNF_MAGIC;
	smc = sm_conf_new(fn);
	if (smc == NULL)
	{
		err = errno;

		sm_io_fprintf(smioerr,
			"sev=ERROR, func=sm_readconf, file=%s, sm_conf_new=NULL, errno=%d\n",
			fn, err);
		return ENOMEM;
	}
	err = sm_conf_read_FILE(smc, fn, fp);
	if (err != 0)
	{
		sm_prt_conferr(fn, smc, err, smioerr);
		sm_conf_destroy(smc);
		smc = NULL;
		return err;
	}

	pflags = SM_CONF_FLAG_KEEP_DEFAULT;
	if (SM_IS_FLAG(flags, SM_ALLOW_ANY_SECTION))
		pflags |= SM_CONF_FLAG_ALLOW_ANY_SECTION;
	err = sm_conf_scan(smc, smx_defs, pflags, &sm_cnf);
	if (err != 0)
	{
		sm_prt_conferr(fn, smc, err, smioerr);
		return err;
	}
	else if (Quiet)
		/* do nothing */ ;
	else if (SM_IS_FLAG(flags, SM_SHOWTREE))
	{
		root = sm_conf_root(smc);
		if (root != NULL)
		{
			node = root;
			if (name != NULL)
			{
				node = sm_conf_section_next_subsection(smc,
						root, name, strlen(name),
						NULL, 0, NULL);
			}
			if (node != NULL)
			{
				sm_conf_dump_root(smc, node, smioout);
				sm_io_flush(smioout);
			}
		}

	}
	else
	{
		if (!SM_IS_FLAG(flags, SM_SHOWALL))
			sm_io_fprintf(smioout, "QMGR {\n");
		qmgr_prt_cnf(&(sm_cnf.smc_qmgr_cnf), smioout,
			SM_IS_FLAG(flags, SM_SHOWALL));
		if (!SM_IS_FLAG(flags, SM_SHOWALL))
			sm_io_fprintf(smioout, "}\nSMTPS {\n");
		ss_prt_cnf(&(sm_cnf.smc_ss_cnf), smioout,
			SM_IS_FLAG(flags, SM_SHOWALL));
		if (!SM_IS_FLAG(flags, SM_SHOWALL))
			sm_io_fprintf(smioout, "}\nSMTPC {\n");
		sc_prt_cnf(&(sm_cnf.smc_sc_cnf), smioout,
			SM_IS_FLAG(flags, SM_SHOWALL));
		if (!SM_IS_FLAG(flags, SM_SHOWALL))
			sm_io_fprintf(smioout, "}\nSMAR {\n");
		smar_prt_cnf(&(sm_cnf.smc_smar_cnf), smioout,
			SM_IS_FLAG(flags, SM_SHOWALL));
		if (!SM_IS_FLAG(flags, SM_SHOWALL))
			sm_io_fprintf(smioout, "}\n");
		sm_io_flush(smioout);
	}

	return SM_SUCCESS;
}

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

static void
usage(const char *prg)
{
	sm_io_fprintf(smioerr, "%s: usage: %s [options] configuration-file\n"
		"options:\n"
		"-a       show complete configuration data after parsing\n"
		"-q       quiet: do not show configuration file, just perform checks\n"
		"-s name  look for section name\n"
		"-t       show parsed tree\n"
		"-u       do not complain about unknown sections\n"
		, prg, prg);
}

/*
**  SHOWCOPT -- show compile time options
**
**	Parameters:
**		none
**
**	Returns:
**		none
*/

static void
showcopt(void)
{
	sm_io_fprintf(smioout, "compile time options:\n"
#if MTA_USE_TLS
			"MTA_USE_TLS\n"
#endif
#if MTA_USE_SASL
			"MTA_USE_SASL\n"
#endif
#if MTA_USE_PMILTER
			"MTA_USE_PMILTER\n"
#endif
#if QMGR_TEST
			"QMGR_TEST\n"
#endif
		);
	sm_io_flush(smioout);
}


int
main(int argc, char **argv)
{
	int ret, ai, r;
	uint flags;
	char *name, *prg;

	prg = argv[0];
	ret = 0;	/* make compiler happy */
	flags = 0;
	name = NULL;

	while ((r = getopt(argc, argv, "aqs:tuV")) != -1)
	{
		switch (r)
		{
		  case 'a':
			flags |= SM_SHOWALL;
			break;
		  case 'q':
			Quiet = true;
			break;
		  case 's':
			name = optarg;
			break;
		  case 't':
			flags |= SM_SHOWTREE;
			break;
		  case 'u':
			flags |= SM_ALLOW_ANY_SECTION;
			break;
		  case 'V':
			Verbose++;
			break;
		  default:
			usage(prg);
			return 1;
		}
	}

	argc -= optind;
	argv += optind;

	if (Verbose == 3)
	{
		showcopt();
		return 0;
	}

	for (ai = 0; ai < argc; ai++)
	{
		ret = sm_readconf(argv[ai], flags, name);
		if (ret != 0)
			break;
	}
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1