tinymush-3.1p2/game/backups/
tinymush-3.1p2/game/bin/
tinymush-3.1p2/game/data/
tinymush-3.1p2/game/modules/
tinymush-3.1p2/game/modules/old/
tinymush-3.1p2/src/modules/comsys/
tinymush-3.1p2/src/modules/hello/
tinymush-3.1p2/src/modules/mail/
tinymush-3.1p2/src/tools/
/* conf.c - configuration functions and defaults */
/* $Id: conf.c,v 1.192 2004/10/09 23:17:03 tyrspace Exp $ */

#include "copyright.h"
#include "autoconf.h"
#include "config.h"

#include "alloc.h"	/* required by mudconf */
#include "flags.h"	/* required by mudconf */
#include "htab.h"	/* required by mudconf */
#include "mudconf.h"	/* required by code */

#include "db.h"		/* required by externs */
#include "externs.h"	/* required by interface */
#include "interface.h"	/* required by code */

#include "command.h"	/* required by code */
#include "attrs.h"	/* required by code */
#include "match.h"	/* required by code */
#include "ansi.h"	/* required by code */

/* Some systems are lame, and inet_addr() claims to return -1 on failure,
 * despite the fact that it returns an unsigned long. (It's not really a -1,
 * obviously.) Better-behaved systems use INADDR_NONE.
 */
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif

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

CONFDATA mudconf;
STATEDATA mudstate;

extern NAMETAB logdata_nametab[];
extern NAMETAB logoptions_nametab[];
extern NAMETAB access_nametab[];
extern NAMETAB attraccess_nametab[];
extern NAMETAB list_names[];
extern NAMETAB sigactions_nametab[];
extern CONF conftable[];
extern LOGFILETAB logfds_table[];

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

void NDECL(cf_init)
{
	char *s;
	
	s = XMALLOC(MBUF_SIZE, "cf_init");

	mudconf.status_file = XSTRDUP("shutdown.status", "cf_string");
	mudstate.modules_list = NULL;
	mudstate.modloaded[0] = '\0';
	mudconf.port = 6250;
	mudconf.conc_port = 6251;
	mudconf.init_size = 1000;
	mudconf.use_global_aconn = 1;
	mudconf.global_aconn_uselocks = 0;
	mudconf.guest_char = NOTHING;
	mudconf.guest_nuker = GOD;
	mudconf.number_guests = 30;
	mudconf.guest_basename = XSTRDUP("Guest", "cf_string");
	mudconf.guest_password = XSTRDUP("guest", "cf_string");
	mudconf.guest_prefixes = XSTRDUP("", "cf_string");
	mudconf.guest_suffixes = XSTRDUP("", "cf_string");
	
	sprintf(s, "%s/guest.txt", mudconf.txthome);
	mudconf.guest_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/connect.txt", mudconf.txthome);
	mudconf.conn_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/register.txt", mudconf.txthome);
	mudconf.creg_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/create_reg.txt", mudconf.txthome);
	mudconf.regf_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/motd.txt", mudconf.txthome);
	mudconf.motd_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/wizmotd.txt", mudconf.txthome);
	mudconf.wizmotd_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/quit.txt", mudconf.txthome);
	mudconf.quit_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/down.txt", mudconf.txthome);
	mudconf.down_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/full.txt", mudconf.txthome);
	mudconf.full_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/badsite.txt", mudconf.txthome);
	mudconf.site_file = XSTRDUP(s, "cf_string");
	
	sprintf(s, "%s/newuser.txt", mudconf.txthome);
	mudconf.crea_file = XSTRDUP(s, "cf_string");
#ifdef PUEBLO_SUPPORT
	sprintf(s, "%s/htmlconn.txt", mudconf.txthome);
	mudconf.htmlconn_file = XSTRDUP(s, "cf_string");
#endif
	mudconf.motd_msg = XSTRDUP("", "cf_string");
	mudconf.wizmotd_msg = XSTRDUP("", "cf_string");
	mudconf.downmotd_msg = XSTRDUP("", "cf_string");
	mudconf.fullmotd_msg = XSTRDUP("", "cf_string");
	mudconf.dump_msg = XSTRDUP("", "cf_string");
	mudconf.postdump_msg = XSTRDUP("", "cf_string");
	mudconf.fixed_home_msg = XSTRDUP("", "cf_string");
	mudconf.fixed_tel_msg = XSTRDUP("", "cf_string");
	mudconf.huh_msg = XSTRDUP("Huh?  (Type \"help\" for help.)", "cf_string");
#ifdef PUEBLO_SUPPORT
	mudconf.pueblo_msg = XSTRDUP("</xch_mudtext><img xch_mode=html><tt>", "cf_string");
#endif
	mudconf.sql_host = XSTRDUP("127.0.0.1", "cf_string");
	mudconf.sql_db = XSTRDUP("", "cf_string");
	mudconf.sql_username = XSTRDUP("", "cf_string");
	mudconf.sql_password = XSTRDUP("", "cf_string");
	mudconf.sql_reconnect = 0;
	mudconf.indent_desc = 0;
       	mudconf.name_spaces = 1;
	mudconf.fork_dump = 0;
	mudconf.fork_vfork = 0;
	mudconf.dbopt_interval = 0;
#ifdef PUEBLO_SUPPORT
	mudconf.have_pueblo = 1;
#else
	mudconf.have_pueblo = 0;
#endif
	mudconf.have_zones = 1;
	mudconf.paranoid_alloc = 0;
	mudconf.sig_action = SA_DFLT;
	mudconf.max_players = -1;
	mudconf.dump_interval = 3600;
	mudconf.check_interval = 600;
	mudconf.events_daily_hour = 7;
	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 = mudconf.start_room_quota =
	    mudconf.start_exit_quota = mudconf.start_thing_quota =
	    mudconf.start_player_quota = 20;
	mudconf.site_chars = 25;
	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.building_limit = 50000;
	mudconf.exit_quota = 1;
	mudconf.player_quota = 1;
	mudconf.room_quota = 1;
	mudconf.thing_quota = 1;
	mudconf.queuemax = 100;
	mudconf.queue_chunk = 10;
	mudconf.active_q_chunk = 10;
	mudconf.sacfactor = 5;
	mudconf.sacadjust = -1;
	mudconf.use_hostname = 1;
	mudconf.quotas = 0;
	mudconf.typed_quotas = 0;
	mudconf.ex_flags = 1;
	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.visible_wizzes = 0;
	mudconf.pemit_players = 0;
	mudconf.pemit_any = 0;
	mudconf.addcmd_match_blindly = 1;
	mudconf.addcmd_obey_stop = 0;
	mudconf.addcmd_obey_uselocks = 0;
	mudconf.lattr_oldstyle = 0;
	mudconf.bools_oldstyle = 0;
	mudconf.match_mine = 0;
	mudconf.match_mine_pl = 0;
	mudconf.switch_df_all = 1;
	mudconf.fascist_objeval = 0;
	mudconf.fascist_tport = 0;
	mudconf.terse_look = 1;
	mudconf.terse_contents = 1;
	mudconf.terse_exits = 1;
	mudconf.terse_movemsg = 1;
	mudconf.trace_topdown = 1;
	mudconf.trace_limit = 200;
	mudconf.safe_unowned = 0;
	mudconf.wiz_obey_linklock = 0;
	mudconf.local_masters = 1;
	mudconf.req_cmds_flag = 1;
	mudconf.ansi_colors = 1;
	mudconf.safer_passwords = 0;
	mudconf.instant_recycle = 1;
	mudconf.dark_actions = 0;
	mudconf.no_ambiguous_match = 0;
	mudconf.exit_calls_move = 0;
	mudconf.move_match_more = 0;
	mudconf.autozone = 1;
	mudconf.page_req_equals = 0;
	mudconf.comma_say = 0;
	mudconf.you_say = 1;
	mudconf.c_cmd_subst = 1;
	mudconf.register_limit = 50;
	
	/* -- ??? Running SC on a non-SC DB may cause problems */
	mudconf.space_compress = 1;

	mudconf.start_room = 0;
	mudconf.guest_start_room = NOTHING; /* default, use start_room */
	mudconf.start_home = NOTHING;
	mudconf.default_home = NOTHING;
	mudconf.master_room = NOTHING;
	mudconf.player_proto = NOTHING;
	mudconf.room_proto = NOTHING;
	mudconf.exit_proto = NOTHING;
	mudconf.thing_proto = NOTHING;
	mudconf.player_defobj = NOTHING;
	mudconf.room_defobj = NOTHING;
	mudconf.thing_defobj = NOTHING;
	mudconf.exit_defobj = NOTHING;
	mudconf.player_parent = NOTHING;
	mudconf.room_parent = NOTHING;
	mudconf.exit_parent = NOTHING;
	mudconf.thing_parent = NOTHING;
	mudconf.player_flags.word1 = 0;
	mudconf.player_flags.word2 = 0;
	mudconf.player_flags.word3 = 0;
	mudconf.room_flags.word1 = 0;
	mudconf.room_flags.word2 = 0;
	mudconf.room_flags.word3 = 0;
	mudconf.exit_flags.word1 = 0;
	mudconf.exit_flags.word2 = 0;
	mudconf.exit_flags.word3 = 0;
	mudconf.thing_flags.word1 = 0;
	mudconf.thing_flags.word2 = 0;
	mudconf.thing_flags.word3 = 0;
	mudconf.robot_flags.word1 = ROBOT;
	mudconf.robot_flags.word2 = 0;
	mudconf.robot_flags.word3 = 0;
	mudconf.stripped_flags.word1 = IMMORTAL | INHERIT | ROYALTY | WIZARD;
	mudconf.stripped_flags.word2 = BLIND | CONNECTED | GAGGED |
	    HEAD_FLAG | SLAVE | STAFF | STOP_MATCH | SUSPECT | UNINSPECTED;
	mudconf.stripped_flags.word3 = 0;
	mudconf.vattr_flags = 0;
	mudconf.vattr_flag_list = NULL;
	mudconf.mud_name = XSTRDUP("TinyMUSH", "cf_string");
	mudconf.one_coin = XSTRDUP("penny", "cf_string");
	mudconf.many_coins = XSTRDUP("pennies", "cf_string");
	mudconf.struct_dstr = XSTRDUP("\r\n", "cf_string");
	mudconf.timeslice = 1000;
	mudconf.cmd_quota_max = 100;
	mudconf.cmd_quota_incr = 1;
#ifdef NO_LAG_CHECK
	mudconf.lag_check = 0;
#else
	mudconf.lag_check = 1;
#endif
	mudconf.max_cmdsecs = 120;
	mudconf.control_flags = 0xffffffff;	/* Everything for now... */
	mudconf.control_flags &= ~CF_GODMONITOR; /* Except for monitoring... */
	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 | LOG_TIMEUSE | LOG_LOCAL;
	mudconf.log_info = LOGOPT_TIMESTAMP | LOGOPT_LOC;
	mudconf.log_diversion = 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;
	mudconf.wild_times_lim = 25000;
	mudconf.cmd_nest_lim = 50;
	mudconf.cmd_invk_lim = 2500;
	mudconf.func_nest_lim = 50;
	mudconf.func_invk_lim = 2500;
	mudconf.func_cpu_lim_secs = 60;
	mudconf.func_cpu_lim = 60 * CLOCKS_PER_SEC;
	mudconf.ntfy_nest_lim = 20;
	mudconf.fwdlist_lim = 100;
	mudconf.lock_nest_lim = 20;
	mudconf.parent_nest_lim = 10;
	mudconf.zone_nest_lim = 20;
	mudconf.numvars_lim = 50;
	mudconf.stack_lim = 50;
	mudconf.struct_lim = 100;
	mudconf.instance_lim = 100;
	mudconf.max_player_aliases = 10;
	mudconf.cache_width = CACHE_WIDTH;
	mudconf.cache_size = CACHE_SIZE;

	mudstate.initializing = 0;
	mudstate.loading_db = 0;
	mudstate.panicking = 0;
	mudstate.standalone = 0;
	mudstate.dumping = 0;
	mudstate.dumper = 0;
	mudstate.logging = 0;
	mudstate.epoch = 0;
	mudstate.generation = 0;
	mudstate.reboot_nums = 0;
	mudstate.mudlognum = 0;
	mudstate.helpfiles = 0;
	mudstate.hfiletab = NULL;
	mudstate.hfiletab_size = 0;
	mudstate.hfile_hashes = NULL;
	mudstate.curr_player = NOTHING;
	mudstate.curr_enactor = NOTHING;
	mudstate.curr_cmd = (char *) "< none >";
    	mudstate.shutdown_flag = 0;
    	mudstate.flatfile_flag = 0;
	mudstate.attr_next = A_USER_START;
	mudstate.debug_cmd = (char *)"< init >";
	StringCopy(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 = NULL;
	mudstate.min_size = 0;
	mudstate.db_top = 0;
	mudstate.db_size = 0;
	mudstate.moduletype_top = DBTYPE_RESERVED;
	mudstate.freelist = NOTHING;
	mudstate.markbits = NULL;
	mudstate.sql_socket = -1;
	mudstate.cmd_nest_lev = 0;
	mudstate.cmd_invk_ctr = 0;
	mudstate.func_nest_lev = 0;
	mudstate.func_invk_ctr = 0;
	mudstate.wild_times_lev = 0;
	mudstate.cputime_base = clock();
	mudstate.ntfy_nest_lev = 0;
	mudstate.lock_nest_lev = 0;
	mudstate.zone_nest_num = 0;
	mudstate.in_loop = 0;
	mudstate.loop_token[0] = NULL;
	mudstate.loop_number[0] = 0;
	mudstate.in_switch = 0;
	mudstate.switch_token = NULL;
	mudstate.inpipe = 0;
	mudstate.pout = NULL;
	mudstate.poutnew = NULL;
	mudstate.poutbufc = NULL;
	mudstate.poutobj = -1;
	mudstate.dbm_fd = -1;
	mudstate.rdata = NULL;

	XFREE(s, "cf_init");
}

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

void cf_log_notfound(player, cmd, thingname, thing)
dbref player;
char *cmd, *thing;
const char *thingname;
{
	if (mudstate.initializing) {
		STARTLOG(LOG_STARTUP, "CNF", "NFND")
		    log_printf("%s: %s %s not found", cmd, thingname, thing);
		ENDLOG
	} else {
		notify(player, tprintf("%s %s not found", thingname, thing));
	}
}

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

#if defined(__STDC__) && defined(STDC_HEADERS)
void cf_log_syntax(dbref player, char *cmd, const char *template,...)
#else
void cf_log_syntax(va_alist)
va_dcl
#endif
{
	va_list ap;

#if defined(__STDC__) && defined(STDC_HEADERS)
	va_start(ap, template);
#else
	dbref player;
	char *cmd, *template;

	player = va_arg(ap, dbref);
	cmd = va_arg(ap, char *);
	template = va_arg(ap, char *);
#endif

	if (mudstate.initializing) {
		STARTLOG(LOG_STARTUP, "CNF", "SYNTX")
		    log_printf("%s: ", cmd);
		    log_vprintf(template, ap);
		ENDLOG
	} else {
		notify(player, tvprintf(template, ap));
	}

	va_end(ap);
}

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

int cf_status_from_succfail(player, cmd, success, failure)
dbref player;
char *cmd;
int success, failure;
{
	/*
	 * 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")
			    log_printf("%s: Nothing to set", cmd);
			ENDLOG
		} else {
			notify(player, "Nothing to set");
		}
	}
	return -1;
}

/* ---------------------------------------------------------------------------
 * cf_const: Read-only integer or boolean parameter.
 */

CF_HAND(cf_const)
{
	/* Fail on any attempt to change the value */

	return -1;
}

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

CF_HAND(cf_int)
{
	/* Copy the numeric value to the parameter */

	if ((extra > 0) && (atoi(str) > extra)) {
	    cf_log_syntax(player, cmd, "Value exceeds limit of %d", extra);
	    return -1;
	}
	sscanf(str, "%d", vp);
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_int_factor: Set integer parameter that will be used as a factor
 *                (ie. cannot be set to 0)
 */

CF_HAND(cf_int_factor)
{
	int num;

	/* Copy the numeric value to the parameter */

	num = atoi(str);

	if ((extra > 0) && (num > extra)) {
	    cf_log_syntax(player, cmd, "Value exceeds limit of %d", extra);
	    return -1;
	}
	if (num == 0) {
	    cf_log_syntax(player, cmd, "Value cannot be 0.  You may want a value of 1.");
	    return -1;
	}
	sscanf(str, "%d", vp);
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_dbref: Set dbref parameter.
 */

CF_HAND(cf_dbref)
{
    int num;

    /* No consistency check on initialization. */

    if (mudstate.initializing) {
	if (*str == '#') {
	    sscanf(str, "#%d", vp);
	} else {
	    sscanf(str, "%d", vp);
	}
	return 0;
    }

    /* Otherwise we have to validate this. If 'extra' is non-zero, the
     * dbref is allowed to be NOTHING.
     */

    if (*str == '#')
	num = atoi(str + 1);
    else
	num = atoi(str);

    if (((extra == NOTHING) && (num == NOTHING)) ||
	(Good_obj(num) && !Going(num))) {
	if (*str == '#') {
	    sscanf(str, "#%d", vp);
	} else {
	    sscanf(str, "%d", vp);
	}
	return 0;
    }

    if (extra == NOTHING) {
	cf_log_syntax(player, cmd, "A valid dbref, or -1, is required.");
    } else {
	cf_log_syntax(player, cmd, "A valid dbref is required.");
    }
    return -1;
}

/* ---------------------------------------------------------------------------
 * cf_module: Open a loadable module. Modules are initialized later in the
 * startup.
 */

CF_HAND(cf_module)
{
	lt_dlhandle handle;
	void (*initptr)(void);
	MODULE *mp;
	
	handle = lt_dlopen(tprintf("%s.la", str));

	if (!handle) {
		STARTLOG(LOG_STARTUP, "CNF", "MOD")
		    log_printf("Loading of %s module failed: %s",
			       str, lt_dlerror());
		ENDLOG
		return -1;
	}

	mp = (MODULE *) XMALLOC(sizeof(MODULE), "cf_module.mp");
	mp->modname = XSTRDUP(str, "cf_module.name");
	mp->handle = handle;
	mp->next = mudstate.modules_list;
	mudstate.modules_list = mp;

	/* Look up our symbols now, and cache the pointers. They're
	 * not going to change from here on out.
	 */

	mp->process_command = DLSYM_INT(handle, str, "process_command",
					(dbref, dbref, int, char *,
					 char *[], int));
	mp->process_no_match = DLSYM_INT(handle, str, "process_no_match",
					(dbref, dbref, int, char *, char *,
					 char *[], int));
	mp->did_it = DLSYM_INT(handle, str, "did_it",
			       (dbref, dbref, dbref,
				int, const char *, int, const char *, int,
				int, char *[], int, int));
	mp->create_obj = DLSYM(handle, str, "create_obj", (dbref, dbref));
	mp->destroy_obj = DLSYM(handle, str, "destroy_obj", (dbref, dbref));
	mp->create_player = DLSYM(handle, str, "create_player",
				  (dbref, dbref, int, int));
	mp->destroy_player = DLSYM(handle, str, "destroy_player",
				   (dbref, dbref));
	mp->announce_connect = DLSYM(handle, str, "announce_connect",
				     (dbref, const char *, int));
	mp->announce_disconnect = DLSYM(handle, str, "announce_disconnect",
					(dbref, const char *, int));
	mp->examine = DLSYM(handle, str, "examine",
			    (dbref, dbref, dbref, int, int));
	mp->dump_database = DLSYM(handle, str, "dump_database", (FILE *));
	mp->db_grow = DLSYM(handle, str, "db_grow", (int, int));
	mp->db_write = DLSYM(handle, str, "db_write", (void));
	mp->db_write_flatfile = DLSYM(handle, str, "db_write_flatfile", (FILE *));
	mp->do_second = DLSYM(handle, str, "do_second", (void));
	mp->cache_put_notify = DLSYM(handle, str, "cache_put_notify", (DBData, unsigned int));
	mp->cache_del_notify = DLSYM(handle, str, "cache_del_notify", (DBData, unsigned int));

	if (!mudstate.standalone) {
		if ((initptr = DLSYM(handle, str, "init", (void))) != NULL)
		    (*initptr)();
	}
	
	STARTLOG(LOG_STARTUP, "CNF", "MOD")
		log_printf("Loaded module: %s", str);
	ENDLOG

	return 0;
}

/* *INDENT-OFF* */

/* ---------------------------------------------------------------------------
 * 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}};

/* *INDENT-ON* */


CF_HAND(cf_bool)
{
	*vp = (int) search_nametab(GOD, bool_names, str);
	if (*vp < 0)
		*vp = (long) 0;
	return 0;
}

/* ---------------------------------------------------------------------------
 * cf_option: Select one option from many choices.
 */

CF_HAND(cf_option)
{
	int i;

	i = search_nametab(GOD, (NAMETAB *) extra, str);
	if (i < 0) {
		cf_log_notfound(player, cmd, "Value", str);
		return -1;
	}
	*vp = i;
	return 0;
}

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

CF_HAND(cf_string)
{
	int retval;

	/*
	 * Make a copy of the string if it is not too big 
	 */

	retval = 0;
	if (strlen(str) >= (unsigned int)extra) {
		str[extra - 1] = '\0';
		if (mudstate.initializing) {
			STARTLOG(LOG_STARTUP, "CNF", "NFND")
			log_printf("%s: String truncated", cmd);
			ENDLOG
		} else {
			notify(player, "String truncated");
		}
		retval = 1;
	}
        XFREE(*(char **)vp, "cf_string");
	*(char **)vp = XSTRDUP(str, "cf_string");
	return retval;
}

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

CF_HAND(cf_alias)
{
	char *alias, *orig, *p, *tokst;
	int *cp, upcase;

	alias = strtok_r(str, " \t=,", &tokst);
	orig = strtok_r(NULL, " \t=,", &tokst);
	if (orig) {
		upcase = 0;
		for (p = orig; *p; p++)
			*p = tolower(*p);
		cp = hashfind(orig, (HASHTAB *) vp);
		if (cp == NULL) {
			upcase++;
			for (p = orig; *p; p++)
				*p = toupper(*p);
			cp = hashfind(orig, (HASHTAB *) vp);
			if (cp == NULL) {
				cf_log_notfound(player, cmd,
						(char *) extra, orig);
				return -1;
			}
		}
		if (upcase) {
			for (p = alias; *p; p++)
				*p = toupper(*p);
		} else {
			for (p = alias; *p; p++)
				*p = tolower(*p);
		}
		if (((HASHTAB *)vp)->flags & HT_KEYREF) {
			/* hashadd won't copy it, so we do that here */
			p = alias;
			alias = XSTRDUP(p, "cf_alias");
		}
		return hashadd(alias, cp, (HASHTAB *) vp, HASH_ALIAS);
	} else {
		cf_log_syntax(player, cmd, "Invalid original for alias %s",
			      alias);
		return -1;
	}
}

/* ---------------------------------------------------------------------------
 * cf_divert_log: Redirect a log type.
 */

CF_HAND(cf_divert_log)
{
    char *type_str, *file_str, *tokst;
    int f, fd;
    FILE *fptr;
    LOGFILETAB *tp, *lp;

    /* Two args, two args only */

    type_str = strtok_r(str, " \t", &tokst);
    file_str = strtok_r(NULL, " \t", &tokst);
    if (!type_str || !file_str) {
	cf_log_syntax(player, cmd, "Missing pathname to log to.", (char *) "");
	return -1;
    }

    /* Find the log. */

    f = search_nametab(GOD, (NAMETAB *) extra, type_str);
    if (f <= 0) {
	cf_log_notfound(player, cmd, "Log diversion", type_str);
	return -1;
    }

    for (tp = logfds_table; tp->log_flag; tp++) {
	if (tp->log_flag == f)
	    break;
    }
    if (tp == NULL) {		/* This should never happen! */
	cf_log_notfound(player, cmd, "Logfile table corruption", type_str);
	return -1;
    }

    /* We shouldn't have a file open already. */

    if (tp->filename != NULL) {
	    STARTLOG(LOG_STARTUP, "CNF", "DIVT")
		log_printf("Log type %s already diverted: %s",
			   type_str, tp->filename);
	    ENDLOG
	    return -1;
    }

    /* Check to make sure that we don't have this filename open already. */

    fptr = NULL;
    for (lp = logfds_table; lp->log_flag; lp++) {
	if (lp->filename && !strcmp(file_str, lp->filename)) {
	    fptr = lp->fileptr;
	    break;
	}
    }

    /* We don't have this filename yet. Open the logfile. */

    if (!fptr) {
	fptr = fopen(file_str, "w");
	if (!fptr) {
	    STARTLOG(LOG_STARTUP, "CNF", "DIVT")
		log_printf("Cannot open logfile: %s", file_str);
	    ENDLOG
	    return -1;
	}
	
	if ((fd = fileno(fptr)) == -1) {
		return -1;
	}
	
#ifdef FNDELAY
	if (fcntl(fd, F_SETFL, FNDELAY) == -1) {
	    STARTLOG(LOG_STARTUP, "CNF", "DIVT")
		log_printf("Cannot make nonblocking: %s", file_str);
	    ENDLOG
	    return -1;
	}
#else
	if (fcntl(fd, F_SETFL, O_NDELAY) == -1) {
	    STARTLOG(LOG_STARTUP, "CNF", "DIVT")
		log_printf("Cannot make nonblocking: %s", file_str);
	    ENDLOG
	    return -1;
	}
#endif
    }

    /* Indicate that this is being diverted. */

    tp->fileptr = fptr;
    tp->filename = XSTRDUP(file_str, "cf_divert_log");
    *vp |= f;

    return 0;
}

/* ---------------------------------------------------------------------------
 * cf_modify_bits: set or clear bits in a flag word from a namelist.
 */

CF_HAND(cf_modify_bits)
{
	char *sp, *tokst;
	int f, negate, success, failure;

	/*
	 * Walk through the tokens 
	 */

	success = failure = 0;
	sp = strtok_r(str, " \t", &tokst);
	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 > 0) {
			if (negate)
				*vp &= ~f;
			else
				*vp |= f;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/* Get the next token */

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

/* ---------------------------------------------------------------------------
 * modify_xfuncs: Helper function to change xfuncs.
 */

static NAMEDFUNC **all_named_funcs = NULL;
static int num_named_funcs = 0;

static int modify_xfuncs(fn_name, fn_ptr, xfuncs, negate)
    char *fn_name;
    int (*fn_ptr)(dbref);
    EXTFUNCS **xfuncs;
    int negate;		/* 0 - normal, 1 - remove */
{
    EXTFUNCS *xfp;
    NAMEDFUNC *np, **tp;
    int i;

    xfp = *xfuncs;

    /* If we're negating, just remove it from the list of functions. */

    if (negate) {
	if (!xfp)
	    return 0;
	for (i = 0; i < xfp->num_funcs; i++) {
	    if (!strcmp(xfp->ext_funcs[i]->fn_name, fn_name)) {
		xfp->ext_funcs[i] = NULL;
		return 1;
	    }
	}
	return 0;
    }

    /* Have we encountered this function before? */

    np = NULL;
    for (i = 0; i < num_named_funcs; i++) {
	if (!strcmp(all_named_funcs[i]->fn_name, fn_name)) {
	    np = all_named_funcs[i];
	    break;
	}
    }

    /* If not, we need to allocate it. */

    if (!np) {
	np = (NAMEDFUNC *) XMALLOC(sizeof(NAMEDFUNC), "nfunc");
	np->fn_name = (char *) strdup(fn_name);
	np->handler = fn_ptr;
    }

    /* Add it to the ones we know about. */

    if (num_named_funcs == 0) {
	all_named_funcs = (NAMEDFUNC **) XMALLOC(sizeof(NAMEDFUNC *),
						 "all_named_funcs");
	num_named_funcs = 1;
	all_named_funcs[0] = np;
    } else {
	tp = (NAMEDFUNC **) XREALLOC(all_named_funcs,
				(num_named_funcs + 1) * sizeof(NAMEDFUNC *),
				"all_named_funcs");
	tp[num_named_funcs] = np;
	all_named_funcs = tp;
	num_named_funcs++;
    }

    /* Do we have an existing list of functions? If not, this is easy. */

    if (!xfp) {
	xfp = (EXTFUNCS *) XMALLOC(sizeof(EXTFUNCS), "xfunc");
	xfp->num_funcs = 1;
	xfp->ext_funcs = (NAMEDFUNC **) XMALLOC(sizeof(NAMEDFUNC *), "nfuncs");
	xfp->ext_funcs[0] = np;
	*xfuncs = xfp;
	return 1;
    }

    /* See if we have an empty slot to insert into. */

    for (i = 0; i < xfp->num_funcs; i++) {
	if (!xfp->ext_funcs[i]) {
	    xfp->ext_funcs[i] = np;
	    return 1;
	}
    }

    /* Guess not. Tack it onto the end. */

    tp = (NAMEDFUNC **) XREALLOC(xfp->ext_funcs,
				 (xfp->num_funcs + 1) * sizeof(NAMEDFUNC *),
				 "nfuncs");
    tp[xfp->num_funcs] = np;
    xfp->ext_funcs = tp;
    xfp->num_funcs++;
    return 1;
}

/* ---------------------------------------------------------------------------
 * parse_ext_access: Parse an extended access list with module callouts.
 */

int parse_ext_access(perms, xperms, str, ntab, player, cmd)
    int *perms;
    EXTFUNCS **xperms;
    char *str;
    NAMETAB *ntab;
    dbref player;
    char *cmd;
{
    char *sp, *tokst, *cp, *ostr;
    int f, negate, success, failure, got_one;
    MODULE *mp;
    int (*hp)(dbref);

    /* Walk through the tokens */

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

	/* Check for negation  */

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

	/* Set or clear the appropriate bit */

	f = search_nametab(GOD, ntab, sp);
	if (f > 0) {
	    if (negate)
		*perms &= ~f;
	    else
		*perms |= f;
	    success++;
	} else {

	    /* Is this a module callout? */

	    got_one = 0;

	    if (!strncmp(sp, "mod_", 4)) {

		/* Split it apart, see if we have anything. */

		ostr = (char *) strdup(sp); 
		if (*(sp + 4) != '\0') {
		    cp = strchr(sp + 4, '_');
		    if (cp) {
			*cp++ = '\0';
			WALK_ALL_MODULES(mp) {
			    got_one = 1;
			    if (!strcmp(sp + 4, mp->modname)) {
				hp = DLSYM_INT(mp->handle, mp->modname, cp,
					       (dbref));
				if (!hp) {
				    cf_log_notfound(player, cmd,
						   "Module function", ostr);
				    failure++;
				} else {
				    if (modify_xfuncs(ostr, hp, xperms,
						      negate))
					success++;
				    else
					failure++;
				}
				break;
			    }
			}
			if (!got_one) {
			    cf_log_notfound(player, cmd, "Loaded module",
					    sp + 4);
			    got_one = 1;
			}
		    }
		}
		free(ostr);
	    }

	    if (!got_one) {
		cf_log_notfound(player, cmd, "Entry", sp);
		failure++;
	    }
	}

	/* Get the next token */

	sp = strtok_r(NULL, " \t", &tokst);
    }

    return cf_status_from_succfail(player, cmd, success, failure);
}

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

CF_HAND(cf_set_flags)
{
	char *sp, *tokst;
	FLAGENT *fp;
	FLAGSET *fset;

	int success, failure;

	for (sp = str; *sp; sp++)
		*sp = toupper(*sp);

	/*
	 * Walk through the tokens 
	 */

	success = failure = 0;
	sp = strtok_r(str, " \t", &tokst);
	fset = (FLAGSET *) vp;

	while (sp != NULL) {

		/*
		 * Set the appropriate bit 
		 */

		fp = (FLAGENT *) hashfind(sp, &mudstate.flags_htab);
		if (fp != NULL) {
			if (success == 0) {
				(*fset).word1 = 0;
				(*fset).word2 = 0;
				(*fset).word3 = 0;
			}
			if (fp->flagflag & FLAG_WORD3)
				(*fset).word3 |= fp->flagvalue;
			else if (fp->flagflag & FLAG_WORD2)
				(*fset).word2 |= fp->flagvalue;
			else
				(*fset).word1 |= fp->flagvalue;
			success++;
		} else {
			cf_log_notfound(player, cmd, "Entry", sp);
			failure++;
		}

		/*
		 * Get the next token 
		 */

		sp = strtok_r(NULL, " \t", &tokst);
	}
	if ((success == 0) && (failure == 0)) {
		(*fset).word1 = 0;
		(*fset).word2 = 0;
		(*fset).word3 = 0;
		return 0;
	}
	if (success > 0)
		return ((failure == 0) ? 0 : 1);
	return -1;
}

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

CF_HAND(cf_badname)
{
	if (extra)
		badname_remove(str);
	else
		badname_add(str);
	return 0;
}

/* ---------------------------------------------------------------------------
 * sane_inet_addr: inet_addr() does not necessarily do reasonable checking
 * for sane syntax. On certain operating systems, if passed less than four
 * octets, it will cause a segmentation violation. This is unfriendly.
 * We take steps here to deal with it.
 */

static unsigned long sane_inet_addr(str)
    char *str;
{
    int i;
    char *p;

    p = str;
    for (i = 1; (p = strchr(p, '.')) != NULL; i++, p++)
	;
    if (i < 4)
	return INADDR_NONE;
    else
	return inet_addr(str);
}


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

CF_AHAND(cf_site)
{
    SITE *site, *last, *head;
    char *addr_txt, *mask_txt, *tokst;
    struct in_addr addr_num, mask_num;
    int mask_bits;

    if ((mask_txt = strchr(str, '/')) == NULL) {

	/* Standard IP range and netmask notation. */

	addr_txt = strtok_r(str, " \t=,", &tokst);
	if (addr_txt)
	    mask_txt = strtok_r(NULL, " \t=,", &tokst);
	if (!addr_txt || !*addr_txt || !mask_txt || !*mask_txt) {
	    cf_log_syntax(player, cmd, "Missing host address or mask.",
			  (char *)"");
	    return -1;
	}
	if ((addr_num.s_addr = sane_inet_addr(addr_txt)) == INADDR_NONE) {
	    cf_log_syntax(player, cmd, "Malformed host address: %s", addr_txt);
	    return -1;
	}
	if (((mask_num.s_addr = sane_inet_addr(mask_txt)) == INADDR_NONE) &&
	    strcmp(mask_txt, "255.255.255.255")) {
	    cf_log_syntax(player, cmd, "Malformed mask address: %s", mask_txt);
	    return -1;
	}
    } else {

	/* RFC 1517, 1518, 1519, 1520: CIDR IP prefix notation */

	addr_txt = str;
	*mask_txt++ = '\0';
	mask_bits = atoi(mask_txt);
	if ((mask_bits > 32) || (mask_bits < 0)) {
	    cf_log_syntax(player, cmd,
			  "Mask bits (%d) in CIDR IP prefix out of range.",
			  mask_bits);
	    return -1;
	} else if (mask_bits == 0) {
	    mask_num.s_addr = htonl(0); /* can't shift by 32 */
	} else {
	    mask_num.s_addr = htonl(0xFFFFFFFFU << (32 - mask_bits));
	}

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

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

    if (!(site = (SITE *) XMALLOC(sizeof(SITE), "cf_site")))
	return -1;

    /*
     * Initialize the site entry 
     */

    site->address.s_addr = addr_num.s_addr;
    site->mask.s_addr = mask_num.s_addr;
    site->flag = (long) 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 = (long *) site;
	} else {
	    for (last = head; last->next; last = last->next)
		;
	    last->next = site;
	}
    } else {
	site->next = head;
	*vp = (long *) site;
    }
    return 0;
}

/* ---------------------------------------------------------------------------
 * cf_cf_access: Set write or read access on config directives
 * kludge: this cf handler uses vp as an extra extra field since the
 * first extra field is taken up with the access nametab.
 */

static int helper_cf_cf_access(tp, player, vp, ap, cmd, extra)
    CONF *tp;
    dbref player;
    int *vp;
    char *ap, *cmd;
    long extra;
{
    /* Cannot modify parameters set STATIC */

    if (tp->flags & CA_STATIC) {
	notify(player, NOPERM_MESSAGE);
	STARTLOG(LOG_CONFIGMODS, "CFG", "PERM")
	    if (db)
		    log_name(player);
	    else
	    	    log_printf("System");
	    log_printf(" tried to change %s access to static param: %s",
		       (((long)vp) ? "read" : "write"),
		       tp->pname);
	ENDLOG
	return -1;
    }
    if ((long)vp) {
	return (cf_modify_bits(&tp->rperms, ap, extra,
			       player, cmd));
    } else {
	return (cf_modify_bits(&tp->flags, ap, extra,
			       player, cmd));
    }
}

CF_HAND(cf_cf_access)
{
	CONF *tp, *ctab;
	char *ap;
	MODULE *mp;

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

	for (tp = conftable; tp->pname; tp++) {
	    if (!strcmp(tp->pname, str)) {
		return (helper_cf_cf_access(tp, player, vp, ap, cmd, extra)); 
	    }
	}

	WALK_ALL_MODULES(mp) {
	    if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
				  CONF *)) != NULL) {
		for (tp = ctab; tp->pname; tp++) {
		    if (!strcmp(tp->pname, str)) {
			return (helper_cf_cf_access(tp, player, vp, ap,
						    cmd, extra));
		    }
		}
	    }
	}

	cf_log_notfound(player, cmd, "Config directive", str);
	return -1;
}

/* ---------------------------------------------------------------------------
 * cf_helpfile: Add a help/news-style file. Only valid during startup.
 */

int add_helpfile(player, confcmd, str, is_raw)
    dbref player;
    char *confcmd, *str;
    int is_raw;
{
    char *fcmd, *fpath, *newstr, *tokst;
    CMDENT *cmdp;
    char **ftab;		/* pointer to an array of filepaths */
    HASHTAB *hashes;

    /* Make a new string so we won't SEGV if given a constant string */
    
    newstr = alloc_mbuf("add_helpfile");
    StringCopy(newstr, str);

    fcmd = strtok_r(newstr, " \t=,", &tokst);
    fpath = strtok_r(NULL, " \t=,", &tokst);
    if (fpath == NULL) {
	cf_log_syntax(player, confcmd, "Missing path for helpfile %s", fcmd);
	free_mbuf(newstr);
	return -1;
    }
    if (fcmd[0] == '_' && fcmd[1] == '_') {
	cf_log_syntax(player, confcmd, "Helpfile %s would cause @addcommand conflict", fcmd);
	free_mbuf(newstr);
	return -1;
    }
    if (strlen(fpath) > SBUF_SIZE) {
	cf_log_syntax(player, confcmd, "Helpfile %s filename too long", fcmd);
	free_mbuf(newstr);
	return -1;
    }
    
    cmdp = (CMDENT *) XMALLOC(sizeof(CMDENT), "add_helpfile.cmdp");
    cmdp->cmdname = XSTRDUP(fcmd, "add_helpfile.cmd");
    cmdp->switches = NULL;
    cmdp->perms = 0;
    cmdp->pre_hook = NULL;
    cmdp->post_hook = NULL;
    cmdp->userperms = NULL;
    cmdp->callseq = CS_ONE_ARG;
    cmdp->info.handler = do_help;

    cmdp->extra = mudstate.helpfiles;
    if (is_raw)
	cmdp->extra |= HELP_RAWHELP;

    hashdelete(cmdp->cmdname, &mudstate.command_htab);
    hashadd(cmdp->cmdname, (int *) cmdp, &mudstate.command_htab, 0);
    hashdelete(tprintf("__%s", cmdp->cmdname), &mudstate.command_htab);
    hashadd(tprintf("__%s", cmdp->cmdname), (int *) cmdp, &mudstate.command_htab, HASH_ALIAS);

    /* We may need to grow the helpfiles table, or create it. */

    if (!mudstate.hfiletab) {

	mudstate.hfiletab = (char **) XCALLOC(4, sizeof(char *), "helpfile.htab");
	mudstate.hfile_hashes = (HASHTAB *) XCALLOC(4, sizeof(HASHTAB), "helpfile.hashes");
	mudstate.hfiletab_size = 4;

    } else if (mudstate.helpfiles >= mudstate.hfiletab_size) {

	ftab = (char **) XREALLOC(mudstate.hfiletab,
				(mudstate.hfiletab_size + 4) * sizeof(char *),
				  "helpfile.htab");
	hashes = (HASHTAB *) XREALLOC(mudstate.hfile_hashes,
				      (mudstate.hfiletab_size + 4) *
				      sizeof(HASHTAB), "helpfile.hashes");
	ftab[mudstate.hfiletab_size] = NULL;
	ftab[mudstate.hfiletab_size + 1] = NULL;
	ftab[mudstate.hfiletab_size + 2] = NULL;
	ftab[mudstate.hfiletab_size + 3] = NULL;
	mudstate.hfiletab_size += 4;
	mudstate.hfiletab = ftab;
	mudstate.hfile_hashes = hashes;

    }

    /* Add or replace the path to the file. */

    if (mudstate.hfiletab[mudstate.helpfiles] != NULL)
	XFREE(mudstate.hfiletab[mudstate.helpfiles], "add_helpfile.fpath");
    mudstate.hfiletab[mudstate.helpfiles] = XSTRDUP(fpath, "add_helpfile.fpath");

    /* Initialize the associated hashtable. */

    hashinit(&mudstate.hfile_hashes[mudstate.helpfiles], 30 * HASH_FACTOR,
	     HT_STR);

    mudstate.helpfiles++;
    free_mbuf(newstr);

    return 0;
}

CF_HAND(cf_helpfile)
{
    return add_helpfile(player, cmd, str, 0);
}

CF_HAND(cf_raw_helpfile)
{
    return add_helpfile(player, cmd, str, 1);
}

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

CF_HAND(cf_include)
{
	FILE *fp;
	char *cp, *ap, *zp, *buf;

	extern int FDECL(cf_set, (char *, char *, dbref));


	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 && !(isdigit(*(zp + 1)) && isspace(*(zp -1))))
			*zp = '\0';	/*
					 * zap comment, but only if it's
					 * not sitting between whitespace
					 * and a digit, which traps a case
					 * like 'master_room #2'
					 */
		for (zp = zp - 1; zp >= ap && isspace(*zp); zp--)
			*zp = '\0';	/*
					 * zap trailing spaces
					 */

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

extern CF_HDCL(cf_access);
extern CF_HDCL(cf_cmd_alias);
extern CF_HDCL(cf_acmd_access);
extern CF_HDCL(cf_attr_access);
extern CF_HDCL(cf_attr_type);
extern CF_HDCL(cf_func_access);
extern CF_HDCL(cf_flag_access);
extern CF_HDCL(cf_flag_name);
extern CF_HDCL(cf_power_access);

/* *INDENT-OFF* */

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

CONF conftable[] = {
{(char *)"access",			cf_access,	CA_GOD,		CA_DISABLED,	NULL,				(long)access_nametab},
{(char *)"addcommands_match_blindly",	cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.addcmd_match_blindly,	(long)"@addcommands don't error if no match is found"},
{(char *)"addcommands_obey_stop",	cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.addcmd_obey_stop,	(long)"@addcommands obey STOP"},
{(char *)"addcommands_obey_uselocks",	cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.addcmd_obey_uselocks,	(long)"@addcommands obey UseLocks"},
{(char *)"alias",			cf_cmd_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.command_htab,	0},
{(char *)"ansi_colors",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.ansi_colors,		(long)"ANSI color codes enabled"},
{(char *)"attr_access",			cf_attr_access,	CA_GOD,		CA_DISABLED,	NULL,				(long)attraccess_nametab},
{(char *)"attr_alias",			cf_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.attr_name_htab,(long)"Attribute"},
{(char *)"attr_cmd_access",		cf_acmd_access,	CA_GOD,		CA_DISABLED,	NULL,				(long)access_nametab},
{(char *)"attr_type",			cf_attr_type,	CA_GOD,		CA_DISABLED,	NULL,				(long)attraccess_nametab},
{(char *)"autozone",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.autozone,		(long)"New objects are @chzoned to their creator's zone"},
{(char *)"bad_name",			cf_badname,	CA_GOD,		CA_DISABLED,	NULL,				0},
{(char *)"badsite_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.site_file,	MBUF_SIZE},
{(char *)"binary_home",			cf_string,	CA_STATIC, 	CA_GOD,		(int *)&mudconf.binhome,	MBUF_SIZE},
{(char *)"booleans_oldstyle",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.bools_oldstyle,	(long)"Dbrefs #0 and #-1 are boolean false, all other\n\t\t\t\tdbrefs are boolean true"},
{(char *)"building_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	(int *)&mudconf.building_limit,	0},
{(char *)"c_is_command",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.c_cmd_subst,		(long)"%c substitution is last command rather than ANSI"},
{(char *)"cache_size",			cf_int,		CA_GOD,		CA_GOD,		&mudconf.cache_size,		0},
{(char *)"cache_width",			cf_int,		CA_STATIC,	CA_GOD,		&mudconf.cache_width,		0},
{(char *)"check_interval",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.check_interval,	0},
{(char *)"check_offset",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.check_offset,		0},
{(char *)"clone_copies_cost",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.clone_copy_cost,	(long)"@clone copies object cost"},
{(char *)"command_invocation_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.cmd_invk_lim,		0},
{(char *)"command_quota_increment",	cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.cmd_quota_incr,	0},
{(char *)"command_quota_max",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.cmd_quota_max,		0},
{(char *)"command_recursion_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.cmd_nest_lim,		0},
{(char *)"concentrator_port",		cf_int,		CA_STATIC,	CA_WIZARD,	&mudconf.conc_port,		0},
{(char *)"config_access",		cf_cf_access,	CA_GOD,		CA_DISABLED,	NULL,				(long)access_nametab},
{(char *)"config_read_access",		cf_cf_access,	CA_GOD,		CA_DISABLED,	(int *)1,			(long)access_nametab},
{(char *)"conn_timeout",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.conn_timeout,		0},
{(char *)"connect_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.conn_file,	MBUF_SIZE},
{(char *)"connect_reg_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.creg_file,	MBUF_SIZE},
{(char *)"crash_database",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.crashdb,	MBUF_SIZE},
{(char *)"create_max_cost",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.createmax,		0},
{(char *)"create_min_cost",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.createmin,		0},
{(char *)"dark_actions",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.dark_actions,		(long)"Dark objects still trigger @a-actions when moving"},
{(char *)"dark_sleepers",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.dark_sleepers,		(long)"Disconnected players not shown in room contents"},
{(char *)"database_home",		cf_string,	CA_STATIC, 	CA_GOD,		(int *)&mudconf.dbhome,		MBUF_SIZE},
{(char *)"default_home",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.default_home,		NOTHING},
{(char *)"dig_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.digcost,		0},
{(char *)"divert_log",			cf_divert_log,	CA_STATIC,	CA_DISABLED,	&mudconf.log_diversion,		(long) logoptions_nametab},
{(char *)"down_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.down_file,	MBUF_SIZE},
{(char *)"down_motd_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.downmotd_msg,	GBUF_SIZE},
{(char *)"dump_interval",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.dump_interval,		0},
{(char *)"dump_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.dump_msg,	MBUF_SIZE},
{(char *)"postdump_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.postdump_msg,	MBUF_SIZE},
{(char *)"dump_offset",			cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.dump_offset,		0},
{(char *)"earn_limit",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.paylimit,		0},
{(char *)"examine_flags",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.ex_flags,		(long)"examine shows names of flags"},
{(char *)"examine_public_attrs",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.exam_public,		(long)"examine shows public attributes"},
{(char *)"exit_flags",			cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.exit_flags,	0},
{(char *)"exit_calls_move",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.exit_calls_move,	(long)"Using an exit calls the move command"},
{(char *)"exit_parent",			cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.exit_parent,		NOTHING},
{(char *)"exit_proto",			cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.exit_proto,		NOTHING},
{(char *)"exit_attr_defaults",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.exit_defobj,		NOTHING},
{(char *)"exit_quota",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.exit_quota,		0},
{(char *)"events_daily_hour",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.events_daily_hour,	0},
{(char *)"fascist_teleport",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.fascist_tport,		(long)"@teleport source restricted to control or JUMP_OK"},
{(char *)"fixed_home_message",		cf_string,	CA_STATIC,	CA_PUBLIC,	(int *)&mudconf.fixed_home_msg,	MBUF_SIZE},
{(char *)"fixed_tel_message",		cf_string,	CA_STATIC,	CA_PUBLIC,	(int *)&mudconf.fixed_tel_msg,	MBUF_SIZE},
{(char *)"find_money_chance",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.payfind, 		0},
{(char *)"flag_alias",			cf_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.flags_htab,	(long)"Flag"},
{(char *)"flag_access",			cf_flag_access,	CA_GOD,		CA_DISABLED,	NULL,				0},
{(char *)"flag_name",			cf_flag_name,	CA_GOD,		CA_DISABLED,	NULL,				0},
{(char *)"forbid_site",			cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.access_list,	H_FORBIDDEN},
{(char *)"fork_dump",			cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.fork_dump,		(long)"Dumps are performed using a forked process"},
{(char *)"fork_vfork",			cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.fork_vfork,		(long)"Forks are done using vfork()"},
{(char *)"forwardlist_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.fwdlist_lim,		0},
{(char *)"full_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.full_file,	MBUF_SIZE},
{(char *)"full_motd_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.fullmotd_msg,	GBUF_SIZE},
{(char *)"function_access",		cf_func_access,	CA_GOD,		CA_DISABLED,	NULL,				(long)access_nametab},
{(char *)"function_alias",		cf_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.func_htab,	(long)"Function"},
{(char *)"function_invocation_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.func_invk_lim,		0},
{(char *)"function_recursion_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.func_nest_lim,		0},
{(char *)"function_cpu_limit",		cf_int,		CA_STATIC,	CA_PUBLIC,	&mudconf.func_cpu_lim_secs,	0},
{(char *)"gdbm_database",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.gdbm,		MBUF_SIZE},
{(char *)"global_aconn_uselocks",	cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.global_aconn_uselocks,	(long)"Obey UseLocks on global @Aconnect and @Adisconnect"},
{(char *)"good_name",			cf_badname,	CA_GOD,		CA_DISABLED,	NULL,				1},
{(char *)"guest_basename",		cf_string,	CA_STATIC,	CA_PUBLIC,	(int *)&mudconf.guest_basename,	PLAYER_NAME_LIMIT},
{(char *)"guest_char_num",		cf_dbref,	CA_GOD,		CA_WIZARD,	&mudconf.guest_char,		NOTHING},
{(char *)"guest_nuker",			cf_dbref,	CA_GOD,		CA_WIZARD,	&mudconf.guest_nuker,		GOD},
{(char *)"guest_password",		cf_string,	CA_GOD,		CA_GOD,		(int *)&mudconf.guest_password,	SBUF_SIZE},
{(char *)"guest_prefixes",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.guest_prefixes,	LBUF_SIZE},
{(char *)"guest_suffixes",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.guest_suffixes,	LBUF_SIZE},
{(char *)"number_guests",		cf_int,		CA_STATIC,	CA_WIZARD,	&mudconf.number_guests,		0},
{(char *)"guest_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.guest_file,	MBUF_SIZE},
{(char *)"guest_site",			cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.access_list, 	H_GUEST},
{(char *)"guest_starting_room",		cf_dbref,	CA_GOD,		CA_WIZARD,	&mudconf.guest_start_room,	NOTHING},

{(char *)"have_pueblo",			cf_const,	CA_STATIC,	CA_PUBLIC,	&mudconf.have_pueblo,		(long)"Pueblo client extensions are supported"},
{(char *)"have_zones",			cf_bool,	CA_STATIC,	CA_PUBLIC,	&mudconf.have_zones,		(long)"Multiple control via ControlLocks is permitted"},
{(char *)"helpfile",			cf_helpfile,	CA_STATIC,	CA_DISABLED,	NULL,				0},
{(char *)"hostnames",			cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.use_hostname,		(long)"DNS lookups are done on hostnames"},

#ifdef PUEBLO_SUPPORT
{(char *)"html_connect_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.htmlconn_file,	MBUF_SIZE},
{(char *)"pueblo_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.pueblo_msg,	GBUF_SIZE},
#endif

{(char *)"huh_message",			cf_string,	CA_GOD,		CA_PUBLIC,	(int *)&mudconf.huh_msg,	MBUF_SIZE},
{(char *)"idle_wiz_dark",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.idle_wiz_dark,		(long)"Wizards who idle are set DARK"},
{(char *)"idle_interval",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.idle_interval,		0},
{(char *)"idle_timeout",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.idle_timeout,		0},
{(char *)"include",			cf_include,	CA_STATIC,	CA_DISABLED,	NULL,				0},
{(char *)"indent_desc",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.indent_desc,		(long)"Descriptions are indented"},
{(char *)"initial_size",		cf_int,		CA_STATIC,	CA_WIZARD,	&mudconf.init_size,		0},
{(char *)"instance_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.instance_lim,		0},
{(char *)"instant_recycle",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.instant_recycle,	(long)"@destroy instantly recycles objects set DESTROY_OK"},
{(char *)"kill_guarantee_cost",		cf_int_factor,		CA_GOD,		CA_PUBLIC,	&mudconf.killguarantee,		0},
{(char *)"kill_max_cost",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.killmax,		0},
{(char *)"kill_min_cost",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.killmin,		0},
{(char *)"lag_check",			cf_const,	CA_STATIC,	CA_PUBLIC,	&mudconf.lag_check,		(long)"CPU usage warnings are enabled"},
{(char *)"lag_maximum",			cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.max_cmdsecs,		0},
{(char *)"lattr_default_oldstyle",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.lattr_oldstyle,	(long)"Empty lattr() returns blank, not #-1 NO MATCH"},
{(char *)"link_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.linkcost,		0},
{(char *)"list_access",			cf_ntab_access,	CA_GOD,		CA_DISABLED,	(int *)list_names,		(long)access_nametab},
{(char *)"local_master_rooms",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.local_masters,		(long)"Objects set ZONE act as local master rooms"},
{(char *)"lock_recursion_limit",	cf_int,		CA_WIZARD,	CA_PUBLIC,	&mudconf.lock_nest_lim,		0},
{(char *)"log",				cf_modify_bits,	CA_GOD,		CA_DISABLED,	&mudconf.log_options,		(long)logoptions_nametab},
{(char *)"log_options",			cf_modify_bits,	CA_GOD,		CA_DISABLED,	&mudconf.log_info,		(long)logdata_nametab},
{(char *)"logout_cmd_access",		cf_ntab_access,	CA_GOD,		CA_DISABLED,	(int *)logout_cmdtable,		(long)access_nametab},
{(char *)"logout_cmd_alias",		cf_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.logout_cmd_htab,(long)"Logged-out command"},
{(char *)"look_obey_terse",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.terse_look,		(long)"look obeys the TERSE flag"},
{(char *)"machine_command_cost",	cf_int_factor,		CA_GOD,		CA_PUBLIC,	&mudconf.machinecost,		0},
{(char *)"master_room",			cf_dbref,	CA_GOD,		CA_WIZARD,	&mudconf.master_room,		NOTHING},
{(char *)"match_own_commands",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.match_mine,		(long)"Non-players can match $-commands on themselves"},
{(char *)"max_players",			cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.max_players,		0},
{(char *)"module",			cf_module,	CA_STATIC,	CA_WIZARD,	NULL,				0},
{(char *)"money_name_plural",		cf_string,	CA_GOD,		CA_PUBLIC,	(int *)&mudconf.many_coins,	SBUF_SIZE},
{(char *)"money_name_singular",		cf_string,	CA_GOD,		CA_PUBLIC,	(int *)&mudconf.one_coin,	SBUF_SIZE},
{(char *)"motd_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.motd_file,	MBUF_SIZE},
{(char *)"motd_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.motd_msg,	GBUF_SIZE},
{(char *)"move_match_more",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.move_match_more,	(long)"Move command checks for global and zone exits,\n\t\t\t\tresolves ambiguity"},
{(char *)"mud_name",			cf_string,	CA_GOD,		CA_PUBLIC,	(int *)&mudconf.mud_name,	SBUF_SIZE},
{(char *)"newuser_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.crea_file,	MBUF_SIZE},
{(char *)"no_ambiguous_match",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.no_ambiguous_match,	(long)"Ambiguous matches resolve to the last match"},
{(char *)"notify_recursion_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.ntfy_nest_lim,		0},
{(char *)"objeval_requires_control",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.fascist_objeval,	(long)"Control of victim required by objeval()"},
{(char *)"open_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.opencost,		0},
{(char *)"opt_frequency",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.dbopt_interval,	0},
{(char *)"output_limit",		cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.output_limit,		0},
{(char *)"page_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.pagecost,		0},
{(char *)"page_requires_equals",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.page_req_equals,	(long)"page command always requires an equals sign"},
{(char *)"paranoid_allocate",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.paranoid_alloc,	(long)"Buffer pools sanity-checked on alloc/free"},
{(char *)"parent_recursion_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.parent_nest_lim,	0},
{(char *)"paycheck",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.paycheck,		0},
{(char *)"pemit_far_players",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.pemit_players,		(long)"@pemit targets can be players in other locations"},
{(char *)"pemit_any_object",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.pemit_any,		(long)"@pemit targets can be objects in other locations"},
{(char *)"permit_site",			cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.access_list,	0},
{(char *)"player_aliases_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.max_player_aliases,	0},
{(char *)"player_flags",		cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.player_flags,	0},
{(char *)"player_listen",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.player_listen,		(long)"@listen and ^-monitors are checked on players"},
{(char *)"player_match_own_commands",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.match_mine_pl,		(long)"Players can match $-commands on themselves"},
{(char *)"player_name_spaces",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.name_spaces,		(long)"Player names can contain spaces"},
{(char *)"player_parent",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.player_parent,		NOTHING},
{(char *)"player_proto",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.player_proto,		NOTHING},
{(char *)"player_attr_defaults",	cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.player_defobj,		NOTHING},
{(char *)"player_queue_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.queuemax,		0},
{(char *)"player_quota",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.player_quota,		0},
{(char *)"player_starting_home",	cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.start_home,		NOTHING},
{(char *)"player_starting_room",	cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.start_room,		0},
{(char *)"port",			cf_int,		CA_STATIC,	CA_PUBLIC,	&mudconf.port,			0},
{(char *)"power_access",		cf_power_access,CA_GOD,		CA_DISABLED,	NULL,				0},
{(char *)"power_alias",			cf_alias,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.powers_htab,	(long)"Power"},
{(char *)"public_flags",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.pub_flags,		(long)"Flag information is public"},
{(char *)"queue_active_chunk",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.active_q_chunk,	0},
{(char *)"queue_idle_chunk",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.queue_chunk,		0},
{(char *)"quiet_look",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.quiet_look,		(long)"look shows public attributes in addition to @Desc"},
{(char *)"quiet_whisper",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.quiet_whisper,		(long)"whisper is quiet"},
{(char *)"quit_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.quit_file,	MBUF_SIZE},
{(char *)"quotas",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.quotas,		(long)"Quotas are enforced"},
{(char *)"raw_helpfile",		cf_raw_helpfile,CA_STATIC,	CA_DISABLED,	NULL,				0},
{(char *)"read_remote_desc",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.read_rem_desc,		(long)"@Desc is public, even to players not nearby"},
{(char *)"read_remote_name",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.read_rem_name,		(long)"Names are public, even to players not nearby"},
{(char *)"register_create_file",	cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.regf_file,	MBUF_SIZE},
{(char *)"register_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.register_limit,	0},
{(char *)"register_site",		cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.access_list,	H_REGISTRATION},
{(char *)"require_cmds_flag",		cf_bool,	CA_GOD, 	CA_PUBLIC,	(int *)&mudconf.req_cmds_flag,	(long)"Only objects with COMMANDS flag are searched\n\t\t\t\tfor $-commands"},
{(char *)"retry_limit",			cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.retry_limit,		0},
{(char *)"robot_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.robotcost,		0},
{(char *)"robot_flags",			cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.robot_flags,	0},
{(char *)"robot_speech",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.robot_speak,		(long)"Robots can speak in locations their owners do not\n\t\t\t\tcontrol"},
{(char *)"room_flags",			cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.room_flags,	0},
{(char *)"room_parent",			cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.room_parent,		NOTHING},
{(char *)"room_proto",			cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.room_proto,		NOTHING},
{(char *)"room_attr_defaults",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.room_defobj,		NOTHING},
{(char *)"room_quota",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.room_quota,		0},
{(char *)"sacrifice_adjust",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.sacadjust,		0},
{(char *)"sacrifice_factor",		cf_int_factor,		CA_GOD,		CA_PUBLIC,	&mudconf.sacfactor,		0},
{(char *)"safer_passwords",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.safer_passwords,	(long)"Passwords must satisfy minimum security standards"},
{(char *)"say_uses_comma",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.comma_say,		(long)"Say uses a grammatically-correct comma"},
{(char *)"say_uses_you",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.you_say,		(long)"Say uses You rather than the player name"},
{(char *)"search_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.searchcost,		0},
{(char *)"see_owned_dark",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.see_own_dark,		(long)"look shows DARK objects owned by you"},
{(char *)"signal_action",		cf_option,	CA_STATIC,	CA_GOD,		&mudconf.sig_action,		(long)sigactions_nametab},
{(char *)"site_chars",			cf_int,		CA_GOD,		CA_WIZARD,	&mudconf.site_chars,		MBUF_SIZE - 2},
{(char *)"space_compress",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.space_compress,	(long)"Multiple spaces are compressed to a single space"},
{(char *)"sql_database",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.sql_db,		MBUF_SIZE},
{(char *)"sql_host",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.sql_host,	MBUF_SIZE},
{(char *)"sql_username",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.sql_username,	MBUF_SIZE},
{(char *)"sql_password",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.sql_password,	MBUF_SIZE},
{(char *)"sql_reconnect",		cf_bool,	CA_GOD,		CA_WIZARD,	&mudconf.sql_reconnect,		(long)"SQL queries re-initiate dropped connections"},
{(char *)"stack_limit",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.stack_lim,		0},
{(char *)"starting_money",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.paystart,		0},
{(char *)"starting_quota",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.start_quota,		0},
{(char *)"starting_exit_quota",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.start_exit_quota,	0},
{(char *)"starting_player_quota",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.start_player_quota,	0},
{(char *)"starting_room_quota",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.start_room_quota,	0},
{(char *)"starting_thing_quota",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.start_thing_quota,	0},
{(char *)"status_file",			cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.status_file,	MBUF_SIZE},
{(char *)"stripped_flags",		cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.stripped_flags,	0},
{(char *)"structure_delimiter_string",	cf_string,	CA_GOD,		CA_PUBLIC,	(int *)&mudconf.struct_dstr,	0},
{(char *)"structure_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.struct_lim,		0},
{(char *)"suspect_site",		cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.suspect_list,	H_SUSPECT},
{(char *)"sweep_dark",			cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.sweep_dark,		(long)"@sweep works on Dark locations"},
{(char *)"switch_default_all",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.switch_df_all,		(long)"@switch default is /all, not /first"},
{(char *)"terse_shows_contents",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.terse_contents,	(long)"TERSE suppresses the contents list of a location"},
{(char *)"terse_shows_exits",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.terse_exits,		(long)"TERSE suppresses the exit list of a location"},
{(char *)"terse_shows_move_messages",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.terse_movemsg,		(long)"TERSE suppresses movement messages"},
{(char *)"text_home",			cf_string,	CA_STATIC, 	CA_GOD,		(int *)&mudconf.txthome,	MBUF_SIZE},
{(char *)"thing_flags",			cf_set_flags,	CA_GOD,		CA_DISABLED,	(int *)&mudconf.thing_flags,	0},
{(char *)"thing_parent",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.thing_parent,		NOTHING},
{(char *)"thing_proto",			cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.thing_proto,		NOTHING},
{(char *)"thing_attr_defaults",		cf_dbref,	CA_GOD,		CA_PUBLIC,	&mudconf.thing_defobj,		NOTHING},
{(char *)"thing_quota",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.thing_quota,		0},
{(char *)"timeslice",			cf_int_factor,		CA_GOD,		CA_PUBLIC,	&mudconf.timeslice,		0},
{(char *)"trace_output_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.trace_limit,		0},
{(char *)"trace_topdown",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.trace_topdown,		(long)"Trace output is top-down"},
{(char *)"trust_site",			cf_site,	CA_GOD,		CA_DISABLED,	(int *)&mudstate.suspect_list,	0},
{(char *)"typed_quotas",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.typed_quotas,		(long)"Quotas are enforced per object type"},
{(char *)"unowned_safe",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.safe_unowned,		(long)"Objects not owned by you are considered SAFE"},
{(char *)"user_attr_access",		cf_modify_bits,	CA_GOD,		CA_DISABLED,	&mudconf.vattr_flags,		(long)attraccess_nametab},
{(char *)"use_global_aconn",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.use_global_aconn,	(long)"Global @Aconnects and @Adisconnects are used"},
{(char *)"variables_limit",		cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.numvars_lim,		0},
{(char *)"visible_wizards",		cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.visible_wizzes,	(long)"DARK Wizards are hidden from WHO but not invisible"},
{(char *)"wait_cost",			cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.waitcost,		0},
{(char *)"wildcard_match_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.wild_times_lim,	0},
{(char *)"wizard_obeys_linklock",	cf_bool,	CA_GOD,		CA_PUBLIC,	&mudconf.wiz_obey_linklock,	(long)"Check LinkLock even if player can link to anything"},
{(char *)"wizard_motd_file",		cf_string,	CA_STATIC,	CA_GOD,		(int *)&mudconf.wizmotd_file,	MBUF_SIZE},
{(char *)"wizard_motd_message",		cf_string,	CA_GOD,		CA_WIZARD,	(int *)&mudconf.wizmotd_msg,	GBUF_SIZE},
{(char *)"zone_recursion_limit",	cf_int,		CA_GOD,		CA_PUBLIC,	&mudconf.zone_nest_lim,		0},
{ NULL,					NULL,		0,		0,		NULL,				0}};

/* *INDENT-ON* */

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

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

    if (!mudstate.standalone && !mudstate.initializing && !check_access(player, tp->flags)) {
	notify(player, NOPERM_MESSAGE);
	return (-1);
    }

    if (!mudstate.initializing) {
	buff = alloc_lbuf("cf_set");
	StringCopy(buff, ap);
    }
    i = tp->interpreter(tp->loc, ap, tp->extra, player, cp);
    if (!mudstate.initializing) {
	STARTLOG(LOG_CONFIGMODS, "CFG", "UPDAT")
	    log_name(player);
	    log_printf(" entered config directive: %s with args '%s'. Status: ", cp, strip_ansi(buff));
	    switch (i) {
		case 0:
		    log_printf("Success.");
		    break;
		case 1:
		    log_printf("Partial success.");
		    break;
		case -1:
		    log_printf("Failure.");
		    break;
		default:
		    log_printf("Strange.");
	    }
	ENDLOG
	free_lbuf(buff);
    }
    return i;
}

int cf_set(cp, ap, player)
char *cp, *ap;
dbref player;
{
	CONF *tp, *ctab;
	MODULE *mp;

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

	/* Make sure that if we're standalone, the paramaters we need to
	 * load module flatfiles are loaded */
	 
	if (mudstate.standalone && strcmp(cp, "module") && 
	    strcmp(cp, "database_home")) {
		return 0;
	}

	for (tp = conftable; tp->pname; tp++) {
		if (!strcmp(tp->pname, cp)) {
		    return (helper_cf_set(cp, ap, player, tp));
		}
	}

	WALK_ALL_MODULES(mp) {
	    if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
				  CONF *)) != NULL) {
		for (tp = ctab; tp->pname; tp++) {
		    if (!strcmp(tp->pname, cp))
			return (helper_cf_set(cp, ap, player, tp));
		}
	    }
	}

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

	if (!mudstate.standalone)
		cf_log_notfound(player, (char *)"Set", "Config directive", cp);

	return (-1);
}

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

void do_admin(player, cause, extra, kw, value)
dbref player, cause;
int extra;
char *kw, *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(fn)
char *fn;
{
	int retval;
	char tmpfile[256], *c;
	
	mudconf.config_file = XSTRDUP(fn, "cf_read.config_file");
	mudstate.initializing = 1;
	retval = cf_include(NULL, fn, 0, 0, (char *)"init");
	mudstate.initializing = 0;

	/* Fill in missing DB file names */

	strcpy(tmpfile, mudconf.gdbm);
	if ((c = strchr(tmpfile, '.')) != NULL)
		*c = '\0';
		
	if (!*mudconf.crashdb) {
		XFREE(mudconf.crashdb, "cf_read_crashdb");
		mudconf.crashdb = XSTRDUP(tprintf("%s.CRASH", tmpfile),
					  "cf_read_crashdb");
	}
	return retval;
}

/* ---------------------------------------------------------------------------
 * list_cf_access, list_cf_read_access: List write or read access to
 * config directives.
 */

void list_cf_access(player)
dbref player;
{
	CONF *tp, *ctab;
	char *buff;
	MODULE *mp;

	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);
		}
	}

	WALK_ALL_MODULES(mp) {
	    if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
				  CONF *)) != NULL) {	
		for (tp = ctab; 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);
}

void list_cf_read_access(player)
dbref player;
{
	CONF *tp, *ctab;
	char *buff;
	MODULE *mp;

	buff = alloc_mbuf("list_cf_read_access");

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

	WALK_ALL_MODULES(mp) {
	    if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
				  CONF *)) != NULL) {	
		for (tp = ctab; tp->pname; tp++) {
		    if (God(player) || check_access(player, tp->rperms)) {
			sprintf(buff, "%s:", tp->pname);
			listset_nametab(player, access_nametab, tp->rperms,
					buff, 1);
		    }
		}
	    }
	}

	free_mbuf(buff);
}

/* ---------------------------------------------------------------------------
 * cf_verify: Walk all configuration tables and validate any dbref values.
 */

#define Check_Conf_Dbref(x) \
if ((x)->interpreter == cf_dbref) { \
    if (!((((x)->extra == NOTHING) && (*((x)->loc) == NOTHING)) || \
	  (Good_obj(*((x)->loc)) && !Going(*((x)->loc))))) { \
	STARTLOG(LOG_ALWAYS, "CNF", "VRFY") \
	    log_printf("%s #%d is invalid. Reset to #%d.", \
		       (x)->pname, *((x)->loc), (x)->extra); \
	ENDLOG \
	*((x)->loc) = (dbref) (x)->extra; \
    } \
}

void cf_verify()
{
    CONF *tp, *ctab;
    MODULE *mp;

    for (tp = conftable; tp->pname; tp++) {
	Check_Conf_Dbref(tp);
    }

    WALK_ALL_MODULES(mp) {
	if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
			      CONF *)) != NULL) {
	    for (tp = ctab; tp->pname; tp++) {
		Check_Conf_Dbref(tp);
	    }
	}
    }
}

/* ---------------------------------------------------------------------------
 * cf_display: Given a config parameter by name, return its value in some
 * sane fashion.
 */

static void helper_cf_display(player, buff, bufc, tp)
    dbref player;
    char *buff, **bufc;
    CONF *tp;
{
    NAMETAB *opt;

    if (!check_access(player, tp->rperms)) {
	safe_noperm(buff, bufc);
	return;
    }
    if ((tp->interpreter == cf_bool) ||
	(tp->interpreter == cf_int) ||
	(tp->interpreter == cf_int_factor) ||
	(tp->interpreter == cf_const)) {
	safe_ltos(buff, bufc, *(tp->loc));
	return;
    }
    if ((tp->interpreter == cf_string)) {
	safe_str(*((char **)tp->loc), buff, bufc);
	return;
    }
    if ((tp->interpreter == cf_dbref)) {
	safe_dbref(buff, bufc, *(tp->loc));
	return;
    }
    if ((tp->interpreter == cf_option)) {
	opt = find_nametab_ent_flag(GOD, (NAMETAB *)tp->extra, *(tp->loc));
	safe_str((opt ? opt->name : "*UNKNOWN*"), buff, bufc);
	return;
    }
    safe_noperm(buff, bufc);
    return;
}

void cf_display(player, param_name, buff, bufc)
    dbref player;
    char *param_name;
    char *buff;
    char **bufc;
{
    CONF *tp, *ctab;
    MODULE *mp;

    for (tp = conftable; tp->pname; tp++) {
	if (!strcasecmp(tp->pname, param_name)) {
	    helper_cf_display(player, buff, bufc, tp);
	    return;
	}
    }

    WALK_ALL_MODULES(mp) {
	if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
			      CONF *)) != NULL) {	
	    for (tp = ctab; tp->pname; tp++) {
		if (!strcasecmp(tp->pname, param_name)) {
		    helper_cf_display(player, buff, bufc, tp);
		    return;
		}
	    }
	}
    }

    safe_nomatch(buff, bufc);
}

void list_options(player)
dbref player;
{
    CONF *tp, *ctab;
    MODULE *mp;

    for (tp = conftable; tp->pname; tp++) {
	if (((tp->interpreter == cf_const) ||
	     (tp->interpreter == cf_bool)) &&
	    (check_access(player, tp->rperms))) {

	    raw_notify(player, tprintf("%-25s %c %s?",
				       tp->pname,
				       (*(tp->loc) ? 'Y' : 'N'),
				       (tp->extra ? (char *)tp->extra : "")));
	}
    }

    WALK_ALL_MODULES(mp) {
	if ((ctab = DLSYM_VAR(mp->handle, mp->modname, "conftable",
			      CONF *)) != NULL) {
	    for (tp = ctab; tp->pname; tp++) {
		if (((tp->interpreter == cf_const) ||
		     (tp->interpreter == cf_bool)) &&
		    (check_access(player, tp->rperms))) {

		    raw_notify(player, tprintf("%-25s %c %s?",
					       tp->pname,
					       (*(tp->loc) ? 'Y' : 'N'),
				       (tp->extra ? (char *)tp->extra : "")));
		}
	    }
	}
    }
}