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/
/* functions.c - MUSH function handlers */
/* $Id: functions.c,v 1.174 2003/02/24 18:05:22 rmg 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 "command.h"	/* required by code */
#include "match.h"	/* required by code */
#include "attrs.h"	/* required by code */
#include "powers.h"	/* required by code */
#include "functions.h"	/* required by code */
#include "fnproto.h"	/* required by code */

extern int FDECL(parse_ext_access, (int *, EXTFUNCS **, char *, NAMETAB *, dbref, char *));
extern NAMETAB access_nametab[];

UFUN *ufun_head;

const Delim SPACE_DELIM = { 1, " " };

void NDECL(init_functab)
{
	FUN *fp;

	hashinit(&mudstate.func_htab, 250 * HASH_FACTOR, HT_STR|HT_KEYREF);
	
	for (fp = flist; fp->name; fp++) {
		hashadd((char *)fp->name, (int *)fp, &mudstate.func_htab, 0);
	}
	ufun_head = NULL;
	hashinit(&mudstate.ufunc_htab, 15 * HASH_FACTOR, HT_STR);
}

void do_function(player, cause, key, fname, target)
dbref player, cause;
int key;
char *fname, *target;
{
	UFUN *ufp, *ufp2;
	ATTR *ap;
	char *np, *bp;
	int atr, aflags;
	dbref obj, aowner;

	/* Check for list first */

	if (key & FUNCT_LIST) {
	    
	    if (fname && *fname) {

		/* Make it case-insensitive, and look it up. */

		for (bp = fname; *bp; bp++) {
		    *bp = tolower(*bp);
		}

		ufp = (UFUN *) hashfind(fname, &mudstate.ufunc_htab);

		if (ufp) {
		    notify(player,
			   tprintf("%s: #%d/%s",
				   ufp->name, ufp->obj, 
				   ((ATTR *) atr_num(ufp->atr))->name));
		} else {
		    notify(player,
			   tprintf("%s not found in user function table.",
				   fname));
		}
		return;
	    }

	    /* No name given, list them all. */

	    for (ufp = (UFUN *) hash_firstentry(&mudstate.ufunc_htab);
		 ufp != NULL;
		 ufp = (UFUN *) hash_nextentry(&mudstate.ufunc_htab)) {
		notify(player,
		       tprintf("%s: #%d/%s",
			       ufp->name, ufp->obj, 
			       ((ATTR *) atr_num(ufp->atr))->name));
	    }
	    return;
	}


	/* Make a local uppercase copy of the function name */

	bp = np = alloc_sbuf("add_user_func");
	safe_sb_str(fname, np, &bp);
	*bp = '\0';
	for (bp = np; *bp; bp++)
		*bp = toupper(*bp);

	/* Verify that the function doesn't exist in the builtin table */

	if (hashfind(np, &mudstate.func_htab) != NULL) {
		notify_quiet(player,
		     "Function already defined in builtin function table.");
		free_sbuf(np);
		return;
	}
	/* Make sure the target object exists */

	if (!parse_attrib(player, target, &obj, &atr, 0)) {
		notify_quiet(player, NOMATCH_MESSAGE);
		free_sbuf(np);
		return;
	}
	/* Make sure the attribute exists */

	if (atr == NOTHING) {
		notify_quiet(player, "No such attribute.");
		free_sbuf(np);
		return;
	}
	/* Make sure attribute is readably by me */

	ap = atr_num(atr);
	if (!ap) {
		notify_quiet(player, "No such attribute.");
		free_sbuf(np);
		return;
	}
	atr_get_info(obj, atr, &aowner, &aflags);
	if (!See_attr(player, obj, ap, aowner, aflags)) {
		notify_quiet(player, NOPERM_MESSAGE);
		free_sbuf(np);
		return;
	}
	/* Privileged functions require you control the obj.  */

	if ((key & FUNCT_PRIV) && !Controls(player, obj)) {
		notify_quiet(player, NOPERM_MESSAGE);
		free_sbuf(np);
		return;
	}
	/* See if function already exists.  If so, redefine it */

	ufp = (UFUN *) hashfind(np, &mudstate.ufunc_htab);

	if (!ufp) {
		ufp = (UFUN *) XMALLOC(sizeof(UFUN), "do_function");
		ufp->name = XSTRDUP(np, "do_function.name");
		for (bp = (char *)ufp->name; *bp; bp++)
			*bp = toupper(*bp);
		ufp->obj = obj;
		ufp->atr = atr;
		ufp->perms = CA_PUBLIC;
		ufp->next = NULL;
		if (!ufun_head) {
			ufun_head = ufp;
		} else {
			for (ufp2 = ufun_head; ufp2->next; ufp2 = ufp2->next) ;
			ufp2->next = ufp;
		}
		if (hashadd(np, (int *) ufp, &mudstate.ufunc_htab, 0)) {
			notify_quiet(player, tprintf("Function %s not defined.", fname));
			XFREE(ufp->name, "do_function");
			XFREE(ufp, "do_function.2");
			free_sbuf(np);
			return;
		}
        }
	ufp->obj = obj;
	ufp->atr = atr;

	ufp->flags = 0;
	if (key & FUNCT_NO_EVAL)
	    ufp->flags |= FN_NO_EVAL;
	if (key & FUNCT_PRIV)
	    ufp->flags |= FN_PRIV;
	if (key & FUNCT_PRES)
	    ufp->flags |= FN_PRES;

	free_sbuf(np);
	if (!Quiet(player))
		notify_quiet(player, tprintf("Function %s defined.", fname));
}

/* ---------------------------------------------------------------------------
 * list_functable: List available functions.
 */

void list_functable(player)
dbref player;
{
	FUN *fp, *modfns;
	UFUN *ufp;
	char *buf, *bp;
	MODULE *mp;

	buf = alloc_lbuf("list_functable");

	bp = buf;
	safe_str((char *)"Built-in functions:", buf, &bp);
	for (fp = flist; fp->name; fp++) {
		if (Check_Func_Access(player, fp)) {
		    safe_chr(' ', buf, &bp);
		    safe_str((char *) fp->name, buf, &bp);
		}
	}
	notify(player, buf);

	WALK_ALL_MODULES(mp) {
	    if ((modfns = DLSYM_VAR(mp->handle, mp->modname, "functable",
				    FUN *)) != NULL) {
		bp = buf;
		safe_tprintf_str(buf, &bp, "Module %s functions:",
				 mp->modname);
		for (fp = modfns; fp->name; fp++) {
		    if (Check_Func_Access(player, fp)) {
			safe_chr(' ', buf, &bp);
			safe_str((char *) fp->name, buf, &bp);
		    }
		}
		notify(player, buf);
	    }
	}

	bp = buf;
	safe_str((char *)"User-defined functions:", buf, &bp);
	for (ufp = ufun_head; ufp; ufp = ufp->next) {
		if (check_access(player, ufp->perms)) {
		    safe_chr(' ', buf, &bp);
		    safe_str(ufp->name, buf, &bp);
		}
	}
	notify(player, buf);

	free_lbuf(buf);
}

/* ---------------------------------------------------------------------------
 * list_funcaccess: List access on functions.
 */

static void helper_list_funcaccess(player, fp, buff)
dbref player;
FUN *fp;
char *buff;
{
	char *bp;
	int i;

	while (fp->name) {
		if (Check_Func_Access(player, fp)) {
		    if (!fp->xperms) {
			sprintf(buff, "%s:", fp->name);
		    } else {
			bp = buff;
			safe_str((char *) fp->name, buff, &bp);
			safe_chr(':', buff, &bp);
			for (i = 0; i < fp->xperms->num_funcs; i++) {
			    if (fp->xperms->ext_funcs[i]) {
				safe_chr(' ', buff, &bp);
				safe_str(fp->xperms->ext_funcs[i]->fn_name,
					 buff, &bp);
			    }
			}
		    }
		    listset_nametab(player, access_nametab,
				    fp->perms, buff, 1);
		}
		fp++;
	}
}

void list_funcaccess(player)
dbref player;
{
	char *buff;
	FUN *ftab;
        UFUN *ufp;
	MODULE *mp;

	buff = alloc_sbuf("list_funcaccess");
	helper_list_funcaccess(player, flist, buff);

	WALK_ALL_MODULES(mp) {
		if ((ftab = DLSYM_VAR(mp->handle, mp->modname, "functable",
				      FUN *)) != NULL) {
			helper_list_funcaccess(player, ftab, buff);
		}
	}

	for (ufp = ufun_head; ufp; ufp = ufp->next) {
		if (check_access(player, ufp->perms)) {
			sprintf(buff, "%s:", ufp->name);
			listset_nametab(player, access_nametab,
					ufp->perms, buff, 1);
		}
	}

	free_sbuf(buff);
}


/* ---------------------------------------------------------------------------
 * cf_func_access: set access on functions
 */

CF_HAND(cf_func_access)
{
	FUN *fp;
	UFUN *ufp;
	char *ap;

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

	for (fp = flist; fp->name; fp++) {
		if (!string_compare(fp->name, str)) {
			return (parse_ext_access(&fp->perms, &fp->xperms,
						 ap, (NAMETAB *) extra,
						 player, cmd));
		}
	}
	for (ufp = ufun_head; ufp; ufp = ufp->next) {
		if (!string_compare(ufp->name, str)) {
			return (cf_modify_bits(&ufp->perms, ap, extra,
					       player, cmd));
		}
	}
	cf_log_notfound(player, cmd, "Function", str);
	return -1;
}