btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * db.c 
 */

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

#include <sys/file.h>
#include <sys/stat.h>

#define __DB_C
#include "mudconf.h"
#include "config.h"
#include "externs.h"
#include "db.h"
#include "attrs.h"
#include "vattr.h"
#include "match.h"
#include "alloc.h"
#include "powers.h"
#include "interface.h"
#include "flags.h"
#include "p.comsys.h"
#include "mmdb.h"

#ifndef O_ACCMODE
#define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
#endif

/*
 * Restart definitions 
 */
#define RS_CONCENTRATE		0x00000002
#define RS_RECORD_PLAYERS	0x00000004
#define RS_NEW_STRINGS		0x00000008
#define RS_HUDKEY		0x00000010

OBJ *db = NULL;
NAME *names = NULL;
NAME *purenames = NULL;

int corrupt;

extern void desc_addhash(DESC *);
extern void del_commac(dbref);
extern void do_clear_macro(dbref player, char *s);

#ifdef TEST_MALLOC
int malloc_count = 0;

#endif /*
	    * * TEST_MALLOC  
	    */

extern VATTR *vattr_rename(char *, char *);

typedef struct atrcount ATRCOUNT;
struct atrcount {
	dbref thing;
	int count;
};

/*
 * #define GNU_MALLOC_TEST 1 
 */

#ifdef GNU_MALLOC_TEST
extern unsigned int malloc_sbrk_used;	/* Amount of data space used now */
#endif

/*
 * Check routine forward declaration. 
 */
extern int fwdlist_ck(int, dbref, dbref, int, char *);

extern void pcache_reload(dbref);
extern void desc_reload(dbref);

/*
 * list of attributes 
 */
ATTR attr[] = {
	{"Aahear", A_AAHEAR, AF_ODARK, NULL},
	{"Aclone", A_ACLONE, AF_ODARK, NULL},
	{"Aconnect", A_ACONNECT, AF_ODARK, NULL},
	{"Adesc", A_ADESC, AF_ODARK, NULL},
	{"Adfail", A_ADFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Adisconnect", A_ADISCONNECT, AF_ODARK, NULL},
	{"Adrop", A_ADROP, AF_ODARK, NULL},
	{"Aefail", A_AEFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Aenter", A_AENTER, AF_ODARK, NULL},
	{"Afail", A_AFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Agfail", A_AGFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Ahear", A_AHEAR, AF_ODARK, NULL},
	{"Akill", A_AKILL, AF_ODARK, NULL},
	{"Aleave", A_ALEAVE, AF_ODARK, NULL},
	{"Alfail", A_ALFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Alias", A_ALIAS, AF_NOPROG | AF_NOCMD | AF_GOD, NULL},
	{"Allowance", A_ALLOWANCE, AF_MDARK | AF_NOPROG | AF_WIZARD, NULL},
	{"Amail", A_AMAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Amhear", A_AMHEAR, AF_ODARK, NULL},
	{"Amove", A_AMOVE, AF_ODARK, NULL},
	{"Apay", A_APAY, AF_ODARK, NULL},
	{"Arfail", A_ARFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Asucc", A_ASUCC, AF_ODARK, NULL},
	{"Atfail", A_ATFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Atport", A_ATPORT, AF_ODARK | AF_NOPROG, NULL},
	{"Atofail", A_ATOFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Aufail", A_AUFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Ause", A_AUSE, AF_ODARK, NULL},
	{"Away", A_AWAY, AF_ODARK | AF_NOPROG, NULL},
	{"Buildcoord", A_BUILDCOORD, AF_MDARK | AF_WIZARD, NULL},
	{"Buildentrance", A_BUILDENTRANCE, AF_MDARK | AF_WIZARD, NULL},
	{"Buildlinks", A_BUILDLINKS, AF_MDARK | AF_WIZARD, NULL},
	{"Charges", A_CHARGES, AF_ODARK | AF_NOPROG, NULL},
	{"Comment", A_COMMENT, AF_MDARK | AF_WIZARD, NULL},
	{"Contactoptions", A_CONTACTOPT, AF_ODARK, NULL},
	{"Cost", A_COST, AF_ODARK, NULL},
	{"Daily", A_DAILY, AF_ODARK, NULL},
	{"HHourly", A_HOURLY, AF_MDARK, NULL},
	{"Desc", A_DESC, AF_NOPROG, NULL},
	{"DefaultLock", A_LOCK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Destroyer", A_DESTROYER, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL},
	{"Dfail", A_DFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Drop", A_DROP, AF_ODARK | AF_NOPROG, NULL},
	{"DropLock", A_LDROP, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Ealias", A_EALIAS, AF_ODARK | AF_NOPROG, NULL},
	{"Efail", A_EFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Enter", A_ENTER, AF_ODARK, NULL},
	{"EnterLock", A_LENTER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Faction", A_FACTION, AF_MDARK | AF_WIZARD, NULL},
	{"Fail", A_FAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Filter", A_FILTER, AF_ODARK | AF_NOPROG, NULL},
	{"Forwardlist", A_FORWARDLIST, AF_ODARK | AF_NOPROG, fwdlist_ck},
	{"Gfail", A_GFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"GiveLock", A_LGIVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Heatchars", A_HEATCHARS, AF_ODARK, NULL},
	{"Idesc", A_IDESC, AF_ODARK | AF_NOPROG, NULL},
	{"Idle", A_IDLE, AF_ODARK | AF_NOPROG, NULL},
	{"Infilter", A_INFILTER, AF_ODARK | AF_NOPROG, NULL},
	{"Inprefix", A_INPREFIX, AF_ODARK | AF_NOPROG, NULL},
	{"Job", A_JOB, AF_MDARK | AF_WIZARD, NULL},
	{"Kill", A_KILL, AF_ODARK, NULL},
	{"Lalias", A_LALIAS, AF_ODARK | AF_NOPROG, NULL},
	{"Last", A_LAST, AF_WIZARD | AF_NOCMD | AF_NOPROG, NULL},
	{"Lastname", A_LASTNAME, AF_WIZARD | AF_NOPROG | AF_MDARK, NULL},
	{"Lastpage", A_LASTPAGE,
	 AF_INTERNAL | AF_NOCMD | AF_NOPROG | AF_GOD | AF_PRIVATE, NULL},
	{"Lastsite", A_LASTSITE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_GOD,
	 NULL},
	{"Leave", A_LEAVE, AF_ODARK, NULL},
	{"LeaveLock", A_LLEAVE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Lfail", A_LFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"LinkLock", A_LLINK, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Listen", A_LISTEN, AF_ODARK, NULL},

	{"Logindata", A_LOGINDATA,
	 AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL, NULL},
	{"LRSheight", A_LRSHEIGHT, AF_ODARK, NULL},
	{"Unused1", A_UNUSED1, AF_WIZARD | AF_MDARK, NULL},
	{"Mailcurf", A_MAILCURF, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL},
	{"Mailflags", A_MAILFLAGS, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL},
	{"Mailfolders", A_MAILFOLDERS, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL},
	{"Mailmsg", A_MAILMSG, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"Mailsub", A_MAILSUB, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"Mailsucc", A_MAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Mailto", A_MAILTO, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"Mapcolor", A_MAPCOLOR, AF_ODARK, NULL},
	{"Mapvis", A_MAPVIS, AF_MDARK | AF_WIZARD, NULL},
	{"Mechdesc", A_MECHDESC, AF_MDARK, NULL},
	{"Mechname", A_MECHNAME, AF_MDARK, NULL},
	{"Mechstatus", A_MECHSTATUS, AF_MDARK | AF_WIZARD, NULL},
	{"Mechtype", A_MECHTYPE, AF_MDARK, NULL},
	{"MechPrefID", A_MECHPREFID, AF_MDARK | AF_WIZARD, NULL},
	{"Mechskills", A_MECHSKILLS, AF_MDARK, NULL},
	{"Mwtemplate", A_MWTEMPLATE, AF_MDARK, NULL},
	{"Move", A_MOVE, AF_ODARK, NULL},
	{"Name", A_NAME, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"Odesc", A_ODESC, AF_ODARK | AF_NOPROG, NULL},
	{"Odfail", A_ODFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Odrop", A_ODROP, AF_ODARK | AF_NOPROG, NULL},
	{"Oefail", A_OEFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Oenter", A_OENTER, AF_ODARK, NULL},
	{"Ofail", A_OFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Ogfail", A_OGFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Okill", A_OKILL, AF_ODARK, NULL},
	{"Amechdest", A_AMECHDEST, AF_MDARK, NULL},
	{"Oleave", A_OLEAVE, AF_ODARK, NULL},
	{"Olfail", A_OLFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Omove", A_OMOVE, AF_ODARK, NULL},
	{"Opay", A_OPAY, AF_ODARK, NULL},
	{"Orfail", A_ORFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Osucc", A_OSUCC, AF_ODARK | AF_NOPROG, NULL},
	{"Otfail", A_OTFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Otport", A_OTPORT, AF_ODARK | AF_NOPROG, NULL},
	{"Otofail", A_OTOFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Oufail", A_OUFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Ouse", A_OUSE, AF_ODARK, NULL},
	{"Oxenter", A_OXENTER, AF_ODARK, NULL},
	{"Oxleave", A_OXLEAVE, AF_ODARK, NULL},
	{"Oxtport", A_OXTPORT, AF_ODARK | AF_NOPROG, NULL},
	{"PageLock", A_LPAGE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"ParentLock", A_LPARENT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Pay", A_PAY, AF_ODARK, NULL},
	{"PCequip", A_PCEQUIP, AF_MDARK, NULL},
	{"Pilot", A_PILOTNUM, AF_MDARK, NULL},
	{"Prefix", A_PREFIX, AF_ODARK | AF_NOPROG, NULL},
	{"ProgCmd", A_PROGCMD, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"QueueMax", A_QUEUEMAX, AF_MDARK | AF_WIZARD | AF_NOPROG, NULL},
	{"Quota", A_QUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD, NULL},
	{"Ranknum", A_RANKNUM, AF_MDARK | AF_WIZARD, NULL},
	{"ReceiveLock", A_LRECEIVE,
	 AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Reject", A_REJECT, AF_ODARK | AF_NOPROG, NULL},
	{"Rfail", A_RFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Rquota", A_RQUOTA, AF_MDARK | AF_NOPROG | AF_GOD | AF_NOCMD, NULL},
	{"Runout", A_RUNOUT, AF_ODARK, NULL},

	{"Semaphore", A_SEMAPHORE,
	 AF_ODARK | AF_NOPROG | AF_WIZARD | AF_NOCMD, NULL},
	{"Sex", A_SEX, AF_NOPROG, NULL},
	{"Signature", A_SIGNATURE, AF_ODARK | AF_NOPROG, NULL},
	{"SpeechLock", A_LSPEECH, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Startup", A_STARTUP, AF_ODARK, NULL},
	{"Succ", A_SUCC, AF_ODARK | AF_NOPROG, NULL},
	{"Tacsize", A_TACSIZE, AF_ODARK, NULL},
	{"TeloutLock", A_LTELOUT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Tfail", A_TFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Timeout", A_TIMEOUT, AF_MDARK | AF_NOPROG | AF_WIZARD, NULL},
	{"Tport", A_TPORT, AF_ODARK | AF_NOPROG, NULL},
	{"TportLock", A_LTPORT, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"Tofail", A_TOFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Tz", A_TZ, AF_NOPROG, NULL},
	{"Ufail", A_UFAIL, AF_ODARK | AF_NOPROG, NULL},
	{"Use", A_USE, AF_ODARK, NULL},
	{"UseLock", A_LUSE, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"UserLock", A_LUSER, AF_ODARK | AF_NOPROG | AF_NOCMD | AF_IS_LOCK,
	 NULL},
	{"VA", A_VA, AF_ODARK, NULL},
	{"VB", A_VA + 1, AF_ODARK, NULL},
	{"VC", A_VA + 2, AF_ODARK, NULL},
	{"VD", A_VA + 3, AF_ODARK, NULL},
	{"VE", A_VA + 4, AF_ODARK, NULL},
	{"VF", A_VA + 5, AF_ODARK, NULL},
	{"VG", A_VA + 6, AF_ODARK, NULL},
	{"VH", A_VA + 7, AF_ODARK, NULL},
	{"VI", A_VA + 8, AF_ODARK, NULL},
	{"VJ", A_VA + 9, AF_ODARK, NULL},
	{"VK", A_VA + 10, AF_ODARK, NULL},
	{"VL", A_VA + 11, AF_ODARK, NULL},
	{"VM", A_VA + 12, AF_ODARK, NULL},
	{"VN", A_VA + 13, AF_ODARK, NULL},
	{"VO", A_VA + 14, AF_ODARK, NULL},
	{"VP", A_VA + 15, AF_ODARK, NULL},
	{"VQ", A_VA + 16, AF_ODARK, NULL},
	{"VR", A_VA + 17, AF_ODARK, NULL},
	{"VS", A_VA + 18, AF_ODARK, NULL},
	{"VT", A_VA + 19, AF_ODARK, NULL},
	{"VU", A_VA + 20, AF_ODARK, NULL},
	{"VV", A_VA + 21, AF_ODARK, NULL},
	{"VW", A_VA + 22, AF_ODARK, NULL},
	{"VX", A_VA + 23, AF_ODARK, NULL},
	{"VY", A_VA + 24, AF_ODARK, NULL},
	{"VZ", A_VA + 25, AF_ODARK, NULL},
	{"Xtype", A_XTYPE, AF_MDARK | AF_WIZARD, NULL},
	{"*Password", A_PASS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"*Privileges", A_PRIVS, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"*Money", A_MONEY, AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
	{"Techtime", A_TECHTIME, AF_MDARK | AF_WIZARD,
	 NULL},
	{"*EconParts", A_ECONPARTS,
	 AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL,
	 NULL},
#if 1
#define PLSTAT_MODE (AF_DARK | AF_NOPROG | AF_NOCMD | AF_INTERNAL)
#else
#define PLSTAT_MODE (AF_MDARK|AF_WIZARD)
#endif
	{"PLHEALTH", A_HEALTH, PLSTAT_MODE, NULL},
	{"PLATTRS", A_ATTRS, PLSTAT_MODE, NULL},
	{"PLADVS", A_ADVS, PLSTAT_MODE, NULL},
	{"PLSKILLS", A_SKILLS, PLSTAT_MODE, NULL},

	{NULL, 0, 0, NULL}
};

/*
 * ---------------------------------------------------------------------------
 * * fwdlist_set, fwdlist_clr: Manage cached forwarding lists
 */
void fwdlist_set(dbref thing, FWDLIST * ifp)
{
	FWDLIST *fp, *xfp;
	int i;

	/*
	 * If fwdlist is null, clear 
	 */

	if(!ifp || (ifp->count <= 0)) {
		fwdlist_clr(thing);
		return;
	}
	/*
	 * Copy input forwardlist to a correctly-sized buffer 
	 */

	fp = (FWDLIST *) XMALLOC(sizeof(int) * ((ifp->count) + 1), "fwdlist_set");

	for(i = 0; i < ifp->count; i++) {
		fp->data[i] = ifp->data[i];
	}
	fp->count = ifp->count;

	/*
	 * Replace an existing forwardlist, or add a new one 
	 */

	xfp = fwdlist_get(thing);
	if(xfp) {
		XFREE(xfp, "fwdlist_set");
		nhashrepl(thing, (int *) fp, &mudstate.fwdlist_htab);
	} else {
		nhashadd(thing, (int *) fp, &mudstate.fwdlist_htab);
	}
}

void fwdlist_clr(dbref thing)
{
	FWDLIST *xfp;

	/*
	 * If a forwardlist exists, delete it 
	 */

	xfp = fwdlist_get(thing);
	if(xfp) {
		XFREE(xfp, "fwdlist_clr");
		nhashdelete(thing, &mudstate.fwdlist_htab);
	}
}

/*
 * ---------------------------------------------------------------------------
 * * fwdlist_load: Load text into a forwardlist.
 */
int fwdlist_load(FWDLIST * fp, dbref player, char *atext)
{
	dbref target;
	char *tp, *bp, *dp;
	int count, errors, fail;

	count = 0;
	errors = 0;
	bp = tp = alloc_lbuf("fwdlist_load.str");
	StringCopy(tp, atext);
	do {
		for(; *bp && isspace(*bp); bp++);	/*
											 * skip spaces 
											 */
		for(dp = bp; *bp && !isspace(*bp); bp++);	/*
													 * remember * 
													 * 
													 * *  * *  *
													 * *  * * * * 
													 * string  
													 */
		if(*bp)
			*bp++ = '\0';		/*
								 * terminate string 
								 */
		if((*dp++ == '#') && isdigit(*dp)) {
			target = atoi(dp);
			fail = (!Good_obj(target) || (!God(player) &&
										  !controls(player, target)
										  && (!Link_ok(target)
											  || !could_doit(player, target,
															 A_LLINK))));
			if(fail) {
				notify_printf(player,
							  "Cannot forward to #%d: Permission denied.",
							  target);
				errors++;
			} else {
				fp->data[count++] = target;
			}
		}
	} while (*bp);
	free_lbuf(tp);
	fp->count = count;
	return errors;
}

/*
 * ---------------------------------------------------------------------------
 * * fwdlist_rewrite: Generate a text string from a FWDLIST buffer.
 */
int fwdlist_rewrite(FWDLIST * fp, char *atext)
{
	char *tp, *bp;
	int i, count;

	if(fp && fp->count) {
		count = fp->count;
		tp = alloc_sbuf("fwdlist_rewrite.errors");
		bp = atext;
		for(i = 0; i < fp->count; i++) {
			if(Good_obj(fp->data[i])) {
				sprintf(tp, "#%d ", fp->data[i]);
				safe_str(tp, atext, &bp);
			} else {
				count--;
			}
		}
		*bp = '\0';
		free_sbuf(tp);
	} else {
		count = 0;
		*atext = '\0';
	}
	return count;
}

/*
 * ---------------------------------------------------------------------------
 * * fwdlist_ck:  Check a list of dbref numbers to forward to for AUDIBLE
 */

int fwdlist_ck(int key, dbref player, dbref thing, int anum, char *atext)
{
	FWDLIST *fp;
	int count;

	count = 0;

	if(atext && *atext) {
		fp = (FWDLIST *) alloc_lbuf("fwdlist_ck.fp");
		fwdlist_load(fp, player, atext);
	} else {
		fp = NULL;
	}

	/*
	 * Set the cached forwardlist 
	 */

	fwdlist_set(thing, fp);
	count = fwdlist_rewrite(fp, atext);
	if(fp)
		free_lbuf(fp);
	return ((count > 0) || !atext || !*atext);
}

FWDLIST *fwdlist_get(dbref thing)
{
	FWDLIST *fp;

	fp = ((FWDLIST *) nhashfind(thing, &mudstate.fwdlist_htab));

	return fp;
}

static char *set_string(char **ptr, char *new)
{
	/*
	 * if pointer not null unalloc it 
	 */

	if(*ptr)
		XFREE(*ptr, "set_string");

	/*
	 * if new string is not null allocate space for it and copy it 
	 */

	if(!new)					/*
								 * * || !*new  
								 */
		return (*ptr = NULL);	/*
								 * Check with GAC about this 
								 */
	*ptr = (char *) XMALLOC(strlen(new) + 1, "set_string");
	StringCopy(*ptr, new);
	return (*ptr);
}

/*
 * ---------------------------------------------------------------------------
 * * Name, s_Name: Get or set an object's name.
 */
INLINE char *Name(dbref thing)
{
	dbref aowner;
	int aflags;
	char *buff;
	static char *tbuff[MBUF_SIZE];
	char buffer[MBUF_SIZE];

	if(mudconf.cache_names) {
		if(thing > mudstate.db_top || thing < 0) {
			return "#-1 INVALID DBREF";
		}
		if(!purenames[thing]) {
			buff = atr_get(thing, A_NAME, &aowner, &aflags);
			strip_ansi_r(buffer, buff, MBUF_SIZE);
			set_string(&purenames[thing], buffer);
			free_lbuf(buff);
		}
	}

	atr_get_str((char *) tbuff, thing, A_NAME, &aowner, &aflags);
	return ((char *) tbuff);
}

INLINE char *PureName(dbref thing)
{
	dbref aowner;
	int aflags;
	char *buff;
	static char *tbuff[LBUF_SIZE];

	if(mudconf.cache_names) {
		if(thing > mudstate.db_top || thing < 0) {
			return "#-1 INVALID DBREF";
		}
		if(!purenames[thing]) {
			buff = atr_get(thing, A_NAME, &aowner, &aflags);
			set_string(&purenames[thing], strip_ansi(buff));
			free_lbuf(buff);
		}
		return purenames[thing];
	}

	atr_get_str((char *) tbuff, thing, A_NAME, &aowner, &aflags);
	return (strip_ansi((char *) tbuff));
}

INLINE void s_Name(dbref thing, char *s)
{
	/* Truncate the name if we have to */

	if(s && (strlen(s) > MBUF_SIZE))
		s[MBUF_SIZE] = '\0';

	atr_add_raw(thing, A_NAME, (char *) s);

	if(mudconf.cache_names) {
		set_string(&purenames[thing], strip_ansi((char *) s));
	}
}

void s_Pass(dbref thing, const char *s)
{
	atr_add_raw(thing, A_PASS, (char *) s);
}

/*
 * ---------------------------------------------------------------------------
 * * do_attrib: Manage user-named attributes.
 */

extern NAMETAB attraccess_nametab[];

void do_attribute(dbref player, dbref cause, int key, char *aname,
				  char *value)
{
	int success, negate, f;
	char *buff, *sp, *p, *q;
	VATTR *va;
	ATTR *va2;

	/*
	 * Look up the user-named attribute we want to play with 
	 */

	buff = alloc_sbuf("do_attribute");
	for(p = buff, q = aname; *q && ((p - buff) < (SBUF_SIZE - 1)); p++, q++)
		*p = ToUpper(*q);
	*p = '\0';

	va = (VATTR *) vattr_find(buff);
	if(!va) {
		notify(player, "No such user-named attribute.");
		free_sbuf(buff);
		return;
	}
	switch (key) {
	case ATTRIB_ACCESS:

		/*
		 * Modify access to user-named attribute 
		 */

		for(sp = value; *sp; sp++)
			*sp = ToUpper(*sp);
		sp = strtok(value, " ");
		success = 0;
		while (sp != NULL) {

			/*
			 * Check for negation 
			 */

			negate = 0;
			if(*sp == '!') {
				negate = 1;
				sp++;
			}
			/*
			 * Set or clear the appropriate bit 
			 */

			f = search_nametab(player, attraccess_nametab, sp);
			if(f > 0) {
				success = 1;
				if(negate)
					va->flags &= ~f;
				else
					va->flags |= f;
			} else {
				notify_printf(player, "Unknown permission: %s.", sp);
			}

			/*
			 * Get the next token 
			 */

			sp = strtok(NULL, " ");
		}
		if(success && !Quiet(player))
			notify(player, "Attribute access changed.");
		break;

	case ATTRIB_RENAME:

		/*
		 * Make sure the new name doesn't already exist 
		 */

		va2 = atr_str(value);
		if(va2) {
			notify(player, "An attribute with that name already exists.");
			free_sbuf(buff);
			return;
		}
		if(vattr_rename(va->name, value) == NULL)
			notify(player, "Attribute rename failed.");
		else
			notify(player, "Attribute renamed.");
		break;

	case ATTRIB_DELETE:

		/*
		 * Remove the attribute 
		 */

		vattr_delete(buff);
		notify(player, "Attribute deleted.");
		break;
	}
	free_sbuf(buff);
	return;
}

/*
 * ---------------------------------------------------------------------------
 * * do_fixdb: Directly edit database fields
 */

void do_fixdb(dbref player, dbref cause, int key, char *arg1, char *arg2)
{
	dbref thing, res;

	init_match(player, arg1, NOTYPE);
	match_everything(0);
	thing = noisy_match_result();
	if(thing == NOTHING)
		return;

	res = NOTHING;
	switch (key) {
	case FIXDB_OWNER:
	case FIXDB_LOC:
	case FIXDB_CON:
	case FIXDB_EXITS:
	case FIXDB_NEXT:
		init_match(player, arg2, NOTYPE);
		match_everything(0);
		res = noisy_match_result();
		break;
	case FIXDB_PENNIES:
		res = atoi(arg2);
		break;
	}

	switch (key) {
	case FIXDB_OWNER:
		s_Owner(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Owner set to #%d", res);
		break;
	case FIXDB_LOC:
		s_Location(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Location set to #%d", res);
		break;
	case FIXDB_CON:
		s_Contents(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Contents set to #%d", res);
		break;
	case FIXDB_EXITS:
		s_Exits(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Exits set to #%d", res);
		break;
	case FIXDB_NEXT:
		s_Next(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Next set to #%d", res);
		break;
	case FIXDB_PENNIES:
		s_Pennies(thing, res);
		if(!Quiet(player))
			notify_printf(player, "Pennies set to %d", res);
		break;
	case FIXDB_NAME:
		if(Typeof(thing) == TYPE_PLAYER) {
			if(!ok_player_name(arg2)) {
				notify(player, "That's not a good name for a player.");
				return;
			}
			if(lookup_player(NOTHING, arg2, 0) != NOTHING) {
				notify(player, "That name is already in use.");
				return;
			}
			STARTLOG(LOG_SECURITY, "SEC", "CNAME") {
				log_name(thing), log_text((char *) " renamed to ");
				log_text(arg2);
				ENDLOG;
			} if(Suspect(player)) {
				send_channel("Suspect", "%s renamed to %s",
							 Name(thing), arg2);
			}
			delete_player_name(thing, Name(thing));

			s_Name(thing, arg2);
			add_player_name(thing, arg2);
		} else {
			if(!ok_name(arg2)) {
				notify(player, "Warning: That is not a reasonable name.");
			}
			s_Name(thing, arg2);
		}
		if(!Quiet(player))
			notify_printf(player, "Name set to %s", arg2);
		break;
	}
}

/*
 * ---------------------------------------------------------------------------
 * * init_attrtab: Initialize the attribute hash tables.
 */

void init_attrtab(void)
{
	ATTR *a;
	char *buff, *p, *q;

	hashinit(&mudstate.attr_name_htab, 512);
	buff = alloc_sbuf("init_attrtab");
	for(a = attr; a->number; a++) {
		anum_extend(a->number);
		anum_set(a->number, a);
		for(p = buff, q = (char *) a->name; *q; p++, q++)
			*p = ToUpper(*q);
		*p = '\0';
		hashadd(buff, (int *) a, &mudstate.attr_name_htab);
	}
	free_sbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * atr_str: Look up an attribute by name.
 */

ATTR *atr_str(char *s)
{
	char *buff, *p, *q;
	ATTR *a;
	VATTR *va;
	static ATTR tattr;

	if(!s || !*s) {
		return (NULL);
	}

	/*
	 * Convert the buffer name to lowercase 
	 */

	buff = alloc_sbuf("atr_str");
	for(p = buff, q = s; *q && ((p - buff) < (SBUF_SIZE - 1)); p++, q++)
		*p = ToUpper(*q);
	*p = '\0';

	/*
	 * Look for a predefined attribute 
	 */

	a = (ATTR *) hashfind(buff, &mudstate.attr_name_htab);
	if(a != NULL) {
		free_sbuf(buff);
		return a;
	}
	/*
	 * Nope, look for a user attribute 
	 */

	va = (VATTR *) vattr_find(buff);
	free_sbuf(buff);

	/*
	 * If we got one, load tattr and return a pointer to it. 
	 */

	if(va != NULL) {
		tattr.name = va->name;
		tattr.number = va->number;
		tattr.flags = va->flags;
		tattr.check = NULL;
		return &tattr;
	}
	/*
	 * All failed, return NULL 
	 */

	return NULL;
}

/*
 * ---------------------------------------------------------------------------
 * * anum_extend: Grow the attr num lookup table.
 */

ATTR **anum_table = NULL;
int anum_alc_top = 0;

void anum_extend(int newtop)
{
	ATTR **anum_table2;
	int delta, i;

	delta = mudconf.init_size;

	if(newtop <= anum_alc_top)
		return;
	if(newtop < anum_alc_top + delta)
		newtop = anum_alc_top + delta;
	if(anum_table == NULL) {
		anum_table = (ATTR **) malloc((newtop + 1) * sizeof(ATTR *));
		for(i = 0; i <= newtop; i++)
			anum_table[i] = NULL;
	} else {
		anum_table2 = (ATTR **) malloc((newtop + 1) * sizeof(ATTR *));
		for(i = 0; i <= anum_alc_top; i++)
			anum_table2[i] = anum_table[i];
		for(i = anum_alc_top + 1; i <= newtop; i++)
			anum_table2[i] = NULL;
		free((char *) anum_table);
		anum_table = anum_table2;
	}
	anum_alc_top = newtop;
}

/*
 * ---------------------------------------------------------------------------
 * * atr_num: Look up an attribute by number.
 */

ATTR *atr_num(int anum)
{
	VATTR *va;
	static ATTR tattr;

	/*
	 * Look for a predefined attribute 
	 */

	if(anum < A_USER_START)
		return anum_get(anum);

	if(anum >= anum_alc_top)
		return NULL;

	/*
	 * It's a user-defined attribute, we need to copy data 
	 */

	va = (VATTR *) anum_get(anum);
	if(va != NULL) {
		tattr.name = va->name;
		tattr.number = va->number;
		tattr.flags = va->flags;
		tattr.check = NULL;
		return &tattr;
	}
	/*
	 * All failed, return NULL 
	 */

	return NULL;
}

/*
 * ---------------------------------------------------------------------------
 * * mkattr: Lookup attribute by name, creating if needed.
 */

int mkattr(char *buff)
{
	ATTR *ap;
	VATTR *va;

	if(!(ap = atr_str(buff))) {

		/*
		 * Unknown attr, create a new one 
		 */

		va = vattr_alloc(buff, mudconf.vattr_flags);
		if(!va || !(va->number))
			return -1;
		return va->number;
	}
	if(!(ap->number))
		return -1;
	return ap->number;
}

/*
 * ---------------------------------------------------------------------------
 * * Commer: check if an object has any $-commands in its attributes.
 */

int Commer(dbref thing)
{
	char *s, *as, c;
	int attr, aflags;
	dbref aowner;
	ATTR *ap;

	for(attr = atr_head(thing, &as); attr; attr = atr_next(&as)) {
		ap = atr_num(attr);
		if(!ap || (ap->flags & AF_NOPROG))
			continue;

		s = atr_get(thing, attr, &aowner, &aflags);
		c = *s;
		free_lbuf(s);
		if((c == '$') && !(aflags & AF_NOPROG)) {
			return 1;
		}
	}
	return 0;
}

/*
 * routines to handle object attribute lists 
 */

/*
 * ---------------------------------------------------------------------------
 * * atr_encode: Encode an attribute string.
 */
static char *atr_encode(char *iattr, dbref thing, dbref owner, int flags,
						int atr)
{

	/*
	 * If using the default owner and flags (almost all attributes will),
	 * * * * * * * just store the string. 
	 */

	if(((owner == Owner(thing)) || (owner == NOTHING)) && !flags)
		return iattr;

	/*
	 * Encode owner and flags into the attribute text 
	 */

	if(owner == NOTHING)
		owner = Owner(thing);
	return tprintf("%c%d:%d:%s", ATR_INFO_CHAR, owner, flags, iattr);
}

/*
 * ---------------------------------------------------------------------------
 * * atr_decode: Decode an attribute string.
 */

static void atr_decode(char *iattr, char *oattr, dbref thing, dbref * owner,
					   int *flags, int atr)
{
	char *cp;
	int neg;

	/*
	 * See if the first char of the attribute is the special character 
	 */

	if(*iattr == ATR_INFO_CHAR) {

		/*
		 * It is, crack the attr apart 
		 */

		cp = &iattr[1];

		/*
		 * Get the attribute owner 
		 */

		*owner = 0;
		neg = 0;
		if(*cp == '-') {
			neg = 1;
			cp++;
		}
		while (isdigit(*cp)) {
			*owner = (*owner * 10) + (*cp++ - '0');
		}
		if(neg)
			*owner = 0 - *owner;

		/*
		 * If delimiter is not ':', just return attribute 
		 */

		if(*cp++ != ':') {
			*owner = Owner(thing);
			*flags = 0;
			if(oattr) {
				StringCopy(oattr, iattr);
			}
			return;
		}
		/*
		 * Get the attribute flags 
		 */

		*flags = 0;
		while (isdigit(*cp)) {
			*flags = (*flags * 10) + (*cp++ - '0');
		}

		/*
		 * If delimiter is not ':', just return attribute 
		 */

		if(*cp++ != ':') {
			*owner = Owner(thing);
			*flags = 0;
			if(oattr) {
				StringCopy(oattr, iattr);
			}
		}
		/*
		 * Get the attribute text 
		 */

		if(oattr) {
			StringCopy(oattr, cp);
		}
		if(*owner == NOTHING)
			*owner = Owner(thing);
	} else {

		/*
		 * Not the special character, return normal info 
		 */

		*owner = Owner(thing);
		*flags = 0;
		if(oattr) {
			StringCopy(oattr, iattr);
		}
	}
}

/*
 * ---------------------------------------------------------------------------
 * * atr_clr: clear an attribute in the list.
 */

void atr_clr(dbref thing, int atr)
{
	ATRLIST *list;
	int hi, lo, mid;

	if(!db[thing].at_count || !db[thing].ahead)
		return;

	if(db[thing].at_count < 0)
		abort();

	/*
	 * Binary search for the attribute. 
	 */
	lo = 0;
	hi = db[thing].at_count - 1;
	list = db[thing].ahead;
	while (lo <= hi) {
		mid = ((hi - lo) >> 1) + lo;
		if(list[mid].number == atr) {
			free(list[mid].data);
			db[thing].at_count -= 1;
			if(mid != db[thing].at_count)
				bcopy((char *) (list + mid + 1), (char *) (list + mid),
					  (db[thing].at_count - mid) * sizeof(ATRLIST));
			break;
		} else if(list[mid].number > atr) {
			hi = mid - 1;
		} else {
			lo = mid + 1;
		}
	}

	switch (atr) {
	case A_STARTUP:
		s_Flags(thing, Flags(thing) & ~HAS_STARTUP);
		break;
	case A_DAILY:
		s_Flags2(thing, Flags2(thing) & ~HAS_DAILY);
		break;
	case A_HOURLY:
		s_Flags2(thing, Flags2(thing) & ~HAS_HOURLY);
		break;
	case A_FORWARDLIST:
		s_Flags2(thing, Flags2(thing) & ~HAS_FWDLIST);
		break;
	case A_LISTEN:
		s_Flags2(thing, Flags2(thing) & ~HAS_LISTEN);
		break;
	case A_TIMEOUT:
		desc_reload(thing);
		break;
	case A_QUEUEMAX:
		pcache_reload(thing);
		break;
	}
}

/*
 * ---------------------------------------------------------------------------
 * * atr_add_raw, atr_add: add attribute of type atr to list
 */

void atr_add_raw(dbref thing, int atr, char *buff)
{
	ATRLIST *list;
	char *text;
	int found = 0;
	int hi, lo, mid;

	if(!buff || !*buff) {
		atr_clr(thing, atr);
		return;
	}
	if(strlen(buff) >= LBUF_SIZE) {
		buff[LBUF_SIZE - 1] = '\0';
	}
	if((text = (char *) malloc(strlen(buff) + 1)) == NULL) {
		return;
	}
	StringCopy(text, buff);

	if(!db[thing].ahead) {
		if((list = (ATRLIST *) malloc(sizeof(ATRLIST))) == NULL) {
			free(text);
			return;
		}
		db[thing].ahead = list;
		db[thing].at_count = 1;
		list[0].number = atr;
		list[0].data = text;
		list[0].size = strlen(text) + 1;
		found = 1;
	} else {

		/*
		 * Binary search for the attribute 
		 */
		lo = 0;
		hi = db[thing].at_count - 1;

		list = db[thing].ahead;
		while (lo <= hi) {
			mid = ((hi - lo) >> 1) + lo;
			if(list[mid].number == atr) {
				free(list[mid].data);
				list[mid].data = text;
				list[mid].size = strlen(text) + 1;
				found = 1;
				break;
			} else if(list[mid].number > atr) {
				hi = mid - 1;
			} else {
				lo = mid + 1;
			}
		}

		if(!found) {
			/*
			 * If we got here, we didn't find it, so lo = hi + 1, 
			 * and the attribute should be inserted between them. 
			 */

			list =
				(ATRLIST *) realloc(db[thing].ahead,
									(db[thing].at_count +
									 1) * sizeof(ATRLIST));

			if(!list)
				return;

			/*
			 * Move the stuff upwards one slot 
			 */
			if(lo < db[thing].at_count)
				bcopy((char *) (list + lo), (char *) (list + lo + 1),
					  (db[thing].at_count - lo) * sizeof(ATRLIST));

			list[lo].data = text;
			list[lo].number = atr;
			list[lo].size = strlen(text) + 1;
			db[thing].at_count++;
			db[thing].ahead = list;
		}
	}

	switch (atr) {
	case A_STARTUP:
		s_Flags(thing, Flags(thing) | HAS_STARTUP);
		break;
	case A_DAILY:
		s_Flags2(thing, Flags2(thing) | HAS_DAILY);
		break;
	case A_HOURLY:
		s_Flags2(thing, Flags2(thing) | HAS_HOURLY);
		break;
	case A_FORWARDLIST:
		s_Flags2(thing, Flags2(thing) | HAS_FWDLIST);
		break;
	case A_LISTEN:
		s_Flags2(thing, Flags2(thing) | HAS_LISTEN);
		break;
	case A_TIMEOUT:
		desc_reload(thing);
		break;
	case A_QUEUEMAX:
		pcache_reload(thing);
		break;
	}
}

void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags)
{
	char *tbuff;

	if(!buff || !*buff) {
		atr_clr(thing, atr);
	} else {
		tbuff = atr_encode(buff, thing, owner, flags, atr);
		atr_add_raw(thing, atr, tbuff);
	}
}

void atr_set_owner(dbref thing, int atr, dbref owner)
{
	dbref aowner;
	int aflags;
	char *buff;

	buff = atr_get(thing, atr, &aowner, &aflags);
	atr_add(thing, atr, buff, owner, aflags);
	free_lbuf(buff);
}

void atr_set_flags(dbref thing, int atr, dbref flags)
{
	dbref aowner;
	int aflags;
	char *buff;

	buff = atr_get(thing, atr, &aowner, &aflags);
	atr_add(thing, atr, buff, aowner, flags);
	free_lbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * get_atr,atr_get_raw, atr_get_str, atr_get: Get an attribute from the database.
 */

int get_atr(char *name)
{
	ATTR *ap;

	if(!(ap = atr_str(name)))
		return 0;
	if(!(ap->number))
		return -1;
	return ap->number;
}

char *atr_get_raw(dbref thing, int atr)
{
	int lo, mid, hi;
	ATRLIST *list;

	if(thing < 0)
		return NULL;

	/*
	 * Binary search for the attribute 
	 */
	lo = 0;
	hi = db[thing].at_count - 1;
	list = db[thing].ahead;
	if(!list)
		return NULL;

	while (lo <= hi) {
		mid = ((hi - lo) >> 1) + lo;
		if(list[mid].number == atr) {

			return list[mid].data;
		} else if(list[mid].number > atr) {
			hi = mid - 1;
		} else {
			lo = mid + 1;
		}
	}
	return NULL;
}

char *atr_get_str(char *s, dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;

	buff = atr_get_raw(thing, atr);
	if(!buff) {
		*owner = Owner(thing);
		*flags = 0;
		*s = '\0';
	} else {
		atr_decode(buff, s, thing, owner, flags, atr);
	}
	return s;
}

char *atr_get(dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;

	buff = alloc_lbuf("atr_get");
	return atr_get_str(buff, thing, atr, owner, flags);
}

int atr_get_info(dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;

	buff = atr_get_raw(thing, atr);
	if(!buff) {
		*owner = Owner(thing);
		*flags = 0;
		return 0;
	}
	atr_decode(buff, NULL, thing, owner, flags, atr);
	return 1;
}

char *atr_pget_str(char *s, dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;
	dbref parent;
	int lev;

	ATTR *ap;

	ITER_PARENTS(thing, parent, lev) {
		buff = atr_get_raw(parent, atr);
		if(buff && *buff) {
			atr_decode(buff, s, thing, owner, flags, atr);
			if((lev == 0) || !(*flags & AF_PRIVATE))
				return s;
		}
		if((lev == 0) && Good_obj(Parent(parent))) {
			ap = atr_num(atr);
			if(!ap || ap->flags & AF_PRIVATE)
				break;
		}
	}
	*owner = Owner(thing);
	*flags = 0;
	*s = '\0';
	return s;
}

char *atr_pget(dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;

	buff = alloc_lbuf("atr_pget");
	return atr_pget_str(buff, thing, atr, owner, flags);
}

int atr_pget_info(dbref thing, int atr, dbref * owner, int *flags)
{
	char *buff;
	dbref parent;
	int lev;
	ATTR *ap;

	ITER_PARENTS(thing, parent, lev) {
		buff = atr_get_raw(parent, atr);
		if(buff && *buff) {
			atr_decode(buff, NULL, thing, owner, flags, atr);
			if((lev == 0) || !(*flags & AF_PRIVATE))
				return 1;
		}
		if((lev == 0) && Good_obj(Parent(parent))) {
			ap = atr_num(atr);
			if(!ap || ap->flags & AF_PRIVATE)
				break;
		}
	}
	*owner = Owner(thing);
	*flags = 0;
	return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * atr_free: Return all attributes of an object.
 */

void atr_free(dbref thing)
{
	free(db[thing].ahead);
	db[thing].ahead = NULL;
}

/*
 * garbage collect an attribute list 
 */
void atr_collect(dbref thing)
{
	/*
	 * Nada.  gdbm takes care of us.  I hope ;-) 
	 */
}

/*
 * ---------------------------------------------------------------------------
 * * atr_cpy: Copy all attributes from one object to another.  Takes the
 * * player argument to ensure that only attributes that COULD be set by
 * * the player are copied.
 */

void atr_cpy(dbref player, dbref dest, dbref source)
{
	int attr, aflags;
	dbref owner, aowner;
	char *as, *buf;
	ATTR *at;

	owner = Owner(dest);
	for(attr = atr_head(source, &as); attr; attr = atr_next(&as)) {
		buf = atr_get(source, attr, &aowner, &aflags);
		if(!(aflags & AF_LOCK))
			aowner = owner;		/*
								 * chg owner 
								 */
		at = atr_num(attr);
		if(attr && at) {
			if(Write_attr(owner, dest, at, aflags))
				/*
				 * Only set attrs that owner has perm to set 
				 */
				atr_add(dest, attr, buf, aowner, aflags);
		}
		free_lbuf(buf);
	}
}

/*
 * ---------------------------------------------------------------------------
 * * atr_chown: Change the ownership of the attributes of an object to the
 * * current owner if they are not locked.
 */

void atr_chown(dbref obj)
{
	int attr, aflags;
	dbref owner, aowner;
	char *as, *buf;

	owner = Owner(obj);
	for(attr = atr_head(obj, &as); attr; attr = atr_next(&as)) {
		buf = atr_get(obj, attr, &aowner, &aflags);
		if((aowner != owner) && !(aflags & AF_LOCK))
			atr_add(obj, attr, buf, owner, aflags);
		free_lbuf(buf);
	}
}

/*
 * ---------------------------------------------------------------------------
 * * atr_next: Return next attribute in attribute list.
 */

int atr_next(char **attrp)
{
	ATRCOUNT *atr;

	if(!attrp || !*attrp) {
		return 0;
	} else {
		atr = (ATRCOUNT *) * attrp;
		if(atr->count > db[atr->thing].at_count) {
			free(atr);
			return 0;
		}
		atr->count++;
		return db[atr->thing].ahead[atr->count - 2].number;
	}
}

/*
 * ---------------------------------------------------------------------------
 * * atr_head: Returns the head of the attr list for object 'thing'
 */

int atr_head(dbref thing, char **attrp)
{
	ATRCOUNT *atr;

	if(db[thing].at_count) {
		atr = (ATRCOUNT *) malloc(sizeof(ATRCOUNT));
		atr->thing = thing;
		atr->count = 2;
		*attrp = (char *) atr;
		return db[thing].ahead[0].number;
	}
	return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * db_grow: Extend the struct database.
 */

#define	SIZE_HACK	1			/*
								 * * So mistaken refs to #-1 won't die.  
								 */

void initialize_objects(dbref first, dbref last)
{
	dbref thing;

	for(thing = first; thing < last; thing++) {
        memset(&db[thing], 0, sizeof(db[0]));
		s_Owner(thing, GOD);
		s_Flags(thing, (TYPE_GARBAGE | GOING));
		s_Flags2(thing, 0);
		s_Flags3(thing, 0);
		s_Powers(thing, 0);
		s_Powers2(thing, 0);
		s_Location(thing, NOTHING);
		s_Contents(thing, NOTHING);
		s_Exits(thing, NOTHING);
		s_Link(thing, NOTHING);
		s_Next(thing, NOTHING);
		s_Zone(thing, NOTHING);
		s_Parent(thing, NOTHING);
		s_Stack(thing, NULL);
		db[thing].ahead = NULL;
		db[thing].at_count = 0;
	}
}

void db_grow(dbref newtop)
{
	int newsize, marksize, delta, i;
	MARKBUF *newmarkbuf;
	OBJ *newdb;
	NAME *newpurenames;

	char *cp;

	delta = mudconf.init_size;

	/*
	 * Determine what to do based on requested size, current top and  * * 
	 * 
	 * *  * *  * *  * * size.  Make sure we grow in reasonable-sized
	 * chunks to * * prevent *  * *  * frequent reallocations of the db
	 * array. 
	 */

	/*
	 * If requested size is smaller than the current db size, ignore it 
	 */

	if(newtop <= mudstate.db_top) {
		return;
	}
	/*
	 * If requested size is greater than the current db size but smaller
	 * * * * * * * than the amount of space we have allocated, raise the
	 * db  * *  * size * * and * initialize the new area. 
	 */

	if(newtop <= mudstate.db_size) {
		for(i = mudstate.db_top; i < newtop; i++) {
			if(mudconf.cache_names)
				purenames[i] = NULL;
		}
		initialize_objects(mudstate.db_top, newtop);
		mudstate.db_top = newtop;
		return;
	}
	/*
	 * Grow by a minimum of delta objects 
	 */

	if(newtop <= mudstate.db_size + delta) {
		newsize = mudstate.db_size + delta;
	} else {
		newsize = newtop;
	}

	/*
	 * Enforce minimumdatabase size 
	 */

	if(newsize < mudstate.min_size)
		newsize = mudstate.min_size + delta;;

	/*
	 * Grow the name tables 
	 */

	if(mudconf.cache_names) {
		newpurenames =
			(NAME *) XMALLOC((newsize + SIZE_HACK) * sizeof(NAME),
							 "db_grow.purenames");

		if(!newpurenames) {
			LOG_SIMPLE(LOG_ALWAYS, "ALC", "DB",
					   tprintf
					   ("Could not allocate space for %d item name cache.",
						newsize));
			abort();
		}
		bzero((char *) newpurenames, (newsize + SIZE_HACK) * sizeof(NAME));

		if(purenames) {

			/*
			 * An old name cache exists.  Copy it. 
			 */

			purenames -= SIZE_HACK;
			bcopy((char *) purenames, (char *) newpurenames,
				  (newtop + SIZE_HACK) * sizeof(NAME));
			cp = (char *) purenames;
			XFREE(cp, "db_grow.purename");
		} else {

			/*
			 * Creating a brand new struct database.  Fill in the
			 * 'reserved' area in case it gets referenced.  
			 */

			purenames = newpurenames;
			for(i = 0; i < SIZE_HACK; i++) {
				purenames[i] = NULL;
			}
		}
		purenames = newpurenames + SIZE_HACK;
		newpurenames = NULL;
	}
	/*
	 * Grow the db array 
	 */

	newdb = (OBJ *)
		XMALLOC((newsize + SIZE_HACK) * sizeof(OBJ), "db_grow.db");
	if(!newdb) {

		LOG_SIMPLE(LOG_ALWAYS, "ALC", "DB",
				   tprintf
				   ("Could not allocate space for %d item struct database.",
					newsize));
		abort();
	}
	if(db) {

		/*
		 * An old struct database exists.  Copy it to the new buffer 
		 */

		db -= SIZE_HACK;
		bcopy((char *) db, (char *) newdb,
			  (mudstate.db_top + SIZE_HACK) * sizeof(OBJ));
		cp = (char *) db;
		XFREE(cp, "db_grow.db");
	} else {

		/*
		 * Creating a brand new struct database.  Fill in the * * * * 
		 * 
		 * *  * * 'reserved' area in case it gets referenced. 
		 */

		db = newdb;
		for(i = 0; i < SIZE_HACK; i++) {
			s_Owner(i, GOD);
			s_Flags(i, (TYPE_GARBAGE | GOING));
			s_Powers(i, 0);
			s_Powers2(i, 0);
			s_Location(i, NOTHING);
			s_Contents(i, NOTHING);
			s_Exits(i, NOTHING);
			s_Link(i, NOTHING);
			s_Next(i, NOTHING);
			s_Zone(i, NOTHING);
			s_Parent(i, NOTHING);
			s_Stack(i, NULL);
			db[i].ahead = NULL;
			db[i].at_count = 0;
		}
	}
	db = newdb + SIZE_HACK;
	newdb = NULL;

	for(i = mudstate.db_top; i < newtop; i++) {
		if(mudconf.cache_names) {
			purenames[i] = NULL;
		}
	}
	initialize_objects(mudstate.db_top, newtop);
	mudstate.db_top = newtop;
	mudstate.db_size = newsize;

	/*
	 * Grow the db mark buffer 
	 */

	marksize = (newsize + 7) >> 3;
	newmarkbuf = (MARKBUF *) XMALLOC(marksize, "db_grow");
	bzero((char *) newmarkbuf, marksize);
	if(mudstate.markbits) {
		marksize = (newtop + 7) >> 3;
		bcopy((char *) mudstate.markbits, (char *) newmarkbuf, marksize);
		cp = (char *) mudstate.markbits;
		XFREE(cp, "db_grow");
	}
	mudstate.markbits = newmarkbuf;
}

void db_free(void)
{
	char *cp;

	if(db != NULL) {
		db -= SIZE_HACK;
		cp = (char *) db;
		XFREE(cp, "db_grow");
		db = NULL;
	}
	mudstate.db_top = 0;
	mudstate.db_size = 0;
	mudstate.freelist = NOTHING;
}

void db_make_minimal(void)
{
	dbref obj;

	db_free();
	db_grow(1);
	s_Name(0, "Limbo");
	s_Flags(0, TYPE_ROOM);
	s_Powers(0, 0);
	s_Powers2(0, 0);
	s_Location(0, NOTHING);
	s_Exits(0, NOTHING);
	s_Link(0, NOTHING);
	s_Parent(0, NOTHING);
	s_Zone(0, NOTHING);
	s_Pennies(0, 1);
	s_Owner(0, 1);
	db[0].ahead = NULL;
	db[0].at_count = 0;
	/*
	 * should be #1 
	 */
	load_player_names();
	obj =
		create_player((char *) "Wizard", (char *) "potrzebie", NOTHING, 0, 0);
	s_Flags(obj, Flags(obj) | WIZARD);
	s_Powers(obj, 0);
	s_Powers2(obj, 0);
	s_Pennies(obj, 1000);

	/*
	 * Manually link to Limbo, just in case 
	 */
	s_Location(obj, 0);
	s_Next(obj, NOTHING);
	s_Contents(0, obj);
	s_Link(obj, 0);
}

dbref parse_dbref(const char *s)
{
	const char *p;
	int x;

	/*
	 * Enforce completely numeric dbrefs 
	 */

	for(p = s; *p; p++) {
		if(!isdigit(*p))
			return NOTHING;
	}

	x = atoi(s);
	return ((x >= 0) ? x : NOTHING);
}

void putref(FILE * f, dbref ref)
{
	fprintf(f, "%d\n", ref);
}

void putstring(FILE * f, const char *s)
{
	putc('"', f);

	while (s && *s) {
		switch (*s) {
		case '\\':
		case '"':
			putc('\\', f);
		default:
			putc(*s, f);
		}
		s++;
	}
	putc('"', f);
	putc('\n', f);
}

const char *getstring_noalloc(FILE * f, int new_strings)
{
	static char buf[LBUF_SIZE];
	char *p;
	int c, lastc;

	p = buf;
	c = fgetc(f);
	if(!new_strings || (c != '"')) {
		ungetc(c, f);
		c = '\0';
		for(;;) {
			lastc = c;
			c = fgetc(f);

			/*
			 * If EOF or null, return 
			 */

			if(!c || (c == EOF)) {
				*p = '\0';
				return buf;
			}
			/*
			 * If a newline, return if prior char is not a cr. *
			 * * * Otherwise * keep on truckin' 
			 */

			if((c == '\n') && (lastc != '\r')) {
				*p = '\0';
				return buf;
			}
			safe_chr(c, buf, &p);
		}
	} else {
		for(;;) {
			c = fgetc(f);
			if(c == '"') {
				if((c = fgetc(f)) != '\n')
					ungetc(c, f);
				*p = '\0';
				return buf;
			} else if(c == '\\') {
				c = fgetc(f);
			}
			if((c == '\0') || (c == EOF)) {
				*p = '\0';
				return buf;
			}
			safe_chr(c, buf, &p);
		}
	}
}

dbref getref(FILE * f)
{
	static char buf[SBUF_SIZE];

	fgets(buf, sizeof(buf), f);
	return (atoi(buf));
}

void free_boolexp(BOOLEXP * b)
{
	if(b == TRUE_BOOLEXP)
		return;

	switch (b->type) {
	case BOOLEXP_AND:
	case BOOLEXP_OR:
		free_boolexp(b->sub1);
		free_boolexp(b->sub2);
		free_bool(b);
		break;
	case BOOLEXP_NOT:
	case BOOLEXP_CARRY:
	case BOOLEXP_IS:
	case BOOLEXP_OWNER:
	case BOOLEXP_INDIR:
		free_boolexp(b->sub1);
		free_bool(b);
		break;
	case BOOLEXP_CONST:
		free_bool(b);
		break;
	case BOOLEXP_ATR:
	case BOOLEXP_EVAL:
		free((char *) b->sub1);
		free_bool(b);
		break;
	}
}

BOOLEXP *dup_bool(BOOLEXP * b)
{
	BOOLEXP *r;

	if(b == TRUE_BOOLEXP)
		return (TRUE_BOOLEXP);

	r = alloc_bool("dup_bool");
	switch (r->type = b->type) {
	case BOOLEXP_AND:
	case BOOLEXP_OR:
		r->sub2 = dup_bool(b->sub2);
	case BOOLEXP_NOT:
	case BOOLEXP_CARRY:
	case BOOLEXP_IS:
	case BOOLEXP_OWNER:
	case BOOLEXP_INDIR:
		r->sub1 = dup_bool(b->sub1);
	case BOOLEXP_CONST:
		r->thing = b->thing;
		break;
	case BOOLEXP_EVAL:
	case BOOLEXP_ATR:
		r->thing = b->thing;
		r->sub1 = (BOOLEXP *) strsave((char *) b->sub1);
		break;
	default:
		fprintf(stderr, "bad bool type!!\n");
		return (TRUE_BOOLEXP);
	}
	return (r);
}

void clone_object(dbref a, dbref b)
{
	bcopy((char *) &db[b], (char *) &db[a], sizeof(struct object));
}

/*
 * check_zone - checks back through a zone tree for control 
 */
int check_zone(dbref player, dbref thing)
{
	mudstate.zone_nest_num++;

	if(!mudconf.have_zones || (Zone(thing) == NOTHING) ||
	   (mudstate.zone_nest_num == mudconf.zone_nest_lim) ||
	   (isPlayer(thing))) {
		mudstate.zone_nest_num = 0;
		return 0;
	}

	/*
	 * If the zone doesn't have an enterlock, DON'T allow control. 
	 */

	if(atr_get_raw(Zone(thing), A_LENTER) &&
	   could_doit(player, Zone(thing), A_LENTER)) {
		mudstate.zone_nest_num = 0;
		return 1;
	} else {
		return check_zone(player, Zone(thing));
	}

}

int check_zone_for_player(dbref player, dbref thing)
{
	mudstate.zone_nest_num++;

	if(!mudconf.have_zones || (Zone(thing) == NOTHING) ||
	   (mudstate.zone_nest_num == mudconf.zone_nest_lim) ||
	   !(isPlayer(thing))) {
		mudstate.zone_nest_num = 0;
		return 0;
	}

	if(atr_get_raw(Zone(thing), A_LENTER) &&
	   could_doit(player, Zone(thing), A_LENTER)) {
		mudstate.zone_nest_num = 0;
		return 1;
	} else {
		return check_zone(player, Zone(thing));
	}

}

void toast_player(dbref player)
{
	do_clearcom(player, player, 0);
	do_channelnuke(player);
	del_commac(player);
	do_clear_macro(player, NULL);
}

/*
 * ---------------------------------------------------------------------------
 * * dump_restart_db: Writes out socket information.
 */


void dump_restart_db(void)
{
	FILE *f;
	DESC *d;
    OBJQE *obq;
	int version = 0;

	/* We maintain a version number for the restart database,
	   so we can restart even if the format of the restart db
	   has been changed in the new executable. */

	version |= RS_RECORD_PLAYERS;
	version |= RS_NEW_STRINGS;
	version |= RS_HUDKEY;

	f = fopen("restart.db", "w");
	fprintf(f, "+V%d\n", version);
	putref(f, mudstate.start_time);
	putstring(f, mudstate.doing_hdr);
	putref(f, mudstate.record_players);
	DESC_ITER_ALL(d) {
		putref(f, d->descriptor);
		putref(f, d->flags);
		putref(f, d->connected_at);
		putref(f, d->command_count);
		putref(f, d->timeout);
		putref(f, d->host_info);
		putref(f, d->player);
		putref(f, d->last_time);
		putstring(f, d->output_prefix);
		putstring(f, d->output_suffix);
		putstring(f, d->addr);
		putstring(f, d->doing);
		putstring(f, d->username);
		putstring(f, d->hudkey);
	}
	putref(f, 0);
	fclose(f);
}

#define RESTART_MAGIC 0x0001D1ED
void dump_restart_db_xdr(void)
{
	struct mmdb_t *mmdb;
    DESC *d;
	int version = 0;

	/* We maintain a version number for the restart database,
	   so we can restart even if the format of the restart db
	   has been changed in the new executable. */

	version |= RS_RECORD_PLAYERS;
	version |= RS_NEW_STRINGS;
	version |= RS_HUDKEY;

   
    mmdb = mmdb_open_write("restart.xdr");
    mmdb_write_uint32(mmdb, RESTART_MAGIC);
    mmdb_write_uint32(mmdb, 1);
    mmdb_write_uint32(mmdb, version);
    mmdb_write_uint32(mmdb, mudstate.start_time);
    mmdb_write_string(mmdb, mudstate.doing_hdr);
	mmdb_write_uint32(mmdb, mudstate.record_players);
	DESC_ITER_ALL(d) {
		mmdb_write_uint32(mmdb, d->descriptor);
		mmdb_write_uint32(mmdb, d->flags);
		mmdb_write_uint32(mmdb, d->connected_at);
		mmdb_write_uint32(mmdb, d->command_count);
		mmdb_write_uint32(mmdb, d->timeout);
		mmdb_write_uint32(mmdb, d->host_info);
		mmdb_write_uint32(mmdb, d->player);
		mmdb_write_uint32(mmdb, d->last_time);
		mmdb_write_string(mmdb, d->output_prefix);
		mmdb_write_string(mmdb, d->output_suffix);
		mmdb_write_string(mmdb, d->addr);
		mmdb_write_string(mmdb, d->doing);
		mmdb_write_string(mmdb, d->username);
		mmdb_write_string(mmdb, d->hudkey);
	}
    mmdb_write_uint32(mmdb, 0);
    cque_dump_restart(mmdb); 
    mmdb_close(mmdb);
}

void accept_client_input(int fd, short event, void *arg);

void bsd_write_callback(struct bufferevent *bufev, void *arg);
void bsd_read_callback(struct bufferevent *bufev, void *arg);
void bsd_error_callback(struct bufferevent *bufev, short whut, void *arg);

void load_restart_db()
{
	FILE *f;
	DESC *d;
	DESC *p;
    struct stat statbuffer;

	int val, version, new_strings = 0;
	char *temp, buf[8];

	f = fopen("restart.db", "r");
	if(!f) {
		mudstate.restarting = 0;
		return;
	}
	mudstate.restarting = 1;

	fgets(buf, 3, f);
	if(strncmp(buf, "+V", 2)) {
		abort();
	}
	version = getref(f);

	if(version & RS_NEW_STRINGS)
		new_strings = 1;

	mudstate.start_time = getref(f);
	time(&mudstate.restart_time);
	strcpy(mudstate.doing_hdr, getstring_noalloc(f, new_strings));

	if(version & RS_RECORD_PLAYERS) {
		mudstate.record_players = getref(f);
	}

	while ((val = getref(f)) != 0) {
		d = malloc(sizeof(DESC));
		memset(d, 0, sizeof(DESC));
		d->descriptor = val;
		d->flags = getref(f);
		d->connected_at = getref(f);
		d->command_count = getref(f);
		d->timeout = getref(f);
		d->host_info = getref(f);
		d->player = getref(f);
		d->last_time = getref(f);
		temp = (char *) getstring_noalloc(f, new_strings);
		if(*temp) {
			d->output_prefix = alloc_lbuf("set_userstring");
			strcpy(d->output_prefix, temp);
		} else {
			d->output_prefix = NULL;
		}
		temp = (char *) getstring_noalloc(f, new_strings);
		if(*temp) {
			d->output_suffix = alloc_lbuf("set_userstring");
			strcpy(d->output_suffix, temp);
		} else {
			d->output_suffix = NULL;
		}

		strcpy(d->addr, getstring_noalloc(f, new_strings));
		strcpy(d->doing, getstring_noalloc(f, new_strings));
		strcpy(d->username, getstring_noalloc(f, new_strings));

		if(version & RS_HUDKEY)
			strncpy(d->hudkey, getstring_noalloc(f, new_strings), HUDKEYLEN);
		else
			d->hudkey[0] = '\0';

		d->output_size = 0;
		d->output_tot = 0;
		d->output_lost = 0;
		d->input_size = 0;
		d->input_tot = 0;
		d->input_lost = 0;
		d->raw_input_at = NULL;
		memset(d->input, 0, sizeof(d->input));
		d->quota = mudconf.cmd_quota_max;
		d->program_data = NULL;
		d->hashnext = NULL;
        d->refcount = 1;

		d->saddr_len = sizeof(d->saddr);
		getpeername(d->descriptor, (struct sockaddr *) &d->saddr,
					(socklen_t *) & d->saddr_len);
		d->outstanding_dnschild_query = dnschild_request(d);

		if(descriptor_list) {
			for(p = descriptor_list; p->next; p = p->next);
			d->prev = &p->next;
			p->next = d;
			d->next = NULL;
		} else {
			d->next = descriptor_list;
			d->prev = &descriptor_list;
			descriptor_list = d;
		}
		d->sock_buff = bufferevent_new(d->descriptor, bsd_write_callback,
									   bsd_read_callback, bsd_error_callback,
									   NULL);
		bufferevent_disable(d->sock_buff, EV_READ);
		bufferevent_enable(d->sock_buff, EV_WRITE);

		event_set(&d->sock_ev, d->descriptor, EV_READ | EV_PERSIST,
				  accept_client_input, d);
		event_add(&d->sock_ev, NULL);

		desc_addhash(d);
		if(isPlayer(d->player))
			s_Flags2(d->player, Flags2(d->player) | CONNECTED);
	}

    DESC_ITER_CONN(d) {
        if(!isPlayer(d->player) || fstat(d->descriptor, &statbuffer) < 0) {
            dprintk("dropping descriptor %d.\n", d->descriptor);
            shutdownsock(d, R_QUIT);
        }

    }

	fclose(f);
	remove("restart.db");
	raw_broadcast(0, "Game: Restart finished.");
}

int load_restart_db_xdr()
{
	struct mmdb_t *mmdb;
    DESC *d;
	DESC *p;
    struct stat statbuffer;

	int val, version, new_strings = 0;
	char *temp, buf[8];

	mmdb = mmdb_open_read("restart.xdr");
    if(!mmdb) return 0;

    val = mmdb_read_uint32(mmdb); // RESTART_MAGIC
    if(val != RESTART_MAGIC) {
        printk("restart database had invalid magic.");
        printk("read %08x expected %08x.", val, RESTART_MAGIC);
        return 0;
    }
    mmdb_read_uint32(mmdb); // VERSION
    mmdb_read_uint32(mmdb); // VERSION
    mudstate.start_time = mmdb_read_uint32(mmdb);
    mmdb_read_opaque(mmdb, mudstate.doing_hdr, sizeof(mudstate.doing_hdr));
    mudstate.record_players = mmdb_read_uint32(mmdb);

	mudstate.restarting = 1;

    while( (val = mmdb_read_uint32(mmdb)) != 0) {
        dprintk("loading descriptor %d\n", val);
		d = malloc(sizeof(DESC));
		memset(d, 0, sizeof(DESC));
		d->descriptor = val;
		d->flags = mmdb_read_uint32(mmdb);
		d->connected_at = mmdb_read_uint32(mmdb);
		d->command_count = mmdb_read_uint32(mmdb);
		d->timeout = mmdb_read_uint32(mmdb);
		d->host_info = mmdb_read_uint32(mmdb);
		d->player = mmdb_read_uint32(mmdb);
		d->last_time = mmdb_read_uint32(mmdb);
	
        d->output_prefix = mmdb_read_string(mmdb);
        d->output_suffix = mmdb_read_string(mmdb);
        mmdb_read_opaque(mmdb, d->addr, sizeof(d->addr));
        mmdb_read_opaque(mmdb, d->doing, sizeof(d->doing));
        mmdb_read_opaque(mmdb, d->username, sizeof(d->username));
        mmdb_read_opaque(mmdb, d->hudkey, sizeof(d->hudkey));

		d->output_size = 0;
		d->output_tot = 0;
		d->output_lost = 0;
		d->input_size = 0;
		d->input_tot = 0;
		d->input_lost = 0;
		d->raw_input_at = NULL;
		memset(d->input, 0, sizeof(d->input));
		d->quota = mudconf.cmd_quota_max;
		d->program_data = NULL;
		d->hashnext = NULL;
        d->refcount = 1;

		d->saddr_len = sizeof(d->saddr);
		getpeername(d->descriptor, (struct sockaddr *) &d->saddr,
					(socklen_t *) & d->saddr_len);
		d->outstanding_dnschild_query = dnschild_request(d);

		if(descriptor_list) {
			for(p = descriptor_list; p->next; p = p->next);
			d->prev = &p->next;
			p->next = d;
			d->next = NULL;
		} else {
			d->next = descriptor_list;
			d->prev = &descriptor_list;
			descriptor_list = d;
		}
		d->sock_buff = bufferevent_new(d->descriptor, bsd_write_callback,
									   bsd_read_callback, bsd_error_callback,
									   NULL);
		bufferevent_disable(d->sock_buff, EV_READ);
		bufferevent_enable(d->sock_buff, EV_WRITE);

		event_set(&d->sock_ev, d->descriptor, EV_READ | EV_PERSIST,
				  accept_client_input, d);
		event_add(&d->sock_ev, NULL);

		desc_addhash(d);
		if(isPlayer(d->player))
			s_Flags2(d->player, Flags2(d->player) | CONNECTED);
	}

	DESC_ITER_CONN(d) {
		if(!isPlayer(d->player) || fstat(d->descriptor, &statbuffer) < 0) {
            dprintk("dropping descriptor %d.\n", d->descriptor);
			shutdownsock(d, R_QUIT);
		}

	}
    cque_load_restart(mmdb);
    mmdb_close(mmdb);
    remove("restart.xdr");
    remove("restart.db");
	raw_broadcast(0, "Game: Restart finished.");
    return 1;
}