/* conf.c:	set up configuration information and static data */

#include "copyright.h"
#include "mudconf.h"
#include "db.h"
#include "flags.h"
#include "externs.h"
#include "interface.h"
#include "command.h"
#include "htab.h"

#include <string.h>
#include <stdio.h>
#include <ctype.h>

/* ---------------------------------------------------------------------------
 * CONFPARM: Data used to find fields in CONFDATA.
 */

typedef struct confparm CONF;
struct confparm {
	char	*pname;			/* parm name */
	int	(*interpreter)();	/* routine to interp parameter */
	int	flags;			/* control flags */
	int	*loc;			/* where to store value */
	int	extra;			/* extra data for interpreter */
};

/* ---------------------------------------------------------------------------
 * External symbols.
 */

CONFDATA mudconf;
STATEDATA mudstate;

#ifndef STANDALONE
extern NAMETAB logdata_nametab[];
extern NAMETAB logoptions_nametab[];
extern NAMETAB access_nametab[];
extern NAMETAB attraccess_nametab[];
extern NAMETAB list_names[];
extern CONF conftable[];
#endif

/* ---------------------------------------------------------------------------
 * cf_init: Initialize mudconf to default values.
 */

void cf_init()
{
#ifndef STANDALONE
    strcpy(mudconf.indb, "tinymush.db");
    strcpy(mudconf.outdb, "");
    strcpy(mudconf.crashdb, "");
    strcpy(mudconf.gdbm, "");
    mudconf.gdbm_cache_size = 1024;	/* 1 megabyte */
    mudconf.compress_db = 0;
    strcpy(mudconf.compress, "/usr/ucb/compress");
    strcpy(mudconf.uncompress, "/usr/ucb/uncompress");
    strcpy(mudconf.status_file, "shutdown.status");
    mudconf.port = 6250;
    mudconf.init_size = 1000;
    mudconf.guest_char = -1;
    strcpy(mudconf.guest_file, "guest.txt");
    strcpy(mudconf.conn_file, "connect.txt");
    strcpy(mudconf.creg_file, "register.txt");
    strcpy(mudconf.regf_file, "create_reg.txt");
    strcpy(mudconf.motd_file, "motd.txt");
    strcpy(mudconf.wizmotd_file, "wizmotd.txt");
    strcpy(mudconf.quit_file, "quit.txt");
    strcpy(mudconf.down_file, "down.txt");
    strcpy(mudconf.full_file, "full.txt");
    strcpy(mudconf.site_file, "badsite.txt");
    strcpy(mudconf.crea_file, "newuser.txt");
    strcpy(mudconf.help_file, "help.txt");
    strcpy(mudconf.help_indx, "help.indx");
    strcpy(mudconf.news_file, "news.txt");
    strcpy(mudconf.news_indx, "news.indx");
    strcpy(mudconf.whelp_file, "wizhelp.txt");
    strcpy(mudconf.whelp_indx, "wizhelp.indx");
    strcpy(mudconf.motd_msg, "");
    strcpy(mudconf.wizmotd_msg, "");
    strcpy(mudconf.downmotd_msg, "");
    strcpy(mudconf.fullmotd_msg, "");
    strcpy(mudconf.dump_msg, "");
    mudconf.fork_dump = 1;
    mudconf.fork_vfork = 0;
    mudconf.max_players = -1;
    mudconf.garbage_chunk = 3;
    mudconf.dump_interval = 3600;
    mudconf.check_interval = 600;
    mudconf.dump_offset = 0;
    mudconf.check_offset = 300;
    mudconf.idle_timeout = 3600;
    mudconf.conn_timeout = 120;
    mudconf.idle_interval = 60;
    mudconf.retry_limit = 3;
    mudconf.output_limit = 16384;
    mudconf.paycheck = 0;
    mudconf.paystart = 0;
    mudconf.paylimit = 10000;
    mudconf.start_quota = 20;
    mudconf.payfind = 0;
    mudconf.digcost = 10;
    mudconf.linkcost = 1;
    mudconf.opencost = 1;
    mudconf.createmin = 10;
    mudconf.createmax = 505;
    mudconf.killmin = 10;
    mudconf.killmax = 100;
    mudconf.killguarantee = 100;
    mudconf.robotcost = 1000;
    mudconf.pagecost = 10;
    mudconf.searchcost = 100;
    mudconf.waitcost = 10;
    mudconf.machinecost = 64;
    mudconf.exit_quota = 1;
    mudconf.player_quota = 1;
    mudconf.room_quota = 1;
    mudconf.thing_quota = 1;
    mudconf.queuemax = 100;
    mudconf.queue_chunk = 3;
    mudconf.active_q_chunk = 0;
    mudconf.sacfactor = 5;
    mudconf.sacadjust = -1;
    mudconf.use_hostname = 1;
    mudconf.recycle = 1;
    mudconf.quotas = 0;
    mudconf.ex_flags = 1;
    mudconf.sac_dest = 0;
    mudconf.robot_speak = 1;
    mudconf.clone_copy_cost = 0;
    mudconf.pub_flags = 1;
    mudconf.quiet_look = 1;
    mudconf.exam_public = 1;
    mudconf.read_rem_desc = 0;
    mudconf.read_rem_name = 0;
    mudconf.sweep_dark = 0;
    mudconf.player_listen = 0;
    mudconf.quiet_whisper = 1;
    mudconf.dark_sleepers = 1;
    mudconf.see_own_dark = 1;
    mudconf.idle_wiz_dark = 0;
    mudconf.pemit_players = 0;
    mudconf.pemit_any = 0;
    mudconf.match_mine = 0;
    mudconf.match_mine_pl = 0;
    mudconf.switch_df_all = 1;
    mudconf.whereis_notify = 1;
    /* -- ??? Running SC on a non-SC DB may cause problems */
    mudconf.space_compress = 1;
    mudconf.intern_comp = 0;
    mudconf.start_room = 0;
    mudconf.start_home = -1;
    mudconf.default_home = -1;
    mudconf.master_room = -1;
    mudconf.player_flags = 0;
    mudconf.room_flags = 0;
    mudconf.exit_flags = 0;
    mudconf.thing_flags = 0;
    mudconf.robot_flags = PLAYER_ROBOT;
    mudconf.vattr_flags = AF_ODARK;
    mudconf.abort_on_bug = 0;
    mudconf.rwho_transmit = 0;
    strcpy(mudconf.mud_name, "TinyMUSH");
    strcpy(mudconf.rwho_host, "18.70.0.216");	/* milo.mit.edu */
    strcpy(mudconf.rwho_pass, "get_your_own");
    mudconf.rwho_info_port = 6888;
    mudconf.rwho_data_port = 0;
    mudconf.rwho_interval = 241;
    strcpy(mudconf.one_coin, "penny");
    strcpy(mudconf.many_coins, "pennies");
    mudconf.timeslice = 1000;
    mudconf.cmd_quota_max = 100;
    mudconf.cmd_quota_incr = 1;
    mudconf.control_flags = 0xffffffff;  /* Everything for now... */
    mudconf.log_options = LOG_ALWAYS | LOG_BUGS | LOG_SECURITY |
			  LOG_NET | LOG_LOGIN | LOG_DBSAVES | LOG_CONFIGMODS |
			  LOG_SHOUTS | LOG_STARTUP | LOG_WIZARD |
			  LOG_PROBLEMS | LOG_PCREATES;
    mudconf.log_info = LOGOPT_TIMESTAMP | LOGOPT_LOC;
    mudconf.markdata[0] = 0x01;
    mudconf.markdata[1] = 0x02;
    mudconf.markdata[2] = 0x04;
    mudconf.markdata[3] = 0x08;
    mudconf.markdata[4] = 0x10;
    mudconf.markdata[5] = 0x20;
    mudconf.markdata[6] = 0x40;
    mudconf.markdata[7] = 0x80;
    mudconf.func_nest_lim = 50;
    mudconf.func_invk_lim = 2500;
    mudconf.ntfy_nest_lim = 20;
    mudconf.lock_nest_lim = 20;
    mudconf.parent_nest_lim = 10;

    mudstate.initializing = 0;
    mudstate.panicking = 0;
    mudstate.logging = 0;
    mudstate.epoch = 0;
    mudstate.generation = 0;
    mudstate.curr_player = NOTHING;
    mudstate.curr_enactor = NOTHING;
    mudstate.shutdown_flag = 0;
    mudstate.rwho_on = 0;
    mudstate.user_attrs = NULL;
    mudstate.user_attr_free = NULL;
    mudstate.attr_next = A_USER_START;
    mudstate.debug_cmd = (char *)"< init >";
    strcpy(mudstate.doing_hdr, "Doing");
    mudstate.access_list = NULL;
    mudstate.suspect_list = NULL;
    mudstate.qfirst = NULL;
    mudstate.qlast = NULL;
    mudstate.qlfirst = NULL;
    mudstate.qllast = NULL;
    mudstate.qwait = NULL;
    mudstate.qsemfirst = NULL;
    mudstate.qsemlast = NULL;
    mudstate.badname_head = NULL;
    mudstate.mstat_ixrss[0] = 0;
    mudstate.mstat_ixrss[1] = 0;
    mudstate.mstat_idrss[0] = 0;
    mudstate.mstat_idrss[1] = 0;
    mudstate.mstat_isrss[0] = 0;
    mudstate.mstat_isrss[1] = 0;
    mudstate.mstat_secs[0] = 0;
    mudstate.mstat_secs[1] = 0;
    mudstate.mstat_curr = 0;
    mudstate.iter_alist.data = NULL;
    mudstate.iter_alist.len = 0;
    mudstate.iter_alist.next = NULL;
    mudstate.mod_alist = NULL;
    mudstate.mod_size = 0;
    mudstate.mod_al_id = NOTHING;
    mudstate.olist_head = NULL;
    mudstate.olist_tail = NULL;
    mudstate.olist_cblock = NULL;
    mudstate.olist_count = 0;
    mudstate.olist_citm = 0;
    mudstate.min_size = 0;
    mudstate.db_top = 0;
    mudstate.db_size = 0;
    mudstate.freelist = NOTHING;
    mudstate.markbits = NULL;
    mudstate.func_nest_lev = 0;
    mudstate.func_invk_ctr = 0;
    mudstate.ntfy_nest_lev = 0;
    mudstate.lock_nest_lev = 0;
#else
    mudconf.paylimit = 10000;
    mudconf.digcost = 10;
    mudconf.opencost = 1;
    mudconf.robotcost = 1000;
    mudconf.createmin = 5;
    mudconf.createmax = 505;
    mudconf.sacfactor = 5;
    mudconf.sacadjust = -1;
    mudconf.room_quota = 1;
    mudconf.exit_quota = 1;
    mudconf.thing_quota = 1;
    mudconf.player_quota = 1;
    mudconf.quotas = 0;
    mudconf.start_room = 0;
    mudconf.start_home = -1;
    mudconf.default_home = -1;
    mudconf.vattr_flags = AF_ODARK;
    mudconf.log_options = 0xffffffff;
    mudconf.log_info = 0;
    mudconf.markdata[0] = 0x01;
    mudconf.markdata[1] = 0x02;
    mudconf.markdata[2] = 0x04;
    mudconf.markdata[3] = 0x08;
    mudconf.markdata[4] = 0x10;
    mudconf.markdata[5] = 0x20;
    mudconf.markdata[6] = 0x40;
    mudconf.markdata[7] = 0x80;

    mudstate.logging = 0;
    mudstate.user_attrs = NULL;
    mudstate.user_attr_free = NULL;
    mudstate.attr_next = A_USER_START;
    mudstate.iter_alist.data = NULL;
    mudstate.iter_alist.len = 0;
    mudstate.iter_alist.next = NULL;
    mudstate.mod_alist = NULL;
    mudstate.mod_size = 0;
    mudstate.mod_al_id = NOTHING;
    mudstate.min_size = 0;
    mudstate.db_top = 0;
    mudstate.db_size = 0;
    mudstate.freelist = NOTHING;
    mudstate.markbits = NULL;
#endif	/* STANDALONE */
}

#ifndef STANDALONE

/* ---------------------------------------------------------------------------
 * cf_log_notfound: Log a 'parameter not found' error.
 */

void cf_log_notfound (dbref player, char *cmd, const char *thingname,
	char *thing)
{
char	*buff;

	if (mudstate.initializing) {
		STARTLOG(LOG_STARTUP,"CNF","NFND")
			buff = alloc_lbuf("cf_log_notfound.LOG");
			sprintf(buff,"%s: %s %s not found",
				cmd, thingname, thing);
			log_text(buff);
			free_lbuf(buff);
		ENDLOG
	} else {
		buff = alloc_lbuf("cf_log_notfound");
		sprintf(buff,"%s %s not found", thingname, thing);
		notify(player, buff);
		free_lbuf(buff);
	}
}

/* ---------------------------------------------------------------------------
 * cf_log_syntax: Log a syntax error.
 */

void cf_log_syntax (dbref player, char *cmd, const char *template, char *arg)
{
char	*buff;

	if (mudstate.initializing) {
		STARTLOG(LOG_STARTUP,"CNF","SYNTX")
			buff = alloc_lbuf("cf_log_syntax.LOG");
			sprintf(buff, template, arg);
			log_text(cmd);
			log_text((char *)": ");
			log_text(buff);
			free_lbuf(buff);
		ENDLOG
	} else {
		buff = alloc_lbuf("cf_log_syntax");
		sprintf(buff, template, arg);
		notify(player, buff);
		free_lbuf(buff);
	}
}

/* ---------------------------------------------------------------------------
 * cf_status_from_succfail: Return command status from succ and fail info
 */

int cf_status_from_succfail (dbref player, char *cmd, int success,
	int failure)
{
char	*buff;

	/* If any successes, return SUCCESS(0) if no failures or
	   PARTIAL_SUCCESS(1) if any failures. */

	if (success > 0) return ((failure == 0) ? 0 : 1);

	/* No successes.  If no failures indicate nothing done.
	   Always return FAILURE(-1) */

	if (failure == 0) {
		if (mudstate.initializing) {
			STARTLOG(LOG_STARTUP,"CNF","NDATA")
				buff = alloc_lbuf("cf_status_from_succfail.LOG");
				sprintf(buff,"%s: Nothing to set", cmd);
				log_text(buff);
				free_lbuf(buff);
			ENDLOG
		} else {
			notify(player, "Nothing to set");
		}
	}
	return -1;
}

/* ---------------------------------------------------------------------------
 * cf_int: Set integer parameter.
 */

int cf_int(int *vp, char *str, int extra, dbref player, char *cmd)
{
    /* Copy the numeric value to the parameter */

    sscanf(str, "%d", vp);
    return 0;
}

/* ---------------------------------------------------------------------------
 * cf_bool: Set boolean parameter.
 */

NAMETAB bool_names[] = {
{(char *)"true",	1,	0,	1},
{(char *)"false",	1,	0,	0},
{(char *)"yes",		1,	0,	1},
{(char *)"no",		1,	0,	0},
{(char *)"1",		1,	0,	1},
{(char *)"0",		1,	0,	0},
{NULL,			0,	0,	0}};

int cf_bool(int *vp, char *str, int extra, dbref player, char *cmd)
{
	*vp = search_nametab(GOD, bool_names, str);
	if (*vp == -1) *vp = 0;
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_string: Set string parameter.
 */

int cf_string(int *vp, char *str, int extra, dbref player, char *cmd)
{
int	retval;
char	*buff;

	/* Copy the string to the buffer if it is not too big */

	retval = 0;
	if (strlen(str) >= extra) {
		str[extra - 1] = '\0';
		if (mudstate.initializing) {
			STARTLOG(LOG_STARTUP,"CNF","NFND")
				buff = alloc_lbuf("cf_string.LOG");
				sprintf(buff,"%s: String truncated", cmd);
				log_text(buff);
				free_lbuf(buff);
			ENDLOG
		} else {
			notify(player, "String truncated");
		}
		retval = 1;
	}
	strcpy((char *)vp, str);
	return retval;
}

/* ---------------------------------------------------------------------------
 * cf_alias: define a generic hash table alias.
 */

int cf_alias(int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*alias, *orig;
int	*cp;

	alias = strtok(str, " \t=,");
	orig = strtok(NULL, " \t=,");
	cp = hashfind(orig, (HASHTAB *)vp);
	if (cp == NULL) {
		cf_log_notfound(player, cmd, "Entry", orig);
		return -1;
	}
	hashadd(alias, cp, (HASHTAB *)vp);
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_flagalias: define a flag alias.
 */

int cf_flagalias(int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*alias, *orig;
int	*cp, i, success;
HASHTAB	*hp;

	success = 0;
	alias = strtok(str, " \t=,");
	orig = strtok(NULL, " \t=,");

	for (i=0; i<=7; i++) {
		hp = object_types[i].flaghtab;
		if (hp != NULL) {
			cp = hashfind(orig, hp);
			if (cp != NULL) {
				hashadd(alias, cp, hp);
				success++;
			}
		}
	}
	if (!success)
		cf_log_notfound(player, cmd, "Flag", orig);
	return ((success > 0) ? 0 : -1);
}

/* ---------------------------------------------------------------------------
 * cf_or_in_bits: OR in bits from namelist to a word.
 */

int cf_or_in_bits(int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*sp;
int	f, success, failure;

	/* Walk through the tokens */

	success = failure = 0;
	sp = strtok(str, " \t");
	while (sp != NULL) {

		/* Set the appropriate bit */

		f = search_nametab(GOD, (NAMETAB *)extra, sp);
		if (f != -1) {
			*vp |= f;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/* Get the next token */

		sp = strtok(NULL, " \t");
	}
	return cf_status_from_succfail(player, cmd, success, failure);
}

/* ---------------------------------------------------------------------------
 * cf_modify_bits: set or clear bits in a flag word from a namelist.
 */
int cf_modify_bits(int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*sp;
int	f, negate, success, failure;

	/* Walk through the tokens */

	success = failure = 0;
	sp = strtok(str, " \t");
	while (sp != NULL) {

		/* Check for negation */

		negate = 0;
		if (*sp == '!') {
			negate = 1;
			sp++;
		}

		/* Set or clear the appropriate bit */

		f = search_nametab(GOD, (NAMETAB *)extra, sp);
		if (f != -1) {
			if (negate)
				*vp &= ~f;
			else
				*vp |= f;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/* Get the next token */

		sp = strtok(NULL, " \t");
	}
	return cf_status_from_succfail(player, cmd, success, failure);
}

/* ---------------------------------------------------------------------------
 * cf_set_bits: Clear flag word and then set specified bits from namelist.
 */

int cf_set_bits(int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*sp;
int	f, success, failure;

	/* Walk through the tokens */

	success = failure = 0;
	*vp = 0;
	sp = strtok(str, " \t");
	while (sp != NULL) {

		/* Set the appropriate bit */

		f = search_nametab(GOD, (NAMETAB *)extra, sp);
		if (f != -1) {
			*vp |= f;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/* Get the next token */

		sp = strtok(NULL, " \t");
	}
	return cf_status_from_succfail(player, cmd, success, failure);
}

/* ---------------------------------------------------------------------------
 * cf_set_flags: Clear flag word and then set from a flags htab.
 */

int cf_set_flags (int *vp, char *str, int extra, dbref player, char *cmd)
{
char	*sp;
FLAGENT	*fp;
int	success, failure;

	/* Walk through the tokens */

	success = failure = 0;
	sp = strtok(str, " \t");
	while (sp != NULL) {

		/* Set the appropriate bit */

		fp = (FLAGENT *)hashfind(sp, (HASHTAB *)extra);
		if (fp != NULL) {
			if (success == 0) *vp = 0;
			*vp |= fp->flagvalue;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/* Get the next token */

		sp = strtok(NULL, " \t");
	}
	if ((success == 0) && (failure == 0)) {
		*vp = 0;
		return 0;
	}
	if (success > 0) return ((failure == 0) ? 0 : 1);
	return -1;
}

/* ---------------------------------------------------------------------------
 * cf_badname: Disallow use of player name/alias.
 */

int cf_badname (int *vp, char *str, int extra, dbref player, char *cmd)
{
	badname_add(str);
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_site: Update site information
 */

int cf_site (int *vp, char *str, int extra, dbref player, char *cmd)
{
SITE	*site, *last, *head;
char	*addr_txt, *mask_txt;
struct in_addr addr_num, mask_num;

	addr_txt = strtok(str, " \t=,");
	mask_txt = strtok(NULL, " \t=,");
	addr_num.s_addr = inet_addr(addr_txt);
	mask_num.s_addr = inet_addr(mask_txt);

	if (addr_num.s_addr == -1) {
		cf_log_syntax(player, cmd, "Bad host address: %s", addr_txt);
		return -1;
	}

	head = (SITE *) *vp;
	/* Parse the access entry and allocate space for it */

	site = (SITE *)malloc(sizeof(SITE));

	/* Initialize the site entry */

	site->address.s_addr = addr_num.s_addr;
	site->mask.s_addr = mask_num.s_addr;
	site->flag = extra;
	site->next = NULL;

	/* Link in the entry.  Link it at the start if not initializing, at
	 * the end if initializing.  This is so that entries in the config
	 * file are processed as you would think they would be, while entries
	 * made while running are processed first.
	 */

	if (mudstate.initializing) {
		if (head == NULL) {
			*vp = (int) site;
		} else {
			for (last=head; last->next; last=last->next);
			last->next = site;
		}
	} else {
		site->next = head;
		*vp = (int) site;
	}
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_cf_access: Set access on config directives
 */

int cf_cf_access (int *vp, char *str, int extra, dbref player, char *cmd)
{
CONF	*tp;
char	*ap;

	for (ap=str; *ap && !isspace(*ap); ap++);
	if (*ap) *ap++='\0';

	for (tp=conftable; tp->pname; tp++) {
		if (!strcmp(tp->pname, str)) {
			return (cf_modify_bits(&tp->flags, ap, extra,
				player, cmd));
		}
	}
	cf_log_notfound(player, cmd, "Config directive", str);
	return -1;
}

/* ---------------------------------------------------------------------------
 * cf_include: Read another config file.  Only valid during startup.
 */

int cf_include (int *vp, char *str, int extra, dbref player, char *cmd)
{
FILE	*fp;
char	*cp, *ap, *zp, *buf;

        if (!mudstate.initializing)
		return -1;

	fp = fopen(str, "r");
	if (fp == NULL) {
		cf_log_notfound(player, cmd, "Config file", str);
		return -1;
	}

	buf = alloc_lbuf("cf_include");
	fgets(buf, LBUF_SIZE, fp);
	while (!feof(fp)) {
		cp = buf;
		if (*cp == '#') {
			fgets(buf, LBUF_SIZE, fp);
			continue;
		}

		/* Not a comment line.  Strip off the NL and any characters
		 * following it.  Then, split the line into the command and
		 * argument portions (separated by a space).  Also, trim off
		 * the trailing comment, if any (delimited by #)
		 */

		for (cp=buf; *cp && *cp!='\n'; cp++);
		*cp = '\0';				/* strip \n */
		for (cp=buf; *cp && isspace(*cp); cp++);/* strip spaces */
		for (ap=cp; *ap && !isspace(*ap); ap++);/* skip over command */
		if (*ap) *ap++ = '\0';			/* trim command */
		for (; *ap && isspace(*ap); ap++);	/* skip spaces */
		for (zp=ap; *zp && (*zp != '#'); zp++);	/* find comment */
		if (*zp) *zp = '\0';			/* zap comment */
		for (zp=zp-1; zp>=ap && isspace(*zp); zp--)
			*zp='\0';			/* zap trailing spcs */

		cf_set(cp, ap, player);
		fgets(buf, LBUF_SIZE, fp);
	}
	free_lbuf(buf);
	fclose(fp);
	return 0;
}

extern int cf_access (int *vp, char *str, int extra, dbref player,
	char *cmd);
extern int cf_acmd_access (int *vp, char *str, int extra, dbref player,
	char *cmd);
extern int cf_cmd_alias (int *vp, char *str, int extra, dbref player,
	char *cmd);
extern int cf_attr_access (int *vp, char *str, int extra, dbref player,
	char *cmd);
extern int cf_ntab_access (int *vp, char *str, int extra, dbref player,
	char *cmd);

/* ---------------------------------------------------------------------------
 * conftable: Table for parsing the configuration file.
 */

CONF conftable[] = {
{(char *)"abort_on_bug",
	cf_bool,	CA_DISABLED,	&mudconf.abort_on_bug,		0},
{(char *)"access",
	cf_access,	CA_GOD,		NULL,
	(int)access_nametab},
{(char *)"alias",
	cf_cmd_alias,	CA_GOD,		(int *)&mudstate.command_htab,	0},
{(char *)"attr_access",
	cf_attr_access,	CA_GOD,		NULL,
	(int)attraccess_nametab},
{(char *)"attr_alias",
	cf_alias,	CA_GOD,		(int *)&mudstate.attr_name_htab,0},
{(char *)"attr_cmd_access",
	cf_acmd_access,	CA_GOD,		NULL,
	(int)access_nametab},
{(char *)"bad_name",
	cf_badname,	CA_GOD,		NULL,				0},
{(char *)"badsite_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.site_file,	32},
{(char *)"check_interval",
	cf_int,		CA_GOD,		&mudconf.check_interval,	0},
{(char *)"check_offset",
	cf_int,		CA_GOD,		&mudconf.check_offset,		0},
{(char *)"clone_copies_cost",
	cf_bool,	CA_GOD,		&mudconf.clone_copy_cost,	0},
{(char *)"command_quota_increment",
	cf_int,		CA_GOD,		&mudconf.cmd_quota_incr,	0},
{(char *)"command_quota_max",
	cf_int,		CA_GOD,		&mudconf.cmd_quota_max,		0},
{(char *)"compress_program",
	cf_string,	CA_DISABLED,	(int *)mudconf.compress,	128},
{(char *)"compression",
	cf_bool,	CA_GOD,		&mudconf.compress_db,		0},
{(char *)"config_access",
	cf_cf_access,	CA_GOD,		NULL,
	(int)access_nametab},
{(char *)"conn_timeout",
	cf_int,		CA_GOD,		&mudconf.conn_timeout,		0},
{(char *)"connect_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.conn_file,	32},
{(char *)"connect_reg_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.creg_file,	32},
{(char *)"crash_database",
	cf_string,	CA_DISABLED,	(int *)mudconf.crashdb,		128},
{(char *)"create_max_cost",
	cf_int,		CA_GOD,		&mudconf.createmax,		0},
{(char *)"create_min_cost",
	cf_int,		CA_GOD,		&mudconf.createmin,		0},
{(char *)"dark_sleepers",
	cf_bool,	CA_GOD,		&mudconf.dark_sleepers,		0},
{(char *)"default_home",
	cf_int,		CA_GOD,		&mudconf.default_home,		0},
{(char *)"destroy_sacrifice",
	cf_bool,	CA_GOD,		&mudconf.sac_dest,		0},
{(char *)"dig_cost",
	cf_int,		CA_GOD,		&mudconf.digcost,		0},
{(char *)"down_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.down_file,	32},
{(char *)"down_motd_message",
	cf_string,	CA_GOD,		(int *)mudconf.downmotd_msg,	1024},
{(char *)"dump_interval",
	cf_int,		CA_GOD,		&mudconf.dump_interval,		0},
{(char *)"dump_message",
	cf_string,	CA_GOD,		(int *)mudconf.dump_msg,	128},
{(char *)"dump_offset",
	cf_int,		CA_GOD,		&mudconf.dump_offset,		0},
{(char *)"earn_limit",
	cf_int,		CA_GOD,		&mudconf.paylimit,		0},
{(char *)"examine_flags",
	cf_bool,	CA_GOD,		&mudconf.ex_flags,		0},
{(char *)"examine_public_attrs",
	cf_bool,	CA_GOD,		&mudconf.exam_public,		0},
{(char *)"exit_flags",
	cf_set_flags,	CA_GOD,		&mudconf.exit_flags,
	(int)&mudstate.e_flags_htab},
{(char *)"exit_quota",
	cf_int,		CA_GOD,		&mudconf.exit_quota,		0},
{(char *)"find_money_chance",
	cf_int,		CA_GOD,		&mudconf.payfind, 		0},
{(char *)"flag_alias",
	cf_flagalias,	CA_GOD,		NULL,				0},
{(char *)"forbid_site",
	cf_site,	CA_GOD,		(int *)&mudstate.access_list,
	H_FORBIDDEN},
{(char *)"fork_dump",
	cf_bool,	CA_GOD,		&mudconf.fork_dump,		0},
{(char *)"fork_vfork",
	cf_bool,	CA_GOD,		&mudconf.fork_vfork,		0},
{(char *)"full_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.full_file,	32},
{(char *)"full_motd_message",
	cf_string,	CA_GOD,		(int *)mudconf.fullmotd_msg,	1024},
{(char *)"function_alias",
	cf_alias,	CA_GOD,		(int *)&mudstate.func_htab,	0},
{(char *)"function_invocation_limit",
	cf_int,         CA_GOD,         &mudconf.func_invk_lim,		0},
{(char *)"function_recursion_limit",
	cf_int,         CA_GOD,         &mudconf.func_nest_lim,		0},
{(char *)"garbage_chunk",
	cf_int,		CA_GOD,		&mudconf.garbage_chunk,		0},
{(char *)"gdbm_cache_size",
	cf_int,		CA_DISABLED,	&mudconf.gdbm_cache_size,	0},
{(char *)"gdbm_database",
	cf_string,	CA_DISABLED,	(int *)mudconf.gdbm,		128},
{(char *)"guest_char_num",
	cf_int,		CA_DISABLED,	&mudconf.guest_char,		0},
{(char *)"guest_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.guest_file,	32},
{(char *)"help_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.help_file,	32},
{(char *)"help_index",
	cf_string,	CA_DISABLED,	(int *)mudconf.help_indx,	32},
{(char *)"hostnames",
	cf_bool,	CA_GOD,		&mudconf.use_hostname,		0},
{(char *)"idle_wiz_dark",
	cf_bool,	CA_GOD,		&mudconf.idle_wiz_dark,		0},
{(char *)"idle_interval",
	cf_int,		CA_GOD,		&mudconf.idle_interval,		0},
{(char *)"idle_timeout",
	cf_int,		CA_GOD,		&mudconf.idle_timeout,		0},
{(char *)"include",
	cf_include,	CA_DISABLED,	NULL,				0},
{(char *)"initial_size",
	cf_int,		CA_DISABLED,	&mudconf.init_size,		0},
{(char *)"input_database",
	cf_string,	CA_DISABLED, 	(int *)mudconf.indb,		128},
{(char *)"internal_compress_string",
	cf_bool, 	CA_DISABLED, 	&mudconf.intern_comp, 		0},
{(char *)"kill_guarantee_cost",
	cf_int,		CA_GOD,		&mudconf.killguarantee,		0},
{(char *)"kill_max_cost",
	cf_int,		CA_GOD,		&mudconf.killmax,		0},
{(char *)"kill_min_cost",
	cf_int,		CA_GOD,		&mudconf.killmin,		0},
{(char *)"link_cost",
	cf_int,		CA_GOD,		&mudconf.linkcost,		0},
{(char *)"list_access",
	cf_ntab_access,	CA_GOD,		(int *)list_names,
	(int)access_nametab},
{(char *)"lock_recursion_limit",
	cf_int,         CA_GOD,         &mudconf.lock_nest_lim,		0},
{(char *)"log",
	cf_modify_bits,	CA_GOD,		&mudconf.log_options,
	(int)logoptions_nametab},
{(char *)"log_options",
	cf_modify_bits,	CA_GOD,		&mudconf.log_info,
	(int)logdata_nametab},
{(char *)"logout_cmd_access",
	cf_ntab_access,	CA_GOD,		(int *)logout_cmdtable,
	(int)access_nametab},
{(char *)"logout_cmd_alias",
	cf_alias,	CA_GOD,		(int *)&mudstate.logout_cmd_htab,0},
{(char *)"machine_command_cost",
	cf_int,		CA_GOD,		&mudconf.machinecost,		0},
{(char *)"master_room",
	cf_int,		CA_GOD,		&mudconf.master_room,		0},
{(char *)"match_own_commands",
	cf_bool,	CA_GOD,		&mudconf.match_mine,		0},
{(char *)"max_players",
	cf_int,		CA_GOD,		&mudconf.max_players,		0},
{(char *)"money_name_plural",
	cf_string,	CA_GOD,		(int *)mudconf.many_coins,	32},
{(char *)"money_name_singular",
	cf_string,	CA_GOD,		(int *)mudconf.one_coin,	32},
{(char *)"motd_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.motd_file,	32},
{(char *)"motd_message",
	cf_string,	CA_GOD,		(int *)mudconf.motd_msg,	1024},
{(char *)"mud_name",
	cf_string,	CA_GOD,		(int *)mudconf.mud_name,	32},
{(char *)"news_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.news_file,	32},
{(char *)"news_index",
	cf_string,	CA_DISABLED,	(int *)mudconf.news_indx,	32},
{(char *)"newuser_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.crea_file,	32},
{(char *)"notify_recursion_limit",
	cf_int,         CA_GOD,         &mudconf.ntfy_nest_lim,		0},
{(char *)"open_cost",
	cf_int,		CA_GOD,		&mudconf.opencost,		0},
{(char *)"output_database",
	cf_string,	CA_DISABLED,	(int *)mudconf.outdb,		128},
{(char *)"output_limit",
	cf_int,		CA_GOD,		&mudconf.output_limit,		0},
{(char *)"page_cost",
	cf_int,		CA_GOD,		&mudconf.pagecost,		0},
{(char *)"paycheck",
	cf_int,		CA_GOD,		&mudconf.paycheck,		0},
{(char *)"pemit_far_players",
	cf_bool,	CA_GOD,		&mudconf.pemit_players,		0},
{(char *)"pemit_any_object",
	cf_bool,	CA_GOD,		&mudconf.pemit_any,		0},
{(char *)"permit_site",
	cf_site,	CA_GOD,		(int *)&mudstate.access_list,	0},
{(char *)"player_flags",
	cf_set_flags,	CA_GOD,		&mudconf.player_flags,
	(int)&mudstate.p_flags_htab},
{(char *)"player_listen",
	cf_bool,	CA_GOD,		&mudconf.player_listen,		0},
{(char *)"player_match_own_commands",
	cf_bool,	CA_GOD,		&mudconf.match_mine_pl,		0},
{(char *)"player_queue_limit",
	cf_int,		CA_GOD,		&mudconf.queuemax,		0},
{(char *)"player_quota",
	cf_int,		CA_GOD,		&mudconf.player_quota,		0},
{(char *)"player_starting_home",
	cf_int,		CA_GOD,		&mudconf.start_home,		0},
{(char *)"player_starting_room",
	cf_int,		CA_GOD,		&mudconf.start_room,		0},
{(char *)"port",
	cf_int,		CA_DISABLED,	&mudconf.port,			0},
{(char *)"power_access",
	cf_ntab_access,	CA_GOD,		(int *)powers_nametab,
	(int)access_nametab},
{(char *)"public_flags",
	cf_bool,	CA_GOD,		&mudconf.pub_flags,		0},
{(char *)"queue_active_chunk",
	cf_int,		CA_GOD,		&mudconf.active_q_chunk,	0},
{(char *)"queue_idle_chunk",
	cf_int,		CA_GOD,		&mudconf.queue_chunk,		0},
{(char *)"quiet_look",
	cf_bool,	CA_GOD,		&mudconf.quiet_look,		0},
{(char *)"quiet_whisper",
	cf_bool,	CA_GOD,		&mudconf.quiet_whisper,		0},
{(char *)"quit_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.quit_file,	32},
{(char *)"quotas",
	cf_bool,	CA_GOD,		&mudconf.quotas,		0},
{(char *)"read_remote_desc",
	cf_bool,	CA_GOD,		&mudconf.read_rem_desc,		0},
{(char *)"read_remote_name",
	cf_bool,	CA_GOD,		&mudconf.read_rem_name,		0},
{(char *)"recycling",
	cf_bool,	CA_GOD,		&mudconf.recycle,		0},
{(char *)"register_create_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.regf_file,	32},
{(char *)"register_site",
	cf_site,	CA_GOD,		(int *)&mudstate.access_list,
	H_REGISTRATION},
{(char *)"retry_limit",
	cf_int,		CA_GOD,		&mudconf.retry_limit,		0},
{(char *)"robot_cost",
	cf_int,		CA_GOD,		&mudconf.robotcost,		0},
{(char *)"robot_flags",
	cf_set_flags,	CA_GOD,		&mudconf.robot_flags,
	(int)&mudstate.p_flags_htab},
{(char *)"robot_speech",
	cf_bool,	CA_GOD,		&mudconf.robot_speak,		0},
{(char *)"room_flags",
	cf_set_flags,	CA_GOD,		&mudconf.room_flags,
	(int)&mudstate.r_flags_htab},
{(char *)"room_quota",
	cf_int,		CA_GOD,		&mudconf.room_quota,		0},
{(char *)"rwho_data_port",
	cf_int,		CA_GOD,		&mudconf.rwho_data_port,	0},
{(char *)"rwho_dump_interval",
	cf_int,		CA_GOD,		&mudconf.rwho_interval,		0},
{(char *)"rwho_host",
	cf_string,	CA_GOD,		(int *)mudconf.rwho_host,	64},
{(char *)"rwho_info_port",
	cf_int,		CA_GOD,		&mudconf.rwho_info_port,	0},
{(char *)"rwho_password",
	cf_string,	CA_GOD,		(int *)mudconf.rwho_pass,	32},
{(char *)"rwho_transmit",
	cf_bool,	CA_GOD,		&mudconf.rwho_transmit,		0},
{(char *)"sacrifice_adjust",
	cf_int,		CA_GOD,		&mudconf.sacadjust,		0},
{(char *)"sacrifice_factor",
	cf_int,		CA_GOD,		&mudconf.sacfactor,		0},
{(char *)"search_cost",
	cf_int,		CA_GOD,		&mudconf.searchcost,		0},
{(char *)"see_owned_dark",
	cf_bool,	CA_GOD,		&mudconf.see_own_dark,		0},
{(char *)"space_compress",
	cf_bool,	CA_GOD,		&mudconf.space_compress,	0},
{(char *)"starting_money",
	cf_int,		CA_GOD,		&mudconf.paystart,		0},
{(char *)"starting_quota",
	cf_int,		CA_GOD,		&mudconf.start_quota,		0},
{(char *)"status_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.status_file,	128},
{(char *)"suspect_site",
	cf_site,	CA_GOD,		(int *)&mudstate.suspect_list,
	H_SUSPECT},
{(char *)"sweep_dark",
	cf_bool,	CA_GOD,		&mudconf.sweep_dark,		0},
{(char *)"switch_default_all",
	cf_bool,	CA_GOD,		&mudconf.switch_df_all,		0},
{(char *)"thing_flags",
	cf_set_flags,	CA_GOD,		&mudconf.thing_flags,
	(int)&mudstate.t_flags_htab},
{(char *)"thing_quota",
	cf_int,		CA_GOD,		&mudconf.thing_quota,		0},
{(char *)"timeslice",
	cf_int,		CA_GOD,		&mudconf.timeslice,		0},
{(char *)"trust_site",
	cf_site,	CA_GOD,		(int *)&mudstate.suspect_list,	0},
{(char *)"uncompress_program",
	cf_string,	CA_DISABLED,	(int *)mudconf.uncompress,	128},
{(char *)"user_attr_access",
	cf_modify_bits,	CA_GOD,		&mudconf.vattr_flags,
	(int)attraccess_nametab},
{(char *)"wait_cost",
	cf_int,		CA_GOD,		&mudconf.waitcost,		0},
{(char *)"whereis_notify",
	cf_bool,	CA_GOD,		&mudconf.whereis_notify,	0},
{(char *)"wizard_help_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.whelp_file,	32},
{(char *)"wizard_help_index",
	cf_string,	CA_DISABLED,	(int *)mudconf.whelp_indx,	32},
{(char *)"wizard_motd_file",
	cf_string,	CA_DISABLED,	(int *)mudconf.wizmotd_file,	32},
{(char *)"wizard_motd_message",
	cf_string,	CA_GOD,		(int *)mudconf.wizmotd_msg,	1024},
{ NULL,
	NULL,		0,		NULL,				0}};

/* ---------------------------------------------------------------------------
 * cf_set: Set config parameter.
 */

int cf_set(char *cp, char *ap, dbref player)
{
CONF	*tp;
int	i;
char	*buff;

	/* Search the config parameter table for the command.
	   If we find it, call the handler to parse the argument. */

	for (tp=conftable; tp->pname; tp++) {
		if (!strcmp(tp->pname, cp)) {
			if (!mudstate.initializing &&
			    !check_access(player, tp->flags)) {
				notify(player,
					"Permission denied.");
				return(-1);
			}
			if (!mudstate.initializing) {
				buff = alloc_lbuf("cf_set");
				strcpy(buff, ap);
			}
			i = tp->interpreter(tp->loc, ap, tp->extra, player, cp);
			if (!mudstate.initializing) {
				STARTLOG(LOG_CONFIGMODS,"CFG","UPDAT")
					log_name(player);
					log_text((char *)" entered config directive: ");
					log_text(cp);
					log_text((char *)" with args '");
					log_text(buff);
					log_text((char *)"'.  Status: ");
					switch (i) {
					case 0:
						log_text((char *)"Success.");
						break;
					case 1:
						log_text((char *)"Partial success.");
						break;
					case -1:
						log_text((char *)"Failure.");
						break;
					default:
						log_text((char *)"Strange.");
					}
				ENDLOG
				free_lbuf(buff);
			}
			return i;
		}
	}

	/* Config directive not found.  Complain about it. */

	cf_log_notfound(player, (char *)"Set", "Config directive", cp);
	return(-1);
}

/* ---------------------------------------------------------------------------
 * do_admin: Command handler to set config params at runtime */

void do_admin (dbref player, dbref cause, int extra, char *kw, char *value)
{
int	i;

	i = cf_set(kw, value, player);
	if ((i >= 0) && !Quiet(player)) notify(player, "Set.");
	return;
}

/* ---------------------------------------------------------------------------
 * cf_read: Read in config parameters from named file
 */

int cf_read (char *fn)
{
int	retval;

	mudstate.initializing = 1;
	retval = cf_include (NULL, fn, 0, 0, (char *)"init");
	mudstate.initializing = 0;

	/* Fill in missing DB file names */

	if (!*mudconf.outdb) {
		strcpy(mudconf.outdb, mudconf.indb);
		strcat(mudconf.outdb, ".out");
	}
	if (!*mudconf.crashdb) {
		strcpy(mudconf.crashdb, mudconf.indb);
		strcat(mudconf.crashdb, ".CRASH");
	}
	if (!*mudconf.gdbm) {
		strcpy(mudconf.gdbm, mudconf.indb);
		strcat(mudconf.gdbm, ".gdbm");
	}
	return retval;
}

/* ---------------------------------------------------------------------------
 * list_cf_access: List access to config directives.
 */

void list_cf_access (dbref player)
{
CONF	*tp;
char	*buff;

	buff = alloc_mbuf("list_cf_access");
	for (tp=conftable; tp->pname; tp++) {
		if (God(player) || check_access(player, tp->flags)) {
			sprintf(buff, "%s:", tp->pname);
			listset_nametab(player, access_nametab, tp->flags,
				buff, 1);
		}
	}
	free_mbuf(buff);
}

#endif	/* STANDALONE */