fbmuck-6.05/auto/
fbmuck-6.05/contrib/jresolver/
fbmuck-6.05/contrib/jresolver/org/
fbmuck-6.05/contrib/jresolver/org/fuzzball/
fbmuck-6.05/docs/devel/
fbmuck-6.05/game/
fbmuck-6.05/game/logs/
fbmuck-6.05/game/muf/
fbmuck-6.05/scripts/
fbmuck-6.05/src_docs/
/* do_parse_mesg()  Parses a message string, expanding {prop}s, {list}s, etc.
 * Written 4/93 - 5/93 by Foxen
 *
 * Args:
 *   int descr             Descriptor that triggered this.
 *   dbref player          Player triggering this.
 *   dbref what            Object that mesg is on.
 *   dbref perms           Object permissions are checked from.
 *   const char *inbuf     A pointer to the input raw mesg string.
 *   char *abuf            Argument string for {&how}.
 *   char *outbuf          Buffer to return results in.
 *   int mesgtyp           1 for personal messages, 0 for omessages.
 *
 *   extern char *match_args     Arg string for {&args}
 *   extern char *match_cmdname  Arg string for {&cmd}
 *
 * Returns a pointer to output string.  Usually in outbuf.
 */


#include "config.h"
#include <math.h>
#include <ctype.h>
#include "params.h"
#include "db.h"
#include "tune.h"

#include "mpi.h"
#include "externs.h"
#include "props.h"
#include "match.h"
#include "interp.h"
#include "interface.h"
#include "msgparse.h"
#include "mfun.h"

time_t mpi_prof_start_time;

int
safeblessprop(dbref obj, dbref perms, char *buf, int mesgtyp, int set_p)
{
	char *ptr;

	if (!buf)
		return 0;
	while (*buf == PROPDIR_DELIMITER)
		buf++;
	if (!*buf)
		return 0;

	/* disallow CR's and :'s in prop names. */
	for (ptr = buf; *ptr; ptr++)
		if (*ptr == '\r' || *ptr == PROP_DELIMITER)
			return 0;

	if (!(mesgtyp & MPI_ISBLESSED)) {
		return 0;
	}
	if (set_p) {
		set_property_flags(obj, buf, PROP_BLESSED);
	} else {
		clear_property_flags(obj, buf, PROP_BLESSED);
	}

	return 1;
}


int
safeputprop(dbref obj, dbref perms, char *buf, char *val, int mesgtyp)
{
	char *ptr;

	if (!buf)
		return 0;
	while (*buf == PROPDIR_DELIMITER)
		buf++;
	if (!*buf)
		return 0;

	/* disallow CR's and :'s in prop names. */
	for (ptr = buf; *ptr; ptr++)
		if (*ptr == '\r' || *ptr == PROP_DELIMITER)
			return 0;

	if (Prop_System(buf))
		return 0;
	
	if (!(mesgtyp & MPI_ISBLESSED)) {
		if (Prop_Hidden(buf))
			return 0;
		if (Prop_SeeOnly(buf))
			return 0;
		if (string_prefix(buf, "_msgmacs/"))
			return 0;
	}
	if (val == NULL) {
		remove_property(obj, buf);
	} else {
		add_property(obj, buf, val, 0);
	}
	return 1;
}


const char *
safegetprop_strict(dbref player, dbref what, dbref perms, const char *inbuf, int mesgtyp, int* blessed)
{
	const char *ptr;
	char bbuf[BUFFER_LEN];
	static char vl[32];

	*blessed = 0;

	if (!inbuf) {
		notify_nolisten(player, "PropFetch: Propname required.", 1);
		return NULL;
	}
	while (*inbuf == PROPDIR_DELIMITER)
		inbuf++;
	if (!*inbuf) {
		notify_nolisten(player, "PropFetch: Propname required.", 1);
		return NULL;
	}
	strcpy(bbuf, inbuf);

	if (Prop_System(bbuf))
	{
		notify_nolisten(player, "PropFetch: Permission denied.", 1);
		return NULL;
	}

	if (!(mesgtyp & MPI_ISBLESSED)) {
		if (Prop_Hidden(bbuf)) {
			notify_nolisten(player, "PropFetch: Permission denied.", 1);
			return NULL;
		}
		if (Prop_Private(bbuf) && OWNER(perms) != OWNER(what)) {
			notify_nolisten(player, "PropFetch: Permission denied.", 1);
			return NULL;
		}
	}

	ptr = get_property_class(what, bbuf);
	if (!ptr) {
		int i;

		i = get_property_value(what, bbuf);
		if (!i) {
			dbref dd;

			dd = get_property_dbref(what, bbuf);
			if (dd == NOTHING) {
				*vl = '\0';
				ptr = vl;
				return ptr;
			} else {
				snprintf(vl, sizeof(vl), "#%d", dd);
				ptr = vl;
			}
		} else {
			snprintf(vl, sizeof(vl), "%d", i);
			ptr = vl;
		}
	}

	ptr = uncompress(ptr);

	if (ptr) {
		if (Prop_Blessed(what, bbuf)) {
			*blessed = 1;
		}
	}
	return ptr;
}


const char *
safegetprop_limited(dbref player, dbref what, dbref whom, dbref perms, const char *inbuf, int mesgtyp, int* blessed)
{
	const char *ptr;

	while (what != NOTHING) {
		ptr = safegetprop_strict(player, what, perms, inbuf, mesgtyp, blessed);
		if (!ptr)
			return ptr;
		if (*ptr) {
			if (OWNER(what) == whom || *blessed) {
				return ptr;
			}
		}
		what = getparent(what);
	}
	return "";
}


const char *
safegetprop(dbref player, dbref what, dbref perms, const char *inbuf, int mesgtyp, int* blessed)
{
	const char *ptr;

	while (what != NOTHING) {
		ptr = safegetprop_strict(player, what, perms, inbuf, mesgtyp, blessed);
		if (!ptr || *ptr)
			return ptr;
		what = getparent(what);
	}
	return "";
}


char *
stripspaces(char *buf, char *in)
{
	char *ptr;

	for (ptr = in; *ptr == ' '; ptr++) ;
	strcpy(buf, ptr);
	ptr = strlen(buf) + buf - 1;
	while (*ptr == ' ' && ptr > buf)
		*(ptr--) = '\0';
	return buf;
}


char *
string_substitute(const char *str, const char *oldstr, const char *newstr, char *buf,
				  int maxlen)
{
	const char *ptr = str;
	char *ptr2 = buf;
	const char *ptr3;
	int len = strlen(oldstr);
	int clen = 0;

	if (len == 0) {
		strcpy(buf, str);
		return buf;
	}
	while (*ptr && clen < (maxlen+2)) {
		if (!strncmp(ptr, oldstr, len)) {
			for (ptr3 = newstr; ((ptr2 - buf) < (maxlen - 2)) && *ptr3;)
				*(ptr2++) = *(ptr3++);
			ptr += len;
			clen += len;
		} else {
			*(ptr2++) = *(ptr++);
			clen++;
		}
	}
	*ptr2 = '\0';
	return buf;
}


const char *
get_list_item(dbref player, dbref what, dbref perms, const char *listname, int itemnum, int mesgtyp, int* blessed)
{
	char buf[BUFFER_LEN];
	const char *ptr;

	snprintf(buf, sizeof(buf), "%.512s#/%d", listname, itemnum);
	ptr = safegetprop(player, what, perms, buf, mesgtyp, blessed);
	if (!ptr || *ptr)
		return ptr;

	snprintf(buf, sizeof(buf), "%.512s/%d", listname, itemnum);
	ptr = safegetprop(player, what, perms, buf, mesgtyp, blessed);
	if (!ptr || *ptr)
		return ptr;

	snprintf(buf, sizeof(buf), "%.512s%d", listname, itemnum);
	return (safegetprop(player, what, perms, buf, mesgtyp, blessed));
}


int
get_list_count(dbref player, dbref obj, dbref perms, const char *listname, int mesgtyp, int* blessed)
{
	char buf[BUFFER_LEN];
	const char *ptr;
	int i;

	snprintf(buf, sizeof(buf), "%.512s#", listname);
	ptr = safegetprop(player, obj, perms, buf, mesgtyp, blessed);
	if (ptr && *ptr)
		return (atoi(ptr));

	snprintf(buf, sizeof(buf), "%.512s/#", listname);
	ptr = safegetprop(player, obj, perms, buf, mesgtyp, blessed);
	if (ptr && *ptr)
		return (atoi(ptr));

	for (i = 1; i < MAX_MFUN_LIST_LEN; i++) {
		ptr = get_list_item(player, obj, perms, listname, i, mesgtyp, blessed);
		if (!ptr)
			return 0;
		if (!*ptr)
			break;
	}
	if (i-- < MAX_MFUN_LIST_LEN)
		return i;
	return MAX_MFUN_LIST_LEN;
}



char *
get_concat_list(dbref player, dbref what, dbref perms, dbref obj, const char *listname,
				char *buf, int maxchars, int mode, int mesgtyp, int* blessed)
{
	int line_limit = MAX_MFUN_LIST_LEN;
	int i;
	const char *ptr;
	char *pos = buf;
	int tmpbless;
	int cnt = get_list_count(what, obj, perms, listname, mesgtyp, &tmpbless);
	*blessed = 1;

	if (!tmpbless) {
		*blessed = 0;
	}

	if (cnt == 0) {
		return NULL;
	}
	maxchars -= 2;
	*buf = '\0';
	for (i = 1; ((pos - buf) < (maxchars - 1)) && i <= cnt && line_limit--; i++) {
		ptr = get_list_item(what, obj, perms, listname, i, mesgtyp, &tmpbless);
		if (ptr) {
			if (!tmpbless) {
				*blessed = 0;
			}
			while (mode && isspace(*ptr))
				ptr++;
			if (pos > buf) {
				if (!mode) {
					*(pos++) = '\r';
					*pos = '\0';
				} else if (mode == 1) {
					char ch = *(pos - 1);

					if ((pos - buf) >= (maxchars - 2))
						break;
					if (ch == '.' || ch == '?' || ch == '!')
						*(pos++) = ' ';
					*(pos++) = ' ';
					*pos = '\0';
				} else {
					*pos = '\0';
				}
			}
			while (((pos - buf) < (maxchars - 1)) && *ptr)
				*(pos++) = *(ptr++);
			if (mode) {
				while (pos > buf && *(pos - 1) == ' ')
					pos--;
			}
			*pos = '\0';
			if ((pos - buf) >= (maxchars - 1))
				break;
		}
	}
	return (buf);
}


int
mesg_read_perms(dbref player, dbref perms, dbref obj, int mesgtyp)
{
	if ((obj == 0) || (obj == player) || (obj == perms))
		return 1;
	if (OWNER(perms) == OWNER(obj))
		return 1;
	if ((mesgtyp & MPI_ISBLESSED))
		return 1;
	return 0;
}


int
isneighbor(dbref d1, dbref d2)
{
	if (d1 == d2)
		return 1;
	if (Typeof(d1) != TYPE_ROOM)
		if (getloc(d1) == d2)
			return 1;
	if (Typeof(d2) != TYPE_ROOM)
		if (getloc(d2) == d1)
			return 1;
	if (Typeof(d1) != TYPE_ROOM && Typeof(d2) != TYPE_ROOM)
		if (getloc(d1) == getloc(d2))
			return 1;
	return 0;
}


int
mesg_local_perms(dbref player, dbref perms, dbref obj, int mesgtyp)
{
	if (getloc(obj) != NOTHING && OWNER(perms) == OWNER(getloc(obj)))
		return 1;
	if (isneighbor(perms, obj))
		return 1;
	if (isneighbor(player, obj))
		return 1;
	if (mesg_read_perms(player, perms, obj, mesgtyp))
		return 1;
	return 0;
}


dbref
mesg_dbref_raw(int descr, dbref player, dbref what, dbref perms, const char *buf)
{
	struct match_data md;
	dbref obj = UNKNOWN;

	if (buf && *buf) {
		if (!string_compare(buf, "this")) {
			obj = what;
		} else if (!string_compare(buf, "me")) {
			obj = player;
		} else if (!string_compare(buf, "here")) {
			obj = getloc(player);
		} else if (!string_compare(buf, "home")) {
			obj = HOME;
		} else {
			init_match(descr, player, buf, NOTYPE, &md);
			match_absolute(&md);
			match_all_exits(&md);
			match_neighbor(&md);
			match_possession(&md);
			match_registered(&md);
			obj = match_result(&md);
			if (obj == NOTHING) {
				init_match_remote(descr, player, what, buf, NOTYPE, &md);
				match_player(&md);
				match_all_exits(&md);
				match_neighbor(&md);
				match_possession(&md);
				match_registered(&md);
				obj = match_result(&md);
			}
		}
	}

	if (obj < 0 || obj >= db_top || Typeof(obj) == TYPE_GARBAGE)
		obj = UNKNOWN;
	return obj;
}


dbref
mesg_dbref(int descr, dbref player, dbref what, dbref perms, char *buf, int mesgtyp)
{
	dbref obj = mesg_dbref_raw(descr, player, what, perms, buf);

	if (obj == UNKNOWN)
		return obj;
	if (!mesg_read_perms(player, perms, obj, mesgtyp)) {
		obj = PERMDENIED;
	}
	return obj;
}


dbref
mesg_dbref_strict(int descr, dbref player, dbref what, dbref perms, char *buf, int mesgtyp)
{
	dbref obj = mesg_dbref_raw(descr, player, what, perms, buf);

	if (obj == UNKNOWN)
		return obj;
	if (!(mesgtyp & MPI_ISBLESSED) && OWNER(perms) != OWNER(obj)) {
		obj = PERMDENIED;
	}
	return obj;
}


dbref
mesg_dbref_local(int descr, dbref player, dbref what, dbref perms, char *buf, int mesgtyp)
{
	dbref obj = mesg_dbref_raw(descr, player, what, perms, buf);

	if (obj == UNKNOWN)
		return obj;
	if (!mesg_local_perms(player, perms, obj, mesgtyp)) {
		obj = PERMDENIED;
	}
	return obj;
}


char *
ref2str(dbref obj, char *buf, size_t buflen)
{
	if (obj < -3 || obj >= db_top) {
		snprintf(buf, buflen, "Bad");
		return buf;
	}

	if (obj >= 0 && Typeof(obj) == TYPE_PLAYER) {
		snprintf(buf, buflen, "*%s", NAME(obj));
	} else {
		snprintf(buf, buflen, "#%d", obj);
	}
	return buf;
}


int
truestr(char *buf)
{
	while (isspace(*buf))
		buf++;
	if (!*buf || (number(buf) && !atoi(buf)))
		return 0;
	return 1;
}


/******** MPI Variable handling ********/

struct mpivar {
	char name[MAX_MFUN_NAME_LEN + 1];
	char *buf;
};

static struct mpivar varv[MPI_MAX_VARIABLES];
int varc = 0;

int check_mvar_overflow(int count)
{
	return (varc + count) > MPI_MAX_VARIABLES;
}

int
new_mvar(const char *varname, char *buf)
{
	if (strlen(varname) > MAX_MFUN_NAME_LEN)
		return 1;
	if (varc >= MPI_MAX_VARIABLES)
		return 2;
	strcpy(varv[varc].name, varname);
	varv[varc++].buf = buf;
	return 0;
}

char *
get_mvar(const char *varname)
{
	int i = 0;

	for (i = varc - 1; i >= 0 && string_compare(varname, varv[i].name); i--) ;
	if (i < 0)
		return NULL;
	return varv[i].buf;
}

int
free_top_mvar(void)
{
	if (varc < 1)
		return 1;
	varc--;
	return 0;
}


/***** MPI function handling *****/


struct mpifunc {
	char name[MAX_MFUN_NAME_LEN + 1];
	char *buf;
};

static struct mpifunc funcv[MPI_MAX_FUNCTIONS];
int funcc = 0;

int
new_mfunc(const char *funcname, const char *buf)
{
	if (strlen(funcname) > MAX_MFUN_NAME_LEN)
		return 1;
	if (funcc > MPI_MAX_FUNCTIONS)
		return 2;
	strcpy(funcv[funcc].name, funcname);
	funcv[funcc++].buf = (char *) string_dup(buf);
	return 0;
}

const char *
get_mfunc(const char *funcname)
{
	int i = 0;

	for (i = funcc - 1; i >= 0 && string_compare(funcname, funcv[i].name); i--) ;
	if (i < 0)
		return NULL;
	return funcv[i].buf;
}

int
free_mfuncs(int downto)
{
	if (funcc < 1)
		return 1;
	if (downto < 0)
		return 1;
	while (funcc > downto)
		free(funcv[--funcc].buf);
	return 0;
}



/*** End of MFUNs. ***/

int
msg_is_macro(dbref player, dbref what, dbref perms, const char *name, int mesgtyp)
{
	const char *ptr;
	char buf2[BUFFER_LEN];
	dbref obj;
	int blessed;

	if (!*name)
		return 0;
	snprintf(buf2, sizeof(buf2), "_msgmacs/%s", name);
	obj = what;
	ptr = get_mfunc(name);
	if (!ptr || !*ptr)
		ptr = safegetprop_strict(player, OWNER(obj), perms, buf2, mesgtyp, &blessed);
	if (!ptr || !*ptr)
		ptr = safegetprop_limited(player, obj, OWNER(obj), perms, buf2, mesgtyp, &blessed);
	if (!ptr || !*ptr)
		ptr = safegetprop_strict(player, 0, perms, buf2, mesgtyp, &blessed);
	if (!ptr || !*ptr)
		return 0;
	return 1;
}


void
msg_unparse_macro(dbref player, dbref what, dbref perms, char *name, int argc, argv_typ argv,
				  char *rest, int maxchars, int mesgtyp)
{
	const char *ptr;
	char *ptr2;
	char buf[BUFFER_LEN];
	char buf2[BUFFER_LEN];
	dbref obj;
	int i, p = 0;
	int blessed;

	strcpy(buf, rest);
	snprintf(buf2, sizeof(buf2), "_msgmacs/%s", name);
	obj = what;
	ptr = get_mfunc(name);
	if (!ptr || !*ptr)
		ptr = safegetprop_strict(player, OWNER(obj), perms, buf2, mesgtyp, &blessed);
	if (!ptr || !*ptr)
		ptr = safegetprop_limited(player, obj, OWNER(obj), perms, buf2, mesgtyp, &blessed);
	if (!ptr || !*ptr)
		ptr = safegetprop_strict(player, 0, perms, buf2, mesgtyp, &blessed);
	while (ptr && *ptr && p < (maxchars - 1)) {
		if (*ptr == '\\') {
			if (*(ptr + 1) == 'r') {
				rest[p++] = '\r';
				ptr++;
				ptr++;
			} else if (*(ptr + 1) == '[') {
				rest[p++] = ESCAPE_CHAR;
				ptr++;
				ptr++;
			} else {
				rest[p++] = *(ptr++);
				rest[p++] = *(ptr++);
			}
		} else if (*ptr == MFUN_LEADCHAR) {
			if (*(ptr + 1) == MFUN_ARGSTART && isdigit(*(ptr + 2)) &&
				*(ptr + 3) == MFUN_ARGEND) {
				ptr++;
				ptr++;
				i = *(ptr++) - '1';
				ptr++;
				if (i >= argc || i < 0) {
					ptr2 = NULL;
				} else {
					ptr2 = argv[i];
				}
				while (ptr2 && *ptr2 && p < (maxchars - 1)) {
					rest[p++] = *(ptr2++);
				}
			} else {
				rest[p++] = *(ptr++);
			}
		} else {
			rest[p++] = *(ptr++);
		}
	}
	ptr2 = buf;
	while (ptr2 && *ptr2 && p < (maxchars - 1)) {
		rest[p++] = *(ptr2++);
	}
	rest[p] = '\0';
}


#ifndef MSGHASHSIZE
#define MSGHASHSIZE 256
#endif

static hash_tab msghash[MSGHASHSIZE];

int
find_mfn(const char *name)
{
	hash_data *exp = find_hash(name, msghash, MSGHASHSIZE);

	if (exp)
		return (exp->ival);
	return (0);
}


void
insert_mfn(const char *name, int i)
{
	hash_data hd;

	(void) free_hash(name, msghash, MSGHASHSIZE);
	hd.ival = i;
	(void) add_hash(name, hd, msghash, MSGHASHSIZE);
}


void
purge_mfns(void)
{
	kill_hash(msghash, MSGHASHSIZE, 0);
}


#define DEFINE_MFUN_LIST
#include "mfunlist.h"


/******** HOOK ********/
void
mesg_init(void)
{
	int i;

	for (i = 0; mfun_list[i].name; i++)
		insert_mfn(mfun_list[i].name, i + 1);
	mpi_prof_start_time = time(NULL);
}



/******** HOOK ********/
int
mesg_args(char *wbuf, argv_typ argv, char ulv, char sep, char dlv, char quot, int maxargs)
{
	int r, lev, argc = 0;
	char buf[BUFFER_LEN];
	char *ptr;
	int litflag = 0;

	/* for (ptr = wbuf; ptr && isspace(*ptr); ptr++); */
	strcpy(buf, wbuf);
	ptr = buf;
	for (lev = r = 0; (r < (BUFFER_LEN - 2)); r++) {
		if (buf[r] == '\0') {
			return (-1);
		} else if (buf[r] == '\\') {
			r++;
			continue;
		} else if (buf[r] == quot) {
			litflag = (!litflag);
		} else if (!litflag && buf[r] == ulv) {
			lev++;
			continue;
		} else if (!litflag && buf[r] == dlv) {
			lev--;
			if (lev < 0) {
				buf[r] = '\0';
				if (argv[argc]) {
					free(argv[argc]);
					argv[argc] = NULL;
				}
				argv[argc] = (char*)malloc(((buf + r) - ptr) + 1);
				strcpy(argv[argc++], ptr);
				ptr = buf + r + 1;
				break;
			}
			continue;
		} else if (!litflag && lev < 1 && buf[r] == sep) {
			if (argc < maxargs - 1) {
				buf[r] = '\0';
				if (argv[argc]) {
					free(argv[argc]);
					argv[argc] = NULL;
				}
				argv[argc] = (char*)malloc(((buf + r) - ptr) + 1);
				strcpy(argv[argc++], ptr);
				ptr = buf + r + 1;
			}
		}
	}
	buf[BUFFER_LEN - 1] = '\0';
	strcpy(wbuf, ptr);
	return argc;
}


char *
cr2slash(char *buf, int buflen, const char *in)
{
	char *ptr = buf;
	const char *ptr2 = in;

	for (ptr = buf, ptr2 = in; *ptr2 && ptr-buf<buflen-3; ptr2++) {
		if (*ptr2 == '\r') {
			*(ptr++) = '\\';
			*(ptr++) = 'r';
		} else if (*ptr2 == ESCAPE_CHAR) {
			*(ptr++) = '\\';
			*(ptr++) = '[';
		} else if (*ptr2 == '`') {
			*(ptr++) = '\\';
			*(ptr++) = '`';
		} else if (*ptr2 == '\\') {
			*(ptr++) = '\\';
			*(ptr++) = '\\';
		} else {
			*(ptr++) = *ptr2;
		}
	}
	*(ptr++) = '\0';
	return buf;
}


static int mesg_rec_cnt = 0;
static int mesg_instr_cnt = 0;


/******** HOOK ********/
char *
mesg_parse(int descr, dbref player, dbref what, dbref perms, const char *inbuf, char *outbuf,
		   int maxchars, int mesgtyp)
{
	char wbuf[BUFFER_LEN];
	char buf[BUFFER_LEN];
	char buf2[BUFFER_LEN];
	char dbuf[BUFFER_LEN];
	char ebuf[BUFFER_LEN];
	char cmdbuf[MAX_MFUN_NAME_LEN + 1];
	const char *ptr;
	char *dptr;
	int p, q, s;
	int i;
	char *argv[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
	int argc = 0;
	int showtextflag = 0;
	int literalflag = 0;

	mesg_rec_cnt++;
	if (mesg_rec_cnt > 26) {
		char *zptr = get_mvar("how");
		snprintf(dbuf, sizeof(dbuf), "%s Recursion limit exceeded.", zptr);
		notify_nolisten(player, dbuf, 1);
		mesg_rec_cnt--;
		outbuf[0] = '\0';
		return NULL;
	}
	if (Typeof(player) == TYPE_GARBAGE) {
		mesg_rec_cnt--;
		outbuf[0] = '\0';
		return NULL;
	}
	if (Typeof(what) == TYPE_GARBAGE) {
		notify_nolisten(player, "MPI Error: Garbage trigger.", 1);
		mesg_rec_cnt--;
		outbuf[0] = '\0';
		return NULL;
	}
	strcpyn(wbuf, sizeof(wbuf), inbuf);
	for (p = q = 0; wbuf[p] && (p < maxchars - 1) && q < (maxchars - 1); p++) {
		if (wbuf[p] == '\\') {
			p++;
			showtextflag = 1;
			if (wbuf[p] == 'r') {
				outbuf[q++] = '\r';
			} else if (wbuf[p] == '[') {
				outbuf[q++] = ESCAPE_CHAR;
			} else {
				outbuf[q++] = wbuf[p];
			}
		} else if (wbuf[p] == MFUN_LITCHAR) {
			literalflag = (!literalflag);
		} else if (!literalflag && wbuf[p] == MFUN_LEADCHAR) {
			if (wbuf[p + 1] == MFUN_LEADCHAR) {
				showtextflag = 1;
				outbuf[q++] = wbuf[p++];
				ptr = "";
			} else {
				ptr = wbuf + (++p);
				s = 0;
				while (wbuf[p] && wbuf[p] != MFUN_LEADCHAR &&
					   !isspace(wbuf[p]) && wbuf[p] != MFUN_ARGSTART &&
					   wbuf[p] != MFUN_ARGEND && s < MAX_MFUN_NAME_LEN) {
					p++;
					s++;
				}
				if (s < MAX_MFUN_NAME_LEN &&
					(wbuf[p] == MFUN_ARGSTART || wbuf[p] == MFUN_ARGEND)) {
					int varflag;

					strncpy(cmdbuf, ptr, s);
					cmdbuf[s] = '\0';

					varflag = 0;
					if (*cmdbuf == '&') {
						s = find_mfn("sublist");
						varflag = 1;
					} else if (*cmdbuf) {
						s = find_mfn(cmdbuf);
					} else {
						s = 0;
					}
					if (s) {
						s--;
						if (++mesg_instr_cnt > tp_mpi_max_commands) {
							char *zptr = get_mvar("how");

							snprintf(dbuf, sizeof(dbuf), "%s %c%s%c: Instruction limit exceeded.",
									zptr, MFUN_LEADCHAR,
									(varflag ? cmdbuf : mfun_list[s].name), MFUN_ARGEND);
							notify_nolisten(player, dbuf, 1);
							mesg_rec_cnt--;
							outbuf[0] = '\0';
							return NULL;
						}
						for (i = 0; i < argc; i++) {
							free(argv[i]);
							argv[i] = NULL;
						}
						if (wbuf[p] == MFUN_ARGEND) {
							argc = 0;
						} else {
							argc = mfun_list[s].maxargs;
							if (argc < 0) {
								argc = mesg_args((wbuf + p + 1),
												 &argv[(varflag ? 1 : 0)],
												 MFUN_LEADCHAR, MFUN_ARGSEP,
												 MFUN_ARGEND, MFUN_LITCHAR,
												 (-argc) + (varflag ? 1 : 0));
							} else {
								argc = mesg_args((wbuf + p + 1),
												 &argv[(varflag ? 1 : 0)],
												 MFUN_LEADCHAR, MFUN_ARGSEP,
												 MFUN_ARGEND, MFUN_LITCHAR, (varflag ? 8 : 9));
							}
							if (argc == -1) {
								char *zptr = get_mvar("how");

								snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: End brace not found.",
										zptr, MFUN_LEADCHAR, cmdbuf, MFUN_ARGEND);
								notify_nolisten(player, ebuf, 1);
								for (i = 0; i < argc; i++) {
									free(argv[i + (varflag? 1 : 0)]);
								}
								mesg_rec_cnt--;
								outbuf[0] = '\0';
								return NULL;
							}
						}
						if (varflag) {
							char *zptr;

							zptr = get_mvar(cmdbuf + 1);
							if (!zptr) {
								zptr = get_mvar("how");
								snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: Unrecognized variable.",
										zptr, MFUN_LEADCHAR, cmdbuf, MFUN_ARGEND);
								notify_nolisten(player, ebuf, 1);
								for (i = 0; i < argc; i++) {
									if (argv[i + (varflag? 1 : 0)]) {
										free(argv[i + (varflag? 1 : 0)]);
									}
								}
								mesg_rec_cnt--;
								outbuf[0] = '\0';
								return NULL;
							}
							if (argv[0]) {
								free(argv[0]);
								argv[0] = NULL;
							}
							argv[0] = (char*)malloc(strlen(zptr) + 1);
							strcpy(argv[0], zptr);
							argc++;
						}
						if (mesgtyp & MPI_ISDEBUG) {
							char *zptr = get_mvar("how");

							snprintf(dbuf, sizeof(dbuf), "%s %*s%c%s%c", zptr,
									(mesg_rec_cnt * 2 - 4), "", MFUN_LEADCHAR,
									(varflag ? cmdbuf : mfun_list[s].name), MFUN_ARGSTART);
							for (i = (varflag ? 1 : 0); i < argc; i++) {
								if (i) {
									const char tbuf[] = { MFUN_ARGSEP, '\0' };
									strcatn(dbuf, sizeof(dbuf), tbuf);
								}
								cr2slash(ebuf, sizeof(ebuf)/8, argv[i]);
								strcatn(dbuf, sizeof(dbuf), "`");
								strcatn(dbuf, sizeof(dbuf), ebuf);
								if (strlen(ebuf) >= (sizeof(ebuf)/8)-2) {
									strcatn(dbuf, sizeof(dbuf), "...");
								}
								strcatn(dbuf, sizeof(dbuf), "`");
							}
							{
								const char tbuf[] = { MFUN_ARGEND, '\0' };
								strcatn(dbuf, sizeof(dbuf), tbuf);
							}
							notify_nolisten(player, dbuf, 1);
						}
						if (mfun_list[s].stripp) {
							for (i = (varflag ? 1 : 0); i < argc; i++) {
								strcpy(argv[i], stripspaces(buf, argv[i]));
							}
						}
						if (mfun_list[s].parsep) {
							for (i = (varflag ? 1 : 0); i < argc; i++) {
								ptr = MesgParse(argv[i], buf);
								if (!ptr) {
									char *zptr = get_mvar("how");

									snprintf(dbuf, sizeof(dbuf), "%s %c%s%c (arg %d)", zptr,
											MFUN_LEADCHAR,
											(varflag ? cmdbuf : mfun_list[s].name),
											MFUN_ARGEND, i + 1);
									notify_nolisten(player, dbuf, 1);
									for (i = 0; i < argc; i++) {
										free(argv[i]);
									}
									mesg_rec_cnt--;
									outbuf[0] = '\0';
									return NULL;
								}
								argv[i] = (char*)realloc(argv[i], strlen(buf) + 1);
								strcpy(argv[i], buf);
							}
						}
						if (mesgtyp & MPI_ISDEBUG) {
							char *zptr = get_mvar("how");

							snprintf(dbuf, sizeof(dbuf), "%.512s %*s%c%.512s%c", zptr,
									(mesg_rec_cnt * 2 - 4), "", MFUN_LEADCHAR,
									(varflag ? cmdbuf : mfun_list[s].name), MFUN_ARGSTART);
							for (i = (varflag ? 1 : 0); i < argc; i++) {
								if (i) {
									const char tbuf[] = { MFUN_ARGSEP, '\0' };
									strcatn(dbuf, sizeof(dbuf), tbuf);
								}
								cr2slash(ebuf, sizeof(ebuf)/8, argv[i]);
								strcatn(dbuf, sizeof(dbuf), "`");
								strcatn(dbuf, sizeof(dbuf), ebuf);
								if (strlen(ebuf) >= (sizeof(ebuf)/8)-2) {
									strcatn(dbuf, sizeof(dbuf), "...");
								}
								strcatn(dbuf, sizeof(dbuf), "`");
							}
							{
								const char tbuf[] = { MFUN_ARGEND, '\0' };
								strcatn(dbuf, sizeof(dbuf), tbuf);
							}
						}
						if (argc < mfun_list[s].minargs) {
							char *zptr = get_mvar("how");

							snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: Too few arguments",
									zptr, MFUN_LEADCHAR,
									(varflag ? cmdbuf : mfun_list[s].name), MFUN_ARGEND);
							notify_nolisten(player, ebuf, 1);
							for (i = 0; i < argc; i++) {
								free(argv[i]);
							}
							mesg_rec_cnt--;
							outbuf[0] = '\0';
							return NULL;
						} else if (mfun_list[s].maxargs > 0 && argc > mfun_list[s].maxargs) {
							char *zptr = get_mvar("how");

							snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: Too many arguments",
									zptr, MFUN_LEADCHAR,
									(varflag ? cmdbuf : mfun_list[s].name), MFUN_ARGEND);
							notify_nolisten(player, ebuf, 1);
							for (i = 0; i < argc; i++) {
								free(argv[i]);
							}
							mesg_rec_cnt--;
							outbuf[0] = '\0';
							return NULL;
						} else {
							ptr = mfun_list[s].mfn(descr, player, what, perms, argc,
												   argv, buf, mesgtyp);
							if (!ptr) {
								outbuf[q] = '\0';
								for (i = 0; i < argc; i++) {
									free(argv[i]);
								}
								mesg_rec_cnt--;
								outbuf[0] = '\0';
								return NULL;
							}
							if (mfun_list[s].postp) {
								dptr = MesgParse(ptr, buf);
								if (!dptr) {
									char *zptr = get_mvar("how");

									snprintf(ebuf, sizeof(ebuf), "%s %c%s%c (returned string)",
											zptr, MFUN_LEADCHAR,
											(varflag ? cmdbuf : mfun_list[s].name),
											MFUN_ARGEND);
									notify_nolisten(player, ebuf, 1);
									for (i = 0; i < argc; i++) {
										free(argv[i]);
									}
									mesg_rec_cnt--;
									outbuf[0] = '\0';
									return NULL;
								}
								ptr = dptr;
							}
						}
						if (mesgtyp & MPI_ISDEBUG) {
							strcatn(dbuf, sizeof(dbuf), " = `");
							cr2slash(ebuf, sizeof(ebuf)/8, ptr);
							strcatn(dbuf, sizeof(dbuf), ebuf);
							if (strlen(ebuf) >= (sizeof(ebuf)/8)-2) {
								strcatn(dbuf, sizeof(dbuf), "...");
							}
							strcatn(dbuf, sizeof(dbuf), "`");
							notify_nolisten(player, dbuf, 1);
						}
					} else if (msg_is_macro(player, what, perms, cmdbuf, mesgtyp)) {
						for (i = 0; i < argc; i++) {
							free(argv[i]);
							argv[i] = NULL;
						}
						if (wbuf[p] == MFUN_ARGEND) {
							argc = 0;
							p++;
						} else {
							p++;
							argc = mesg_args(wbuf + p, argv, MFUN_LEADCHAR,
											 MFUN_ARGSEP, MFUN_ARGEND, MFUN_LITCHAR, 9);
							if (argc == -1) {
								char *zptr = get_mvar("how");

								snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: End brace not found.",
										zptr, MFUN_LEADCHAR, cmdbuf, MFUN_ARGEND);
								notify_nolisten(player, ebuf, 1);
								for (i = 0; i < argc; i++) {
									free(argv[i]);
								}
								mesg_rec_cnt--;
								outbuf[0] = '\0';
								return NULL;
							}
						}
						msg_unparse_macro(player, what, perms, cmdbuf, argc,
										  argv, (wbuf + p), (BUFFER_LEN - p),
										  mesgtyp);
						p--;
						ptr = NULL;
					} else {
						/* unknown function */
						char *zptr = get_mvar("how");

						snprintf(ebuf, sizeof(ebuf), "%s %c%s%c: Unrecognized function.",
								zptr, MFUN_LEADCHAR, cmdbuf, MFUN_ARGEND);
						notify_nolisten(player, ebuf, 1);
						for (i = 0; i < argc; i++) {
							free(argv[i]);
						}
						mesg_rec_cnt--;
						outbuf[0] = '\0';
						return NULL;
					}
				} else {
					showtextflag = 1;
					ptr--;
					i = s + 1;
					while (ptr && *ptr && i-- && q < (maxchars - 1)) {
						outbuf[q++] = *(ptr++);
					}
					outbuf[q] = '\0';
					p = (int) (ptr - wbuf) - 1;
					ptr = "";	/* unknown substitution type */
				}
				while (ptr && *ptr && q < (maxchars - 1)) {
					outbuf[q++] = *(ptr++);
				}
			}
		} else {
			outbuf[q++] = wbuf[p];
			showtextflag = 1;
		}
	}
	outbuf[q] = '\0';
	if ((mesgtyp & MPI_ISDEBUG) && showtextflag) {
		char *zptr = get_mvar("how");

		snprintf(dbuf, sizeof(dbuf), "%s %*s`%.512s`",
		        zptr, (mesg_rec_cnt * 2 - 4), "",
				cr2slash(buf2, sizeof(buf2), outbuf));
		notify_nolisten(player, dbuf, 1);
	}
	for (i = 0; i < argc; i++) {
		free(argv[i]);
	}
	mesg_rec_cnt--;
	outbuf[maxchars - 1] = '\0';
	return (outbuf);
}

char *
do_parse_mesg_2(int descr, dbref player, dbref what, dbref perms, const char *inbuf,
				const char *abuf, char *outbuf, int mesgtyp)
{

	char howvar[BUFFER_LEN];
	char cmdvar[BUFFER_LEN];
	char argvar[BUFFER_LEN];
	char tmparg[BUFFER_LEN];
	char tmpcmd[BUFFER_LEN];
	char *dptr;
	int mvarcnt = varc;
	int mfunccnt = funcc;
	int tmprec_cnt = mesg_rec_cnt;
	int tmpinst_cnt = mesg_instr_cnt;

	abuf = uncompress(abuf);

	*outbuf = '\0';

	if ((mesgtyp & MPI_NOHOW) == 0)
	{
		if (new_mvar("how", howvar))
		{
			snprintf(howvar, sizeof(howvar), "%s Out of MPI variables.", abuf);
			notify_nolisten(player, howvar, 1);
			varc = mvarcnt;
			return outbuf;
		}
		strcpy(howvar, abuf);
	}

	if (new_mvar("cmd", cmdvar))
	{
		snprintf(cmdvar, sizeof(cmdvar), "%s Out of MPI variables.", abuf);
		notify_nolisten(player, cmdvar, 1);
		varc = mvarcnt;
		return outbuf;
	}
	strcpy(cmdvar, match_cmdname);
	strcpy(tmpcmd, match_cmdname);

	if (new_mvar("arg", argvar))
	{
		snprintf(argvar, sizeof(argvar), "%s Out of MPI variables.", abuf);
		notify_nolisten(player, argvar, 1);
		varc = mvarcnt;
		return outbuf;
	}
	strcpy(argvar, match_args);
	strcpy(tmparg, match_args);

	inbuf = uncompress(inbuf);

	dptr = MesgParse(inbuf, outbuf);
	if (!dptr) {
		*outbuf = '\0';
	}

	varc = mvarcnt;
	free_mfuncs(mfunccnt);
	mesg_rec_cnt = tmprec_cnt;
	mesg_instr_cnt = tmpinst_cnt;

	strcpy(match_cmdname, tmpcmd);
	strcpy(match_args, tmparg);


	return outbuf;
}


char *
do_parse_mesg(int descr, dbref player, dbref what, const char *inbuf, const char *abuf,
			  char *outbuf, int mesgtyp)
{
	if (tp_do_mpi_parsing) {
		char *tmp = NULL;
		struct timeval st, et;

		/* Quickie additions to do rough per-object MPI profiling */
		gettimeofday(&st,NULL);
		tmp = do_parse_mesg_2(descr, player, what, what, inbuf, abuf, outbuf, mesgtyp);
		gettimeofday(&et,NULL);
		if (strcmp(tmp,inbuf)) {
			if (st.tv_usec > et.tv_usec) {
				et.tv_usec += 1000000;
				et.tv_sec -= 1;
			}
			et.tv_usec -= st.tv_usec;
			et.tv_sec -= st.tv_sec;
			DBFETCH(what)->mpi_proftime.tv_sec += et.tv_sec;
			DBFETCH(what)->mpi_proftime.tv_usec += et.tv_usec;
			if (DBFETCH(what)->mpi_proftime.tv_usec >= 1000000) {
				DBFETCH(what)->mpi_proftime.tv_usec -= 1000000;
				DBFETCH(what)->mpi_proftime.tv_sec += 1;
			}
			DBFETCH(what)->mpi_prof_use++;
		}
		return(tmp);
	} else {
		strcpy(outbuf, inbuf);
	}
	return outbuf;
}

char *
do_parse_prop(int descr, dbref player, dbref what, const char *propname, const char *abuf, char *outbuf, int mesgtyp)
{
	const char* propval = get_property_class(what, propname);
	if (!propval)
		return NULL;
	if (Prop_Blessed(what, propname))
		mesgtyp |= MPI_ISBLESSED;
	return do_parse_mesg(descr, player, what, propval, abuf, outbuf, mesgtyp);
}