/* command.c - command parser and support routines */
/* $Id: command.c,v 1.117.4.2 2000/06/01 15:19:41 rmg Exp $ */
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "mudconf.h"
#include "command.h"
#include "functions.h"
#include "externs.h"
#include "match.h"
#include "attrs.h"
#include "flags.h"
#include "powers.h"
#include "alloc.h"
#include "vattr.h"
#include "mail.h"
#include "db_sql.h"
extern void FDECL(list_cf_access, (dbref));
extern void FDECL(list_cf_read_access, (dbref));
extern void FDECL(list_siteinfo, (dbref));
extern void FDECL(logged_out, (dbref, dbref, int, char *));
extern void NDECL(boot_slave);
extern void NDECL(vattr_clean_db);
extern void NDECL(match_zone_exit);
#ifndef MEMORY_BASED
extern void FDECL(list_cached_objs, (dbref));
#endif
#ifdef USE_COMSYS
extern int FDECL(do_comsys, (dbref, char *));
#endif
#define CACHING "object"
#define NOGO_MESSAGE "You can't go that way."
/* Take care of all the assorted problems associated with getrusage(). */
#ifdef hpux
#define HAVE_GETRUSAGE 1
#include <sys/syscall.h>
#define getrusage(x,p) syscall(SYS_GETRUSAGE,x,p)
#endif
#ifdef _SEQUENT_
#define HAVE_GET_PROCESS_STATS 1
#include <sys/procstats.h>
#endif
/* ---------------------------------------------------------------------------
* Hook macros.
*
* We never want to call hooks in the case of @addcommand'd commands
* (both for efficiency reasons and the fact that we might NOT match an
* @addcommand even if we've been told there is one), but we leave this
* to the hook-adder to prevent.
*/
#define CALL_PRE_HOOK(x,a,na) \
if (((x)->pre_hook != NULL) && !((x)->callseq & CS_ADDED)) { \
process_hook((x)->pre_hook, (x)->callseq & CS_PRESERVE, \
player, cause, (a), (na)); \
}
#define CALL_POST_HOOK(x,a,na) \
if (((x)->post_hook != NULL) && !((x)->callseq & CS_ADDED)) { \
process_hook((x)->post_hook, (x)->callseq & CS_PRESERVE, \
player, cause, (a), (na)); \
}
/* ---------------------------------------------------------------------------
* Switch tables for the various commands.
*/
/* *INDENT-OFF* */
NAMETAB attrib_sw[] = {
{(char *)"access", 1, CA_GOD, ATTRIB_ACCESS},
{(char *)"delete", 1, CA_GOD, ATTRIB_DELETE},
{(char *)"info", 1, CA_WIZARD, ATTRIB_INFO},
{(char *)"rename", 1, CA_GOD, ATTRIB_RENAME},
{ NULL, 0, 0, 0}};
NAMETAB boot_sw[] = {
{(char *)"port", 1, CA_WIZARD, BOOT_PORT|SW_MULTIPLE},
{(char *)"quiet", 1, CA_WIZARD, BOOT_QUIET|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
#ifdef USE_COMSYS
NAMETAB cboot_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, CBOOT_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB cemit_sw[] = {
{(char *)"noheader", 1, CA_PUBLIC, CEMIT_NOHEADER},
{ NULL, 0, 0, 0}};
NAMETAB channel_sw[] = {
{(char *)"charge", 1, CA_PUBLIC, CHANNEL_CHARGE},
{(char *)"desc", 1, CA_PUBLIC, CHANNEL_DESC},
{(char *)"lock", 1, CA_PUBLIC, CHANNEL_LOCK},
{(char *)"owner", 1, CA_PUBLIC, CHANNEL_OWNER},
{(char *)"set", 1, CA_PUBLIC, CHANNEL_SET},
{(char *)"join", 1, CA_PUBLIC, CHANNEL_JOIN | SW_MULTIPLE},
{(char *)"transmit", 1, CA_PUBLIC, CHANNEL_TRANS | SW_MULTIPLE},
{(char *)"receive", 1, CA_PUBLIC, CHANNEL_RECV | SW_MULTIPLE},
{ NULL, 0, 0, 0}};
#endif /* USE_COMSYS */
NAMETAB chown_sw[] = {
{(char *)"nostrip", 1, CA_WIZARD, CHOWN_NOSTRIP},
{ NULL, 0, 0, 0}};
NAMETAB clone_sw[] = {
{(char *)"cost", 1, CA_PUBLIC, CLONE_SET_COST|SW_MULTIPLE},
{(char *)"inherit", 3, CA_PUBLIC, CLONE_INHERIT|SW_MULTIPLE},
{(char *)"inventory", 3, CA_PUBLIC, CLONE_INVENTORY},
{(char *)"location", 1, CA_PUBLIC, CLONE_LOCATION},
{(char *)"nostrip", 1, CA_WIZARD, CLONE_NOSTRIP|SW_MULTIPLE},
{(char *)"parent", 2, CA_PUBLIC, CLONE_PARENT|SW_MULTIPLE},
{(char *)"preserve", 2, CA_PUBLIC, CLONE_PRESERVE|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
#ifdef USE_COMSYS
NAMETAB clist_sw[] = {
{(char *)"full", 0, CA_PUBLIC, CLIST_FULL},
{ NULL, 0, 0, 0}};
NAMETAB cwho_sw[] = {
{(char *)"all", 0, CA_PUBLIC, CWHO_ALL},
{ NULL, 0, 0, 0}};
#endif /* USE_COMSYS */
NAMETAB decomp_sw[] = {
{(char *)"dbref", 1, CA_PUBLIC, DECOMP_DBREF},
{(char *)"pretty", 1, CA_PUBLIC, DECOMP_PRETTY},
{ NULL, 0, 0, 0}};
NAMETAB destroy_sw[] = {
{(char *)"instant", 4, CA_PUBLIC, DEST_INSTANT|SW_MULTIPLE},
{(char *)"override", 8, CA_PUBLIC, DEST_OVERRIDE|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB dig_sw[] = {
{(char *)"teleport", 1, CA_PUBLIC, DIG_TELEPORT},
{ NULL, 0, 0, 0}};
NAMETAB doing_sw[] = {
{(char *)"header", 1, CA_PUBLIC, DOING_HEADER},
{(char *)"message", 1, CA_PUBLIC, DOING_MESSAGE},
{(char *)"poll", 1, CA_PUBLIC, DOING_POLL},
{ NULL, 0, 0, 0}};
NAMETAB dolist_sw[] = {
{(char *)"delimit", 1, CA_PUBLIC, DOLIST_DELIMIT},
{(char *)"space", 1, CA_PUBLIC, DOLIST_SPACE},
{(char *)"notify", 1, CA_PUBLIC, DOLIST_NOTIFY | SW_MULTIPLE },
{ NULL, 0, 0, 0,}};
NAMETAB drop_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, DROP_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB dump_sw[] = {
{(char *)"structure", 1, CA_WIZARD, DUMP_STRUCT|SW_MULTIPLE},
{(char *)"text", 1, CA_WIZARD, DUMP_TEXT|SW_MULTIPLE},
{(char *)"flatfile", 1, CA_WIZARD, DUMP_FLATFILE|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB emit_sw[] = {
{(char *)"here", 1, CA_PUBLIC, SAY_HERE|SW_MULTIPLE},
{(char *)"room", 1, CA_PUBLIC, SAY_ROOM|SW_MULTIPLE},
#ifdef PUEBLO_SUPPORT
{(char *)"html", 1, CA_PUBLIC, SAY_HTML|SW_MULTIPLE},
#endif
{ NULL, 0, 0, 0}};
NAMETAB enter_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, MOVE_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB examine_sw[] = {
{(char *)"brief", 1, CA_PUBLIC, EXAM_BRIEF},
{(char *)"debug", 1, CA_WIZARD, EXAM_DEBUG},
{(char *)"full", 1, CA_PUBLIC, EXAM_LONG},
{(char *)"owner", 1, CA_PUBLIC, EXAM_OWNER},
{(char *)"pairs", 3, CA_PUBLIC, EXAM_PAIRS},
{(char *)"parent", 1, CA_PUBLIC, EXAM_PARENT|SW_MULTIPLE},
{(char *)"pretty", 2, CA_PUBLIC, EXAM_PRETTY},
{ NULL, 0, 0, 0}};
NAMETAB femit_sw[] = {
{(char *)"here", 1, CA_PUBLIC, PEMIT_HERE|SW_MULTIPLE},
{(char *)"room", 1, CA_PUBLIC, PEMIT_ROOM|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB fixdb_sw[] = {
/* {(char *)"add_pname",1, CA_GOD, FIXDB_ADD_PN}, */
{(char *)"contents", 1, CA_GOD, FIXDB_CON},
{(char *)"exits", 1, CA_GOD, FIXDB_EXITS},
{(char *)"location", 1, CA_GOD, FIXDB_LOC},
{(char *)"next", 1, CA_GOD, FIXDB_NEXT},
{(char *)"owner", 1, CA_GOD, FIXDB_OWNER},
{(char *)"pennies", 1, CA_GOD, FIXDB_PENNIES},
{(char *)"rename", 1, CA_GOD, FIXDB_NAME},
/* {(char *)"rm_pname", 1, CA_GOD, FIXDB_DEL_PN}, */
{ NULL, 0, 0, 0}};
NAMETAB fpose_sw[] = {
{(char *)"default", 1, CA_PUBLIC, 0},
{(char *)"nospace", 1, CA_PUBLIC, SAY_NOSPACE},
{ NULL, 0, 0, 0}};
NAMETAB function_sw[] = {
{(char *)"noeval", 1, CA_WIZARD, FN_NO_EVAL|SW_MULTIPLE},
{(char *)"privileged", 3, CA_WIZARD, FN_PRIV|SW_MULTIPLE},
{(char *)"preserve", 3, CA_WIZARD, FN_PRES|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB get_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, GET_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB give_sw[] = {
{(char *)"quiet", 1, CA_WIZARD, GIVE_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB goto_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, MOVE_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB halt_sw[] = {
{(char *)"all", 1, CA_PUBLIC, HALT_ALL},
{ NULL, 0, 0, 0}};
NAMETAB hook_sw[] = {
{(char *)"before", 1, CA_GOD, HOOK_BEFORE},
{(char *)"after", 1, CA_GOD, HOOK_AFTER},
{(char *)"preserve", 1, CA_GOD, HOOK_PRESERVE},
{(char *)"nopreserve", 1, CA_GOD, HOOK_NOPRESERVE},
{ NULL, 0, 0, 0}};
NAMETAB leave_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, MOVE_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB listmotd_sw[] = {
{(char *)"brief", 1, CA_WIZARD, MOTD_BRIEF},
{ NULL, 0, 0, 0}};
NAMETAB lock_sw[] = {
{(char *)"chownlock", 2, CA_PUBLIC, A_LCHOWN},
{(char *)"controllock", 2, CA_PUBLIC, A_LCONTROL},
{(char *)"defaultlock", 1, CA_PUBLIC, A_LOCK},
{(char *)"droplock", 1, CA_PUBLIC, A_LDROP},
{(char *)"enterlock", 1, CA_PUBLIC, A_LENTER},
{(char *)"givelock", 1, CA_PUBLIC, A_LGIVE},
{(char *)"leavelock", 2, CA_PUBLIC, A_LLEAVE},
{(char *)"linklock", 2, CA_PUBLIC, A_LLINK},
{(char *)"pagelock", 3, CA_PUBLIC, A_LPAGE},
{(char *)"parentlock", 3, CA_PUBLIC, A_LPARENT},
{(char *)"receivelock", 1, CA_PUBLIC, A_LRECEIVE},
{(char *)"teloutlock", 2, CA_PUBLIC, A_LTELOUT},
{(char *)"tportlock", 2, CA_PUBLIC, A_LTPORT},
{(char *)"uselock", 1, CA_PUBLIC, A_LUSE},
{(char *)"userlock", 4, CA_PUBLIC, A_LUSER},
{(char *)"speechlock", 1, CA_PUBLIC, A_LSPEECH},
{ NULL, 0, 0, 0}};
NAMETAB look_sw[] = {
{(char *)"outside", 1, CA_PUBLIC, LOOK_OUTSIDE},
{ NULL, 0, 0, 0}};
#ifdef USE_MAIL
NAMETAB mail_sw[] = {
{(char *)"abort", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ABORT},
{(char *)"alias", 4, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ALIAS},
{(char *)"alist", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_ALIST},
{(char *)"cc", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_CC},
{(char *)"clear", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_CLEAR},
{(char *)"debug", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_DEBUG},
{(char *)"dstats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_DSTATS},
{(char *)"edit", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_EDIT},
{(char *)"file", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FILE},
{(char *)"folder", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FOLDER},
{(char *)"forward", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FORWARD},
{(char *)"fstats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FSTATS},
{(char *)"fwd", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_FORWARD},
{(char *)"list", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_LIST},
{(char *)"nuke", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_NUKE},
{(char *)"proof", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_PROOF},
{(char *)"purge", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_PURGE},
{(char *)"quick", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_QUICK},
{(char *)"quote", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_QUOTE|SW_MULTIPLE},
{(char *)"read", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_READ},
{(char *)"reply", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REPLY},
{(char *)"replyall", 6, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REPLYALL},
{(char *)"retract", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_RETRACT},
{(char *)"review", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_REVIEW},
{(char *)"safe", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_SAFE},
{(char *)"send", 0, CA_NO_SLAVE|CA_NO_GUEST, MAIL_SEND},
{(char *)"stats", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_STATS},
{(char *)"tag", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_TAG},
{(char *)"unclear", 1, CA_NO_SLAVE|CA_NO_GUEST, MAIL_UNCLEAR},
{(char *)"untag", 3, CA_NO_SLAVE|CA_NO_GUEST, MAIL_UNTAG},
{(char *)"urgent", 2, CA_NO_SLAVE|CA_NO_GUEST, MAIL_URGENT},
{ NULL, 0, 0, 0}};
NAMETAB malias_sw[] = {
{(char *)"desc", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_DESC},
{(char *)"chown", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_CHOWN},
{(char *)"add", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_ADD},
{(char *)"remove", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_REMOVE},
{(char *)"delete", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_DELETE},
{(char *)"rename", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_RENAME},
{(char *)"list", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_LIST},
{(char *)"status", 1, CA_NO_SLAVE|CA_NO_GUEST, MALIAS_STATUS},
{ NULL, 0, 0, 0}};
#endif
NAMETAB mark_sw[] = {
{(char *)"set", 1, CA_PUBLIC, MARK_SET},
{(char *)"clear", 1, CA_PUBLIC, MARK_CLEAR},
{ NULL, 0, 0, 0}};
NAMETAB markall_sw[] = {
{(char *)"set", 1, CA_PUBLIC, MARK_SET},
{(char *)"clear", 1, CA_PUBLIC, MARK_CLEAR},
{ NULL, 0, 0, 0}};
NAMETAB motd_sw[] = {
{(char *)"brief", 1, CA_WIZARD, MOTD_BRIEF|SW_MULTIPLE},
{(char *)"connect", 1, CA_WIZARD, MOTD_ALL},
{(char *)"down", 1, CA_WIZARD, MOTD_DOWN},
{(char *)"full", 1, CA_WIZARD, MOTD_FULL},
{(char *)"list", 1, CA_PUBLIC, MOTD_LIST},
{(char *)"wizard", 1, CA_WIZARD, MOTD_WIZ},
{ NULL, 0, 0, 0}};
NAMETAB notify_sw[] = {
{(char *)"all", 1, CA_PUBLIC, NFY_NFYALL},
{(char *)"first", 1, CA_PUBLIC, NFY_NFY},
{ NULL, 0, 0, 0}};
NAMETAB open_sw[] = {
{(char *)"inventory", 1, CA_PUBLIC, OPEN_INVENTORY},
{(char *)"location", 1, CA_PUBLIC, OPEN_LOCATION},
{ NULL, 0, 0, 0}};
NAMETAB pemit_sw[] = {
{(char *)"contents", 1, CA_PUBLIC, PEMIT_CONTENTS|SW_MULTIPLE},
{(char *)"object", 1, CA_PUBLIC, 0},
{(char *)"silent", 1, CA_PUBLIC, 0},
{(char *)"list", 1, CA_PUBLIC, PEMIT_LIST|SW_MULTIPLE},
{(char *)"noeval", 1, CA_PUBLIC, SW_NOEVAL | SW_MULTIPLE},
#ifdef PUEBLO_SUPPORT
{(char *)"html", 1, CA_PUBLIC, PEMIT_HTML|SW_MULTIPLE},
#endif
{ NULL, 0, 0, 0}};
NAMETAB pose_sw[] = {
{(char *)"default", 1, CA_PUBLIC, 0},
{(char *)"nospace", 1, CA_PUBLIC, SAY_NOSPACE},
{ NULL, 0, 0, 0}};
NAMETAB ps_sw[] = {
{(char *)"all", 1, CA_PUBLIC, PS_ALL|SW_MULTIPLE},
{(char *)"brief", 1, CA_PUBLIC, PS_BRIEF},
{(char *)"long", 1, CA_PUBLIC, PS_LONG},
{(char *)"summary", 1, CA_PUBLIC, PS_SUMM},
{ NULL, 0, 0, 0}};
NAMETAB quota_sw[] = {
{(char *)"all", 1, CA_GOD, QUOTA_ALL|SW_MULTIPLE},
{(char *)"fix", 1, CA_WIZARD, QUOTA_FIX},
{(char *)"remaining", 1, CA_WIZARD, QUOTA_REM|SW_MULTIPLE},
{(char *)"set", 1, CA_WIZARD, QUOTA_SET},
{(char *)"total", 1, CA_WIZARD, QUOTA_TOT|SW_MULTIPLE},
{(char *)"room", 1, CA_WIZARD, QUOTA_ROOM | SW_MULTIPLE},
{(char *)"exit", 1, CA_WIZARD, QUOTA_EXIT | SW_MULTIPLE},
{(char *)"thing", 1, CA_WIZARD, QUOTA_THING | SW_MULTIPLE},
{(char *)"player", 1, CA_WIZARD, QUOTA_PLAYER | SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB set_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, SET_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB shutdown_sw[] = {
{(char *)"abort", 1, CA_WIZARD, SHUTDN_COREDUMP},
{ NULL, 0, 0, 0}};
NAMETAB stats_sw[] = {
{(char *)"all", 1, CA_PUBLIC, STAT_ALL},
{(char *)"me", 1, CA_PUBLIC, STAT_ME},
{(char *)"player", 1, CA_PUBLIC, STAT_PLAYER},
{ NULL, 0, 0, 0}};
NAMETAB sweep_sw[] = {
{(char *)"commands", 3, CA_PUBLIC, SWEEP_COMMANDS|SW_MULTIPLE},
{(char *)"connected", 3, CA_PUBLIC, SWEEP_CONNECT|SW_MULTIPLE},
{(char *)"exits", 1, CA_PUBLIC, SWEEP_EXITS|SW_MULTIPLE},
{(char *)"here", 1, CA_PUBLIC, SWEEP_HERE|SW_MULTIPLE},
{(char *)"inventory", 1, CA_PUBLIC, SWEEP_ME|SW_MULTIPLE},
{(char *)"listeners", 1, CA_PUBLIC, SWEEP_LISTEN|SW_MULTIPLE},
{(char *)"players", 1, CA_PUBLIC, SWEEP_PLAYER|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB switch_sw[] = {
{(char *)"all", 1, CA_PUBLIC, SWITCH_ANY},
{(char *)"default", 1, CA_PUBLIC, SWITCH_DEFAULT},
{(char *)"first", 1, CA_PUBLIC, SWITCH_ONE},
{ NULL, 0, 0, 0}};
NAMETAB teleport_sw[] = {
{(char *)"loud", 1, CA_PUBLIC, TELEPORT_DEFAULT},
{(char *)"quiet", 1, CA_PUBLIC, TELEPORT_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB timecheck_sw[] = {
{(char *) "log", 1, CA_WIZARD, TIMECHK_LOG | SW_MULTIPLE},
{(char *) "reset", 1, CA_WIZARD, TIMECHK_RESET | SW_MULTIPLE},
{(char *) "screen", 1, CA_WIZARD, TIMECHK_SCREEN | SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB toad_sw[] = {
{(char *)"no_chown", 1, CA_WIZARD, TOAD_NO_CHOWN|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB trig_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, TRIG_QUIET},
{ NULL, 0, 0, 0}};
NAMETAB wall_sw[] = {
{(char *)"emit", 1, CA_PUBLIC, SAY_WALLEMIT},
{(char *)"no_prefix", 1, CA_PUBLIC, SAY_NOTAG|SW_MULTIPLE},
{(char *)"pose", 1, CA_PUBLIC, SAY_WALLPOSE},
{(char *)"wizard", 1, CA_PUBLIC, SAY_WIZSHOUT|SW_MULTIPLE},
{(char *)"admin", 1, CA_ADMIN, SAY_ADMINSHOUT},
{ NULL, 0, 0, 0}};
NAMETAB warp_sw[] = {
{(char *)"check", 1, CA_WIZARD, TWARP_CLEAN|SW_MULTIPLE},
{(char *)"dump", 1, CA_WIZARD, TWARP_DUMP|SW_MULTIPLE},
{(char *)"idle", 1, CA_WIZARD, TWARP_IDLE|SW_MULTIPLE},
{(char *)"queue", 1, CA_WIZARD, TWARP_QUEUE|SW_MULTIPLE},
{(char *)"events", 1, CA_WIZARD, TWARP_EVENTS|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
/* ---------------------------------------------------------------------------
* Command table: Definitions for builtin commands, used to build the command
* hash table.
*
* Format: Name Switches Permissions Needed
* Key (if any) Calling Seq Handler
*/
CMDENT command_table[] = {
{(char *)"@@", NULL, CA_PUBLIC,
0, CS_NO_ARGS,
NULL, NULL, do_comment},
{(char *)"@addcommand", NULL, CA_GOD,
0, CS_TWO_ARG,
NULL, NULL, do_addcommand},
{(char *)"@admin", NULL, CA_WIZARD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_admin},
{(char *)"@alias", NULL, CA_NO_GUEST|CA_NO_SLAVE,
0, CS_TWO_ARG,
NULL, NULL, do_alias},
{(char *)"@apply_marked", NULL, CA_WIZARD|CA_GBL_INTERP,
0, CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,
NULL, NULL, do_apply_marked},
{(char *)"@attribute", attrib_sw, CA_WIZARD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_attribute},
{(char *)"@boot", boot_sw, CA_NO_GUEST|CA_NO_SLAVE,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_boot},
#ifdef USE_COMSYS
{(char *)"@cboot", cboot_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG,
NULL, NULL, do_cboot},
{(char *)"@ccreate", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_ONE_ARG,
NULL, NULL, do_ccreate},
{(char *)"@cdestroy", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_ONE_ARG,
NULL, NULL, do_cdestroy},
{(char *)"@cemit", cemit_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG,
NULL, NULL, do_cemit},
{(char *)"@channel", channel_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG,
NULL, NULL, do_channel},
#endif /* USE_COMSYS */
{(char *)"@chown", chown_sw,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
CHOWN_ONE, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_chown},
{(char *)"@chownall", chown_sw, CA_WIZARD|CA_GBL_BUILD,
CHOWN_ALL, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_chownall},
{(char *)"@chzone", NULL,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_chzone},
{(char *)"@clone", clone_sw,
CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_clone},
#ifdef USE_COMSYS
{(char *)"@clist", clist_sw, CA_NO_SLAVE,
0, CS_ONE_ARG,
NULL, NULL, do_clist},
#endif
{(char *)"@cpattr", NULL,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_ARGV,
NULL, NULL, do_cpattr},
{(char *)"@create", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_create},
{(char *)"@cron", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_cron},
{(char *)"@crondel", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_crondel},
{(char *)"@crontab", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_crontab},
{(char *)"@cut", NULL, CA_WIZARD|CA_LOCATION,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_cut},
#ifdef USE_COMSYS
{(char *)"@cwho", cwho_sw, CA_NO_SLAVE,
0, CS_ONE_ARG,
NULL, NULL, do_cwho},
#endif
{(char *)"@dbck", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_dbck},
{(char *)"@dbclean", NULL, CA_GOD,
0, CS_NO_ARGS,
NULL, NULL, do_dbclean},
{(char *)"@decompile", decomp_sw, CA_PUBLIC,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_decomp},
{(char *)"@delcommand", NULL, CA_GOD,
0, CS_TWO_ARG,
NULL, NULL, do_delcommand},
{(char *)"@destroy", destroy_sw,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
DEST_ONE, CS_ONE_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_destroy},
/*{(char *)"@destroyall", NULL, CA_WIZARD|CA_GBL_BUILD,
DEST_ALL, CS_ONE_ARG,
NULL, NULL, do_destroy}, */
{(char *)"@dig", dig_sw,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP,
NULL, NULL, do_dig},
{(char *)"@disable", NULL, CA_WIZARD,
GLOB_DISABLE, CS_ONE_ARG,
NULL, NULL, do_global},
{(char *)"@doing", doing_sw, CA_PUBLIC,
0, CS_ONE_ARG,
NULL, NULL, do_doing},
{(char *)"@dolist", dolist_sw, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,
NULL, NULL, do_dolist},
{(char *)"@drain", NULL,
CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,
NFY_DRAIN, CS_TWO_ARG,
NULL, NULL, do_notify},
{(char *)"@dump", dump_sw, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_dump},
{(char *)"@edit", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_ARGV|CS_STRIP_AROUND,
NULL, NULL, do_edit},
{(char *)"@emit", emit_sw,
CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,
SAY_EMIT, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_say},
{(char *)"@enable", NULL, CA_WIZARD,
GLOB_ENABLE, CS_ONE_ARG,
NULL, NULL, do_global},
{(char *)"@entrances", NULL, CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_entrances},
{(char *)"@eval", NULL, CA_NO_SLAVE,
0, CS_ONE_ARG | CS_INTERP,
NULL, NULL, do_eval},
{(char *)"@femit", femit_sw,
CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,
PEMIT_FEMIT, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"@find", NULL, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_find},
{(char *)"@fixdb", fixdb_sw, CA_GOD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_fixdb},
{(char *)"@force", NULL,
CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST,
FRC_COMMAND, CS_TWO_ARG|CS_INTERP|CS_CMDARG,
NULL, NULL, do_force},
{(char *)"@fpose", fpose_sw, CA_LOCATION|CA_NO_SLAVE,
PEMIT_FPOSE, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"@fsay", NULL, CA_LOCATION|CA_NO_SLAVE,
PEMIT_FSAY, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"@freelist", NULL, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_freelist},
{(char *)"@function", function_sw, CA_GOD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_function},
{(char *)"@halt", halt_sw, CA_NO_SLAVE,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_halt},
{(char *)"@hashresize", NULL, CA_GOD,
0, CS_NO_ARGS,
NULL, NULL, do_hashresize},
{(char *)"@hook", hook_sw, CA_GOD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_hook},
{(char *)"@kick", NULL, CA_WIZARD,
QUEUE_KICK, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_queue},
{(char *)"@last", NULL, CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_last},
{(char *)"@link", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_link},
{(char *)"@list", NULL, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_list},
{(char *)"@listcommands", NULL, CA_GOD,
0, CS_ONE_ARG,
NULL, NULL, do_listcommands},
{(char *)"@list_file", NULL, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_list_file},
{(char *)"@listmotd", listmotd_sw, CA_PUBLIC,
MOTD_LIST, CS_ONE_ARG,
NULL, NULL, do_motd},
{(char *)"@lock", lock_sw, CA_NO_SLAVE,
0, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_lock},
{(char *)"@logrotate", NULL, CA_GOD,
0, CS_NO_ARGS,
NULL, NULL, do_logrotate},
#ifdef USE_MAIL
{(char *)"@mail", mail_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_mail},
{(char *)"@malias", malias_sw, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_malias},
#endif
{(char *)"@mark", mark_sw, CA_WIZARD,
SRCH_MARK, CS_ONE_ARG|CS_NOINTERP,
NULL, NULL, do_search},
{(char *)"@mark_all", markall_sw, CA_WIZARD,
MARK_SET, CS_NO_ARGS,
NULL, NULL, do_markall},
{(char *)"@motd", motd_sw, CA_WIZARD,
0, CS_ONE_ARG,
NULL, NULL, do_motd},
{(char *)"@mvattr", NULL,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_ARGV,
NULL, NULL, do_mvattr},
{(char *)"@name", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_name},
{(char *)"@newpassword", NULL, CA_WIZARD,
PASS_ANY, CS_TWO_ARG,
NULL, NULL, do_newpassword},
{(char *)"@notify", notify_sw,
CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG,
NULL, NULL, do_notify},
{(char *)"@oemit", NULL,
CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,
PEMIT_OEMIT, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"@open", open_sw,
CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP,
NULL, NULL, do_open},
{(char *)"@parent", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG|CS_FUNCTION,
NULL, NULL, do_parent},
{(char *)"@password", NULL, CA_NO_GUEST,
PASS_MINE, CS_TWO_ARG,
NULL, NULL, do_password},
{(char *)"@pcreate", NULL, CA_WIZARD|CA_GBL_BUILD,
PCRE_PLAYER, CS_TWO_ARG,
NULL, NULL, do_pcreate},
{(char *)"@pemit", pemit_sw, CA_NO_GUEST|CA_NO_SLAVE,
PEMIT_PEMIT, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"@npemit", pemit_sw, CA_NO_GUEST|CA_NO_SLAVE,
PEMIT_PEMIT, CS_TWO_ARG|CS_UNPARSE|CS_NOSQUISH,
NULL, NULL, do_pemit},
{(char *)"@poor", NULL, CA_GOD,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_poor},
{(char *)"@power", NULL, CA_PUBLIC,
0, CS_TWO_ARG,
NULL, NULL, do_power},
{(char *)"@program", NULL, CA_PUBLIC,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_prog},
{(char *)"@ps", ps_sw, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_ps},
{(char *)"@quota", quota_sw, CA_PUBLIC,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_quota},
{(char *)"@quitprogram", NULL, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_quitprog},
{(char *)"@readcache", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_readcache},
{(char *)"@restart", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_restart},
{(char *)"@robot", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER,
PCRE_ROBOT, CS_TWO_ARG,
NULL, NULL, do_pcreate},
{(char *)"@search", NULL, CA_PUBLIC,
SRCH_SEARCH, CS_ONE_ARG|CS_NOINTERP,
NULL, NULL, do_search},
{(char *)"@set", set_sw,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG,
NULL, NULL, do_set},
{(char *)"@shutdown", shutdown_sw, CA_WIZARD,
0, CS_ONE_ARG,
NULL, NULL, do_shutdown},
{(char *)"@sql", NULL, CA_SQL_OK,
0, CS_ONE_ARG,
NULL, NULL, do_sql},
{(char *)"@sqlconnect", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_sql_connect},
{(char *)"@sqldisconnect", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, sql_shutdown},
{(char *)"@stats", stats_sw, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_stats},
{(char *)"@startslave", NULL, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, boot_slave},
{(char *)"@sweep", sweep_sw, CA_PUBLIC,
0, CS_ONE_ARG,
NULL, NULL, do_sweep},
{(char *)"@switch", switch_sw, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,
NULL, NULL, do_switch},
{(char *)"@teleport", teleport_sw, CA_NO_GUEST,
TELEPORT_DEFAULT, CS_TWO_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_teleport},
{(char *)"@timecheck", timecheck_sw, CA_WIZARD,
0, CS_NO_ARGS,
NULL, NULL, do_timecheck},
{(char *)"@timewarp", warp_sw, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_timewarp},
{(char *)"@toad", toad_sw, CA_WIZARD,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_toad},
{(char *)"@trigger", trig_sw, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_ARGV,
NULL, NULL, do_trigger},
{(char *)"@unlink", NULL, CA_NO_SLAVE|CA_GBL_BUILD,
0, CS_ONE_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_unlink},
{(char *)"@unlock", lock_sw, CA_NO_SLAVE,
0, CS_ONE_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_unlock},
{(char *)"@verb", NULL, CA_GBL_INTERP|CA_NO_SLAVE,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP_AROUND,
NULL, NULL, do_verb},
{(char *)"@wait", NULL, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,
NULL, NULL, do_wait},
{(char *)"@wall", wall_sw, CA_PUBLIC,
SAY_SHOUT, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_say},
{(char *)"@wipe", NULL,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_ONE_ARG|CS_INTERP|CS_FUNCTION,
NULL, NULL, do_wipe},
#ifdef USE_COMSYS
{(char *)"addcom", NULL, CA_NO_SLAVE,
0, CS_TWO_ARG|CS_ARGV,
NULL, NULL, do_addcom},
{(char *)"allcom", NULL, CA_NO_SLAVE,
0, CS_ONE_ARG,
NULL, NULL, do_allcom},
{(char *)"comlist", NULL, CA_NO_SLAVE,
0, CS_NO_ARGS,
NULL, NULL, do_comlist},
{(char *)"comtitle", NULL, CA_NO_SLAVE,
0, CS_TWO_ARG,
NULL, NULL, do_comtitle},
{(char *)"clearcom", NULL, CA_NO_SLAVE,
0, CS_NO_ARGS,
NULL, NULL, do_clearcom},
{(char *)"delcom", NULL, CA_NO_SLAVE,
0, CS_ONE_ARG,
NULL, NULL, do_delcom},
#endif
{(char *)"drop", drop_sw,
CA_NO_SLAVE|CA_CONTENTS|CA_LOCATION|CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_drop},
{(char *)"enter", enter_sw, CA_LOCATION,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_enter},
{(char *)"examine", examine_sw, CA_PUBLIC,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_examine},
{(char *)"get", get_sw, CA_LOCATION|CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_get},
{(char *)"give", give_sw, CA_LOCATION|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_give},
{(char *)"goto", goto_sw, CA_LOCATION,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_move},
{(char *)"inventory", NULL, CA_PUBLIC,
LOOK_INVENTORY, CS_NO_ARGS,
NULL, NULL, do_inventory},
{(char *)"kill", NULL, CA_NO_GUEST|CA_NO_SLAVE,
KILL_KILL, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_kill},
{(char *)"leave", leave_sw, CA_LOCATION,
0, CS_NO_ARGS|CS_INTERP,
NULL, NULL, do_leave},
{(char *)"look", look_sw, CA_LOCATION,
LOOK_LOOK, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_look},
{(char *)"page", NULL, CA_NO_SLAVE,
0, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_page},
{(char *)"pose", pose_sw, CA_LOCATION|CA_NO_SLAVE,
SAY_POSE, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_say},
{(char *)"say", NULL, CA_LOCATION|CA_NO_SLAVE,
SAY_SAY, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_say},
{(char *)"score", NULL, CA_PUBLIC,
LOOK_SCORE, CS_NO_ARGS,
NULL, NULL, do_score},
{(char *)"slay", NULL, CA_WIZARD,
KILL_SLAY, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_kill},
{(char *)"think", NULL, CA_NO_SLAVE,
0, CS_ONE_ARG,
NULL, NULL, do_think},
{(char *)"use", NULL, CA_NO_SLAVE|CA_GBL_INTERP,
0, CS_ONE_ARG|CS_INTERP,
NULL, NULL, do_use},
{(char *)"version", NULL, CA_PUBLIC,
0, CS_NO_ARGS,
NULL, NULL, do_version},
{(char *)"whisper", NULL, CA_LOCATION|CA_NO_SLAVE,
PEMIT_WHISPER, CS_TWO_ARG|CS_INTERP,
NULL, NULL, do_pemit},
{(char *)"doing", NULL, CA_PUBLIC,
CMD_DOING, CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"quit", NULL, CA_PUBLIC,
CMD_QUIT, CS_NO_ARGS,
NULL, NULL, logged_out},
{(char *)"logout", NULL, CA_PUBLIC,
CMD_LOGOUT, CS_NO_ARGS,
NULL, NULL, logged_out},
{(char *)"who", NULL, CA_PUBLIC,
CMD_WHO, CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"session", NULL, CA_PUBLIC,
CMD_SESSION, CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"info", NULL, CA_PUBLIC,
CMD_INFO, CS_NO_ARGS,
NULL, NULL, logged_out},
{(char *)"outputprefix", NULL, CA_PUBLIC,
CMD_PREFIX, CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"outputsuffix", NULL, CA_PUBLIC,
CMD_SUFFIX, CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"puebloclient", NULL, CA_PUBLIC,
CMD_PUEBLOCLIENT,CS_ONE_ARG,
NULL, NULL, logged_out},
{(char *)"\\", NULL,
CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_SLAVE,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, do_say},
{(char *)"#", NULL,
CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK,
0, CS_ONE_ARG|CS_INTERP|CS_CMDARG|CS_LEADIN,
NULL, NULL, do_force_prefixed},
{(char *)":", NULL,
CA_LOCATION|CF_DARK|CA_NO_SLAVE,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, do_say},
{(char *)";", NULL,
CA_LOCATION|CF_DARK|CA_NO_SLAVE,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, do_say},
{(char *)"\"", NULL,
CA_LOCATION|CF_DARK|CA_NO_SLAVE,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN,
NULL, NULL, do_say},
{(char *)"&", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_TWO_ARG|CS_LEADIN,
NULL, NULL, do_setvattr},
#ifdef USE_MAIL
{(char *)"-", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_ONE_ARG|CS_LEADIN,
NULL, NULL, do_postpend},
{(char *)"~", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_ONE_ARG|CS_LEADIN,
NULL, NULL, do_prepend},
#endif
{(char *)NULL, NULL, 0,
0, 0,
NULL, NULL, NULL}};
/* *INDENT-ON* */
CMDENT *prefix_cmds[256];
CMDENT *goto_cmdp, *enter_cmdp, *leave_cmdp;
void NDECL(init_cmdtab)
{
CMDENT *cp;
ATTR *ap;
char *p, *q;
char *cbuff;
hashinit(&mudstate.command_htab, 250 * HASH_FACTOR);
/* Load attribute-setting commands */
cbuff = alloc_sbuf("init_cmdtab");
for (ap = attr; ap->name; ap++) {
if ((ap->flags & AF_NOCMD) == 0) {
p = cbuff;
*p++ = '@';
for (q = (char *)ap->name; *q; p++, q++)
*p = ToLower(*q);
*p = '\0';
cp = (CMDENT *) XMALLOC(sizeof(CMDENT), "init_cmdtab");
cp->cmdname = (char *)strsave(cbuff);
cp->perms = CA_NO_GUEST | CA_NO_SLAVE;
cp->switches = NULL;
if (ap->flags & (AF_WIZARD | AF_MDARK)) {
cp->perms |= CA_WIZARD;
}
cp->extra = ap->number;
cp->callseq = CS_TWO_ARG;
cp->pre_hook = NULL;
cp->post_hook = NULL;
cp->info.handler = do_setattr;
if (hashadd(cp->cmdname, (int *)cp, &mudstate.command_htab)) {
XFREE(cp->cmdname, "init_cmdtab.2");
XFREE(cp, "init_cmdtab.3");
}
}
}
free_sbuf(cbuff);
/* Load the builtin commands */
for (cp = command_table; cp->cmdname; cp++)
hashadd(cp->cmdname, (int *)cp, &mudstate.command_htab);
set_prefix_cmds();
goto_cmdp = (CMDENT *) hashfind("goto", &mudstate.command_htab);
enter_cmdp = (CMDENT *) hashfind("enter", &mudstate.command_htab);
leave_cmdp = (CMDENT *) hashfind("leave", &mudstate.command_htab);
}
void set_prefix_cmds()
{
int i;
/* Load the command prefix table. Note - these commands can never
* be typed in by a user because commands are lowercased
* before the hash table is checked. The names are
* abbreviated to minimise name checking time.
*/
for (i = 0; i < 256; i++)
prefix_cmds[i] = NULL;
prefix_cmds['"'] = (CMDENT *) hashfind((char *)"\"",
&mudstate.command_htab);
prefix_cmds[':'] = (CMDENT *) hashfind((char *)":",
&mudstate.command_htab);
prefix_cmds[';'] = (CMDENT *) hashfind((char *)";",
&mudstate.command_htab);
prefix_cmds['\\'] = (CMDENT *) hashfind((char *)"\\",
&mudstate.command_htab);
prefix_cmds['#'] = (CMDENT *) hashfind((char *)"#",
&mudstate.command_htab);
prefix_cmds['&'] = (CMDENT *) hashfind((char *)"&",
&mudstate.command_htab);
#ifdef USE_MAIL
/* Note that doing it this way means that you'll later run into
* problems if you enable the mailer without a @restart. However,
* not doing it this way breaks all the softcoded mailers.
*/
if (mudconf.have_mailer) {
prefix_cmds['-'] = (CMDENT *) hashfind((char *)"-",
&mudstate.command_htab);
prefix_cmds['~'] = (CMDENT *) hashfind((char *)"~",
&mudstate.command_htab);
}
#endif
}
/* ---------------------------------------------------------------------------
* check_access: Check if player has access to function.
* Note that the calling function may also give permission
* denied messages on failure.
*/
int check_access(player, mask)
dbref player;
int mask;
{
int succ, fail;
/* Check if we have permission to execute */
if (mask & CA_DISABLED)
return 0;
if (mask & CA_STATIC)
return 0;
if (God(player) || mudstate.initializing)
return 1;
succ = fail = 0;
if (mask & CA_GOD)
fail++;
if (mask & CA_WIZARD) {
if (Wizard(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_ADMIN)) {
if (WizRoy(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_BUILDER)) {
if (Builder(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_STAFF)) {
if (Staff(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_HEAD)) {
if (Head(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_IMMORTAL)) {
if (Immortal(player))
succ++;
else
fail++;
}
if (mask & CA_SQL_OK) {
if (Can_Use_SQL(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER0)) {
if (H_Marker0(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER1)) {
if (H_Marker1(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER2)) {
if (H_Marker2(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER3)) {
if (H_Marker3(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER4)) {
if (H_Marker4(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER5)) {
if (H_Marker5(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER6)) {
if (H_Marker6(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER7)) {
if (H_Marker7(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER8)) {
if (H_Marker8(player))
succ++;
else
fail++;
}
if ((succ == 0) && (mask & CA_MARKER9)) {
if (H_Marker9(player))
succ++;
else
fail++;
}
if (succ > 0)
fail = 0;
if (fail > 0)
return 0;
/* Check for forbidden flags. */
if (!Wizard(player) &&
(((mask & CA_NO_HAVEN) && Player_haven(player)) ||
((mask & CA_NO_ROBOT) && Robot(player)) ||
((mask & CA_NO_SLAVE) && Slave(player)) ||
((mask & CA_NO_SUSPECT) && Suspect(player)) ||
((mask & CA_NO_GUEST) && Guest(player)))) {
return 0;
}
return 1;
}
/* ---------------------------------------------------------------------------
* process_hook: Evaluate a hook function.
*/
static void process_hook(hp, save_globs, player, cause, cargs, ncargs)
HOOKENT *hp;
int save_globs;
dbref player, cause;
char *cargs[];
int ncargs;
{
char *buf, *bp;
char *tstr, *str;
dbref aowner;
int aflags, alen, preserve_len[MAX_GLOBAL_REGS];
char *preserve[MAX_GLOBAL_REGS];
/* We know we have a non-null hook. We want to evaluate the obj/attr
* pair of that hook. We consider the enactor to be the player who
* executed the command that caused this hook to be called.
*/
tstr = atr_get(hp->thing, hp->atr, &aowner, &aflags, &alen);
str = tstr;
if (save_globs) {
save_global_regs("process_hook", preserve, preserve_len);
}
buf = bp = alloc_lbuf("process_hook");
exec(buf, &bp, 0, hp->thing, player, EV_EVAL | EV_FIGNORE | EV_TOP,
&str, cargs, ncargs);
*bp = '\0';
free_lbuf(buf);
if (save_globs) {
restore_global_regs("process_hook", preserve, preserve_len);
}
free_lbuf(tstr);
}
/* ---------------------------------------------------------------------------
* process_cmdent: Perform indicated command with passed args.
*/
void process_cmdent(cmdp, switchp, player, cause, interactive, arg,
unp_command, cargs, ncargs)
CMDENT *cmdp;
char *switchp, *arg, *unp_command, *cargs[];
dbref player, cause;
int interactive, ncargs;
{
char *buf1, *buf2, tchar, *bp, *str, *buff, *s, *j, *new;
char *args[MAX_ARG];
int nargs, i, interp, key, xkey, aflags, alen;
int hasswitch = 0;
int cmd_matches = 0;
dbref aowner;
char *aargs[10];
ADDENT *add;
/* Perform object type checks. */
if (Invalid_Objtype(player)) {
notify(player, "Command incompatible with invoker type.");
return;
}
/* Check if we have permission to execute the command */
if (!check_access(player, cmdp->perms)) {
notify(player, NOPERM_MESSAGE);
return;
}
/* Check global flags */
if ((!Builder(player)) && Protect(CA_GBL_BUILD) &&
!(mudconf.control_flags & CF_BUILD)) {
notify(player, "Sorry, building is not allowed now.");
return;
}
if (Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP)) {
notify(player,
"Sorry, queueing and triggering are not allowed now.");
return;
}
key = cmdp->extra & ~SW_MULTIPLE;
if (key & SW_GOT_UNIQUE) {
i = 1;
key = key & ~SW_GOT_UNIQUE;
} else {
i = 0;
}
/* Check command switches. Note that there may be more than one,
* and that we OR all of them together along with the extra value
* from the command table to produce the key value in the handler call.
*/
if (switchp && cmdp->switches) {
do {
buf1 = (char *)index(switchp, '/');
if (buf1)
*buf1++ = '\0';
xkey = search_nametab(player, cmdp->switches,
switchp);
if (xkey == -1) {
notify(player,
tprintf("Unrecognized switch '%s' for command '%s'.",
switchp, cmdp->cmdname));
return;
} else if (xkey == -2) {
notify(player, NOPERM_MESSAGE);
return;
} else if (!(xkey & SW_MULTIPLE)) {
if (i == 1) {
notify(player,
"Illegal combination of switches.");
return;
}
i = 1;
} else {
xkey &= ~SW_MULTIPLE;
}
key |= xkey;
switchp = buf1;
hasswitch = 1;
} while (buf1);
} else if (switchp && !(cmdp->callseq & CS_ADDED)) {
notify(player,
tprintf("Command %s does not take switches.",
cmdp->cmdname));
return;
}
/* At this point we're guaranteed we're going to execute something.
* Let's check to see if we have a pre-command hook.
*/
CALL_PRE_HOOK(cmdp, cargs, ncargs);
/* If the command normally has interpreted args, but the user
* specified, /noeval, just do EV_STRIP.
*
* If the command is interpreted, or we're interactive (and
* the command isn't specified CS_NOINTERP), eval the args.
*
* The others are obvious.
*/
if ((cmdp->callseq & CS_INTERP) && (key & SW_NOEVAL)) {
interp = EV_STRIP;
key &= ~SW_NOEVAL; /* Remove SW_NOEVAL from 'key' */
}
else if ((cmdp->callseq & CS_INTERP) ||
!(interactive || (cmdp->callseq & CS_NOINTERP)))
interp = EV_EVAL | EV_STRIP;
else if (cmdp->callseq & CS_STRIP)
interp = EV_STRIP;
else if (cmdp->callseq & CS_STRIP_AROUND)
interp = EV_STRIP_AROUND;
else
interp = 0;
switch (cmdp->callseq & CS_NARG_MASK) {
case CS_NO_ARGS: /* <cmd> (no args) */
(*(cmdp->info.handler)) (player, cause, key);
break;
case CS_ONE_ARG: /* <cmd> <arg> */
/* If an unparsed command, just give it to the handler */
if (cmdp->callseq & CS_UNPARSE) {
(*(cmdp->info.handler)) (player, unp_command);
break;
}
/* Interpret if necessary, but not twice for CS_ADDED */
if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED)) {
buf1 = bp = alloc_lbuf("process_cmdent");
str = arg;
exec(buf1, &bp, 0, player, cause, interp | EV_FCHECK | EV_TOP,
&str, cargs, ncargs);
*bp = '\0';
} else
buf1 = parse_to(&arg, '\0', interp | EV_TOP);
/* Call the correct handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->info.handler)) (player, cause, key, buf1,
cargs, ncargs);
} else {
if (cmdp->callseq & CS_ADDED) {
/* Construct the matching buffer. */
/* In the case of a single-letter prefix, we want
* to just skip past that first letter. Otherwise
* we want to go past the first word.
*/
if (!(cmdp->callseq & CS_LEADIN)) {
for (j = unp_command; *j && (*j != ' '); j++) ;
} else {
j = unp_command; j++;
}
new = alloc_lbuf("process_cmdent.soft");
bp = new;
if (!*j) {
/* No args */
if (!(cmdp->callseq & CS_LEADIN)) {
safe_str(cmdp->cmdname, new, &bp);
} else {
safe_str(unp_command, new, &bp);
}
if (switchp) {
safe_chr('/', new, &bp);
safe_str(switchp, new, &bp);
}
*bp = '\0';
} else {
if (!(cmdp->callseq & CS_LEADIN))
j++;
safe_str(cmdp->cmdname, new, &bp);
if (switchp) {
safe_chr('/', new, &bp);
safe_str(switchp, new, &bp);
}
if (!(cmdp->callseq & CS_LEADIN))
safe_chr(' ', new, &bp);
safe_str(j, new, &bp);
*bp = '\0';
}
/* Now search against the attributes. */
for (add = (ADDENT *)cmdp->info.added;
add != NULL; add = add->next) {
buff = atr_get(add->thing,
add->atr, &aowner, &aflags, &alen);
/* Skip the '$' character, and the next */
for (s = buff + 2; *s && (*s != ':'); s++) ;
if (!*s) {
free_lbuf(buff);
break;
}
*s++ = '\0';
if (wild(buff + 1, new, aargs, 10)) {
if (!mudconf.addcmd_obey_uselocks ||
could_doit(player, add->thing, A_LUSE)) {
wait_que(add->thing, player,
0, NOTHING, 0, s, aargs, 10,
mudstate.global_regs);
for (i = 0; i < 10; i++) {
if (aargs[i])
free_lbuf(aargs[i]);
}
cmd_matches++;
}
}
free_lbuf(buff);
if (cmd_matches && mudconf.addcmd_obey_stop &&
Stop_Match(add->thing)) {
break;
}
}
if (!cmd_matches && !mudconf.addcmd_match_blindly) {
/* The command the player typed didn't match
* any of the wildcard patterns we have for
* that addcommand. We should raise an error.
* We DO NOT go back into trying to match
* other stuff -- this is a 'Huh?' situation.
*/
notify(player, "Huh? (Type \"help\" for help.)");
STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD")
log_name_and_loc(player);
log_text((char *) " entered: ");
log_text(new);
ENDLOG
}
free_lbuf(new);
} else
(*(cmdp->info.handler)) (player, cause, key, buf1);
}
/* Free the buffer if one was allocated */
if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED))
free_lbuf(buf1);
break;
case CS_TWO_ARG: /* <cmd> <arg1> = <arg2> */
/* Interpret ARG1 */
buf2 = parse_to(&arg, '=', EV_STRIP_TS);
/* Handle when no '=' was specified */
if (!arg || (arg && !*arg)) {
arg = &tchar;
*arg = '\0';
}
buf1 = bp = alloc_lbuf("process_cmdent.2");
str = buf2;
exec(buf1, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL | EV_TOP,
&str, cargs, ncargs);
*bp = '\0';
if (cmdp->callseq & CS_ARGV) {
/* Arg2 is ARGV style. Go get the args */
parse_arglist(player, cause, arg, '\0',
interp | EV_STRIP_LS | EV_STRIP_TS,
args, MAX_ARG, cargs, ncargs);
for (nargs = 0; (nargs < MAX_ARG) && args[nargs]; nargs++) ;
/* Call the correct command handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->info.handler)) (player, cause, key,
buf1, args, nargs, cargs, ncargs);
} else {
(*(cmdp->info.handler)) (player, cause, key,
buf1, args, nargs);
}
/* Free the argument buffers */
for (i = 0; i <= nargs; i++)
if (args[i])
free_lbuf(args[i]);
} else {
/* Arg2 is normal style. Interpret if needed */
if (interp & EV_EVAL) {
buf2 = bp = alloc_lbuf("process_cmdent.3");
str = arg;
exec(buf2, &bp, 0, player, cause,
interp | EV_FCHECK | EV_TOP,
&str, cargs, ncargs);
*bp = '\0';
} else if (cmdp->callseq & CS_UNPARSE) {
buf2 = parse_to(&arg, '\0',
interp | EV_TOP | EV_NO_COMPRESS);
} else {
buf2 = parse_to(&arg, '\0',
interp | EV_STRIP_LS | EV_STRIP_TS | EV_TOP);
}
/* Call the correct command handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->info.handler)) (player, cause, key,
buf1, buf2, cargs, ncargs);
} else {
(*(cmdp->info.handler)) (player, cause, key,
buf1, buf2);
}
/* Free the buffer, if needed */
if (interp & EV_EVAL)
free_lbuf(buf2);
}
/* Free the buffer obtained by evaluating Arg1 */
free_lbuf(buf1);
break;
}
/* And now we go do the posthook, if we have one. */
CALL_POST_HOOK(cmdp, cargs, ncargs);
return;
}
/* ---------------------------------------------------------------------------
* process_command: Execute a command.
*/
char *process_command(player, cause, interactive, command, args, nargs)
dbref player, cause;
int interactive, nargs;
char *command, *args[];
{
static char preserve_cmd[LBUF_SIZE];
char *p, *q, *arg, *lcbuf, *slashp, *cmdsave, *bp, *str, *evcmd;
char *gbuf, *gc;
int succ, aflags, alen, i, got_stop, pcount;
dbref exit, aowner, parent;
CMDENT *cmdp;
#ifndef MEMORY_BASED
cache_reset(0);
#endif /* MEMORY_BASED */
/* Robustify player */
cmdsave = mudstate.debug_cmd;
mudstate.debug_cmd = (char *)"< process_command >";
if (!command) {
fprintf(stderr, "ABORT! command.c, null command in process_command().\n");
abort();
}
if (!Good_obj(player)) {
STARTLOG(LOG_BUGS, "CMD", "PLYR")
lcbuf = alloc_mbuf("process_command.LOG.badplayer");
sprintf(lcbuf, "Bad player in process_command: %d",
player);
log_text(lcbuf);
free_mbuf(lcbuf);
ENDLOG
mudstate.debug_cmd = cmdsave;
return command;
}
/* Make sure player isn't going or halted */
if (Going(player) ||
(Halted(player) &&
!((Typeof(player) == TYPE_PLAYER) && interactive))) {
notify(Owner(player),
tprintf("Attempt to execute command by halted object #%d",
player));
mudstate.debug_cmd = cmdsave;
return command;
}
if (Suspect(player)) {
STARTLOG(LOG_SUSPECTCMDS, "CMD", "SUSP")
log_name_and_loc(player);
log_text(" entered: ");
log_text(command);
ENDLOG
} else {
STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL")
log_name_and_loc(player);
log_text(" entered: ");
log_text(command);
ENDLOG
}
/* Reset recursion limits */
mudstate.func_nest_lev = 0;
mudstate.func_invk_ctr = 0;
mudstate.ntfy_nest_lev = 0;
mudstate.lock_nest_lev = 0;
if (Verbose(player))
notify(Owner(player), tprintf("%s] %s", Name(player),
command));
/*
* NOTE THAT THIS WILL BREAK IF "GOD" IS NOT A DBREF.
*/
if (mudconf.control_flags & CF_GODMONITOR) {
raw_notify(GOD, tprintf("%s(#%d)%c %s", Name(player), player,
(interactive) ? '|' : ':', command));
}
/* Eat leading whitespace, and space-compress if configured */
while (*command && isspace(*command))
command++;
strcpy(preserve_cmd, command);
mudstate.debug_cmd = command;
mudstate.curr_cmd = preserve_cmd;
if (mudconf.space_compress) {
p = q = command;
while (*p) {
while (*p && !isspace(*p))
*q++ = *p++;
while (*p && isspace(*p))
p++;
if (*p)
*q++ = ' ';
}
*q = '\0';
}
#ifndef MEMORY_BASED
/* Reset the cache so that unreferenced attributes may be flushed */
cache_reset(0);
#endif /* MEMORY_BASED */
/* Now comes the fun stuff. First check for single-letter leadins.
* We check these before checking HOME because
* they are among the most frequently executed commands,
* and they can never be the HOME command.
*/
i = command[0] & 0xff;
if ((prefix_cmds[i] != NULL) && command[0]) {
process_cmdent(prefix_cmds[i], NULL, player, cause,
interactive, command, command, args, nargs);
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
#ifdef USE_COMSYS
if (mudconf.have_comsys && !Slave(player) &&
!do_comsys(player, command))
return preserve_cmd;
#endif
/* Check for the HOME command. You cannot do hooks on this because
* home is not part of the traditional command table.
*/
if (string_compare(command, "home") == 0) {
if (((Fixed(player)) || (Fixed(Owner(player)))) &&
!(WizRoy(player))) {
notify(player, mudconf.fixed_home_msg);
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
do_move(player, cause, 0, "home");
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
/* Only check for exits if we may use the goto command */
if (check_access(player, goto_cmdp->perms)) {
/* Check for an exit name */
init_match_check_keys(player, command, TYPE_EXIT);
match_exit_with_parents();
exit = last_match_result();
if (exit != NOTHING) {
if (mudconf.exit_calls_move) {
/* Exits literally call the 'move' command. Note
* that, later, when we go to matching master-room
* and other global-ish exits, that we also need
* to have move_match_more set to 'yes', or
* we'll match here only to encounter dead silence
* when we try to find the exit inside the move
* routine. We also need to directly find what
* the pointer for the move (goto) command is,
* since we could have @addcommand'd it (and
* probably did, if this conf option is on).
* Finally, we've got to make this look like
* we really did type 'goto <exit>', or the
* @addcommand will just skip over the string.
*/
cmdp = (CMDENT *) hashfind("goto",
&mudstate.command_htab);
if (cmdp) { /* just in case */
gbuf = alloc_lbuf("process_command.goto");
gc = gbuf;
safe_str(cmdp->cmdname, gbuf, &gc);
safe_chr(' ', gbuf, &gc);
safe_str(command, gbuf, &gc);
*gc = '\0';
process_cmdent(cmdp, NULL, player, cause,
interactive, command, gbuf,
args, nargs);
free_lbuf(gbuf);
}
} else {
/* Execute the pre-hook for the goto command */
CALL_PRE_HOOK(goto_cmdp, args, nargs);
move_exit(player, exit, 0, NOGO_MESSAGE, 0);
/* Execute the post-hook for the goto command */
CALL_POST_HOOK(goto_cmdp, args, nargs);
}
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
/* Check for an exit in the master room */
init_match_check_keys(player, command, TYPE_EXIT);
match_master_exit();
exit = last_match_result();
if (exit != NOTHING) {
if (mudconf.exit_calls_move) {
cmdp = (CMDENT *) hashfind("goto",
&mudstate.command_htab);
if (cmdp) {
gbuf = alloc_lbuf("process_command.goto");
gc = gbuf;
safe_str(cmdp->cmdname, gbuf, &gc);
safe_chr(' ', gbuf, &gc);
safe_str(command, gbuf, &gc);
*gc = '\0';
process_cmdent(cmdp, NULL, player, cause,
interactive, command, gbuf,
args, nargs);
free_lbuf(gbuf);
}
} else {
CALL_PRE_HOOK(goto_cmdp, args, nargs);
move_exit(player, exit, 1, NOGO_MESSAGE, 0);
CALL_POST_HOOK(goto_cmdp, args, nargs);
}
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
}
/* Set up a lowercase command and an arg pointer for the hashed
* command check. Since some types of argument
* processing destroy the arguments, make a copy so that
* we keep the original command line intact. Store the
* edible copy in lcbuf after the lowercased command.
*/
/* Removed copy of the rest of the command, since it's ok to allow
* it to be trashed. -dcm
*/
lcbuf = alloc_lbuf("process_commands.LCbuf");
for (p = command, q = lcbuf; *p && !isspace(*p); p++, q++)
*q = ToLower(*p); /* Make lowercase command */
*q++ = '\0'; /* Terminate command */
while (*p && isspace(*p))
p++; /* Skip spaces before arg */
arg = p; /* Remember where arg starts */
/* Strip off any command switches and save them */
slashp = (char *)index(lcbuf, '/');
if (slashp)
*slashp++ = '\0';
/* Check for a builtin command (or an alias of a builtin command) */
cmdp = (CMDENT *) hashfind(lcbuf, &mudstate.command_htab);
if (cmdp != NULL) {
if (mudconf.space_compress && (cmdp->callseq & CS_NOSQUISH)) {
/* We handle this specially -- there is no space compression
* involved, so we must go back to the preserved command.
*/
strcpy(command, preserve_cmd);
arg = command;
while (*arg && !isspace(*arg))
arg++;
if (*arg) /* we stopped on the space, advance to next */
arg++;
}
process_cmdent(cmdp, slashp, player, cause, interactive, arg,
command, args, nargs);
free_lbuf(lcbuf);
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
/* Check for enter and leave aliases, user-defined commands on the
* player, other objects where the player is, on objects in
* the player's inventory, and on the room that holds
* the player. We evaluate the command line here to allow
* chains of $-commands to work.
*/
str = evcmd = alloc_lbuf("process_command.evcmd");
StringCopy(evcmd, command);
bp = lcbuf;
exec(lcbuf, &bp, 0, player, cause,
EV_EVAL | EV_FCHECK | EV_STRIP | EV_TOP, &str, args, nargs);
*bp = '\0';
free_lbuf(evcmd);
succ = 0;
/* Idea for enter/leave aliases from R'nice@TinyTIM */
if (Has_location(player) && Good_obj(Location(player))) {
/* Check for a leave alias, if we have permissions to
* use the 'leave' command.
*/
if (check_access(player, leave_cmdp->perms)) {
p = atr_pget(Location(player), A_LALIAS, &aowner, &aflags, &alen);
if (*p) {
if (matches_exit_from_list(lcbuf, p)) {
free_lbuf(lcbuf);
free_lbuf(p);
CALL_PRE_HOOK(leave_cmdp, args, nargs);
do_leave(player, player, 0);
CALL_POST_HOOK(leave_cmdp, args, nargs);
return preserve_cmd;
}
}
free_lbuf(p);
}
/* Check for enter aliases, if we have permissions to use the
* 'enter' command.
*/
if (check_access(player, enter_cmdp->perms)) {
DOLIST(exit, Contents(Location(player))) {
p = atr_pget(exit, A_EALIAS, &aowner, &aflags, &alen);
if (*p) {
if (matches_exit_from_list(lcbuf, p)) {
free_lbuf(lcbuf);
free_lbuf(p);
CALL_PRE_HOOK(enter_cmdp, args, nargs);
do_enter_internal(player, exit, 0);
CALL_POST_HOOK(enter_cmdp, args, nargs);
return preserve_cmd;
}
}
free_lbuf(p);
}
}
}
/* At each of the following stages, we check to make sure that we
* haven't hit a match on a STOP-set object.
*/
got_stop = 0;
/* Check for $-command matches on me */
if (mudconf.match_mine) {
if (((Typeof(player) != TYPE_PLAYER) ||
mudconf.match_mine_pl) &&
(atr_match(player, player, AMATCH_CMD, lcbuf, preserve_cmd, 1) > 0)) {
succ++;
got_stop = Stop_Match(player);
}
}
/* Check for $-command matches on nearby things and on my room */
if (!got_stop && Has_location(player)) {
succ += list_check(Contents(Location(player)), player,
AMATCH_CMD, lcbuf, preserve_cmd, 1, &got_stop);
if (!got_stop &&
atr_match(Location(player), player, AMATCH_CMD, lcbuf,
preserve_cmd, 1) > 0) {
succ++;
got_stop = Stop_Match(Location(player));
}
}
/* Check for $-command matches in my inventory */
if (!got_stop && Has_contents(player))
succ += list_check(Contents(player), player,
AMATCH_CMD, lcbuf, preserve_cmd, 1, &got_stop);
/* If we didn't find anything, and we're checking local masters,
* do those checks. Do it for the zone of the player's location first,
* and then, if nothing is found, on the player's personal zone.
* Walking back through the parent tree stops when a match is found.
* Also note that these matches are done in the style of the master room:
* parents of the contents of the rooms aren't checked for commands.
* We try to maintain 2.2/MUX compatibility here, putting both sets
* of checks together.
*/
/* 2.2 style location */
if (!succ && mudconf.local_masters) {
if (Has_location(player)) {
pcount = 0;
parent = Parent(Location(player));
while (!succ && !got_stop &&
Good_obj(parent) && ParentZone(parent) &&
(pcount < mudconf.parent_nest_lim)) {
if (Has_contents(parent)) {
succ += list_check(Contents(parent), player,
AMATCH_CMD, lcbuf, preserve_cmd,
0, &got_stop);
}
parent = Parent(parent);
pcount++;
}
}
}
/* MUX style location */
if ((!succ) && mudconf.have_zones &&
(Zone(Location(player)) != NOTHING)) {
if (Typeof(Zone(Location(player))) == TYPE_ROOM) {
/* zone of player's location is a parent room */
if (Location(player) != Zone(player)) {
/* check parent room exits */
init_match_check_keys(player, command, TYPE_EXIT);
match_zone_exit();
exit = last_match_result();
if (exit != NOTHING) {
if (mudconf.exit_calls_move) {
cmdp = (CMDENT *) hashfind("goto",
&mudstate.command_htab);
if (cmdp) {
gbuf = alloc_lbuf("process_command.goto");
gc = gbuf;
safe_str(cmdp->cmdname, gbuf, &gc);
safe_chr(' ', gbuf, &gc);
safe_str(command, gbuf, &gc);
*gc = '\0';
process_cmdent(cmdp, NULL, player, cause,
interactive, command, gbuf,
args, nargs);
free_lbuf(gbuf);
}
} else {
CALL_PRE_HOOK(goto_cmdp, args, nargs);
move_exit(player, exit, 1, NOGO_MESSAGE, 0);
CALL_POST_HOOK(goto_cmdp, args, nargs);
}
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
if (!got_stop) {
succ += list_check(Contents(Zone(Location(player))),
player, AMATCH_CMD, lcbuf,
preserve_cmd, 1, &got_stop);
}
} /* end of parent room checks */
} else
/* try matching commands on area zone object */
if (!got_stop && !succ && mudconf.have_zones
&& (Zone(Location(player)) != NOTHING)) {
succ += atr_match(Zone(Location(player)), player,
AMATCH_CMD, lcbuf, preserve_cmd, 1);
}
} /* end of matching on zone of player's location */
/* 2.2 style player */
if (!succ && mudconf.local_masters) {
parent = Parent(player);
if ((parent != Location(player)) &&
(!Good_obj(Location(player)) ||
(parent != Parent(Location(player))))) {
pcount = 0;
while (!succ && !got_stop &&
Good_obj(parent) && ParentZone(parent) &&
(pcount < mudconf.parent_nest_lim)) {
if (Has_contents(parent)) {
succ += list_check(Contents(parent), player,
AMATCH_CMD, lcbuf, preserve_cmd, 0,
&got_stop);
}
parent = Parent(parent);
pcount++;
}
}
}
/* MUX style player */
/* if nothing matched with parent room/zone object, try matching
* zone commands on the player's personal zone
*/
if (!got_stop && !succ && mudconf.have_zones &&
(Zone(player) != NOTHING) &&
(Zone(Location(player)) != Zone(player))) {
succ += atr_match(Zone(player), player, AMATCH_CMD, lcbuf,
preserve_cmd, 1);
}
/* If we didn't find anything, try in the master room */
if (!got_stop && !succ) {
if (Good_obj(mudconf.master_room) &&
Has_contents(mudconf.master_room)) {
succ += list_check(Contents(mudconf.master_room),
player, AMATCH_CMD, lcbuf,
preserve_cmd, 0, &got_stop);
if (!got_stop && atr_match(mudconf.master_room,
player, AMATCH_CMD, lcbuf, preserve_cmd, 0) > 0) {
succ++;
}
}
}
free_lbuf(lcbuf);
/* If we still didn't find anything, tell how to get help. */
if (!succ) {
notify(player, "Huh? (Type \"help\" for help.)");
STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD")
log_name_and_loc(player);
log_text((char *) " entered: ");
log_text(command);
ENDLOG
}
mudstate.debug_cmd = cmdsave;
return preserve_cmd;
}
/* ---------------------------------------------------------------------------
* list_cmdtable: List internal commands.
*/
static void list_cmdtable(player)
dbref player;
{
CMDENT *cmdp;
char *buf, *bp, *cp;
buf = alloc_lbuf("list_cmdtable");
bp = buf;
for (cp = (char *)"Commands:"; *cp; cp++)
*bp++ = *cp;
for (cmdp = command_table; cmdp->cmdname; cmdp++) {
if (check_access(player, cmdp->perms)) {
if (!(cmdp->perms & CF_DARK)) {
*bp++ = ' ';
for (cp = cmdp->cmdname; *cp; cp++)
*bp++ = *cp;
}
}
}
*bp = '\0';
/* Players get the list of logged-out cmds too */
if (Typeof(player) == TYPE_PLAYER)
display_nametab(player, logout_cmdtable, buf, 1);
else
notify(player, buf);
free_lbuf(buf);
}
/* ---------------------------------------------------------------------------
* list_attrtable: List available attributes.
*/
static void list_attrtable(player)
dbref player;
{
ATTR *ap;
char *buf, *bp, *cp;
buf = alloc_lbuf("list_attrtable");
bp = buf;
for (cp = (char *)"Attributes:"; *cp; cp++)
*bp++ = *cp;
for (ap = attr; ap->name; ap++) {
if (See_attr(player, player, ap, player, 0)) {
*bp++ = ' ';
for (cp = (char *)(ap->name); *cp; cp++)
*bp++ = *cp;
}
}
*bp = '\0';
raw_notify(player, buf);
free_lbuf(buf);
}
/* ---------------------------------------------------------------------------
* list_cmdaccess: List access commands.
*/
NAMETAB access_nametab[] =
{
{(char *)"admin", 2, CA_WIZARD, CA_ADMIN},
{(char *)"builder", 6, CA_WIZARD, CA_BUILDER},
{(char *)"dark", 4, CA_GOD, CF_DARK},
{(char *)"disabled", 4, CA_GOD, CA_DISABLED},
{(char *)"global_build", 8, CA_PUBLIC, CA_GBL_BUILD},
{(char *)"global_interp", 8, CA_PUBLIC, CA_GBL_INTERP},
{(char *)"god", 2, CA_GOD, CA_GOD},
{(char *)"head", 2, CA_WIZARD, CA_HEAD},
{(char *)"immortal", 3, CA_WIZARD, CA_IMMORTAL},
{(char *)"marker0", 7, CA_WIZARD, CA_MARKER0},
{(char *)"marker1", 7, CA_WIZARD, CA_MARKER1},
{(char *)"marker2", 7, CA_WIZARD, CA_MARKER2},
{(char *)"marker3", 7, CA_WIZARD, CA_MARKER3},
{(char *)"marker4", 7, CA_WIZARD, CA_MARKER4},
{(char *)"marker5", 7, CA_WIZARD, CA_MARKER5},
{(char *)"marker6", 7, CA_WIZARD, CA_MARKER6},
{(char *)"marker7", 7, CA_WIZARD, CA_MARKER7},
{(char *)"marker8", 7, CA_WIZARD, CA_MARKER8},
{(char *)"marker9", 7, CA_WIZARD, CA_MARKER9},
{(char *)"need_location", 6, CA_PUBLIC, CA_LOCATION},
{(char *)"need_contents", 6, CA_PUBLIC, CA_CONTENTS},
{(char *)"need_player", 6, CA_PUBLIC, CA_PLAYER},
{(char *)"no_haven", 4, CA_PUBLIC, CA_NO_HAVEN},
{(char *)"no_robot", 4, CA_WIZARD, CA_NO_ROBOT},
{(char *)"no_slave", 5, CA_PUBLIC, CA_NO_SLAVE},
{(char *)"no_suspect", 5, CA_WIZARD, CA_NO_SUSPECT},
{(char *)"no_guest", 5, CA_WIZARD, CA_NO_GUEST},
{(char *)"sql", 2, CA_GOD, CA_SQL_OK},
{(char *)"staff", 3, CA_WIZARD, CA_STAFF},
{(char *)"static", 3, CA_GOD, CA_STATIC},
{(char *)"wizard", 3, CA_WIZARD, CA_WIZARD},
{NULL, 0, 0, 0}};
static void list_cmdaccess(player)
dbref player;
{
char *buff, *p, *q;
CMDENT *cmdp;
ATTR *ap;
buff = alloc_sbuf("list_cmdaccess");
for (cmdp = command_table; cmdp->cmdname; cmdp++) {
if (check_access(player, cmdp->perms)) {
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff, "%s:", cmdp->cmdname);
listset_nametab(player, access_nametab,
cmdp->perms, buff, 1);
}
}
}
for (ap = attr; ap->name; ap++) {
p = buff;
*p++ = '@';
for (q = (char *)ap->name; *q; p++, q++)
*p = ToLower(*q);
if (ap->flags & AF_NOCMD)
continue;
*p = '\0';
cmdp = (CMDENT *) hashfind(buff, &mudstate.command_htab);
if (cmdp == NULL)
continue;
if (!check_access(player, cmdp->perms))
continue;
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff, "%s:", cmdp->cmdname);
listset_nametab(player, access_nametab,
cmdp->perms, buff, 1);
}
}
free_sbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_cmdswitches: List switches for commands.
*/
static void list_cmdswitches(player)
dbref player;
{
char *buff;
CMDENT *cmdp;
buff = alloc_sbuf("list_cmdswitches");
for (cmdp = command_table; cmdp->cmdname; cmdp++) {
if (cmdp->switches) {
if (check_access(player, cmdp->perms)) {
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff, "%s:", cmdp->cmdname);
display_nametab(player, cmdp->switches,
buff, 0);
}
}
}
}
free_sbuf(buff);
}
/* *INDENT-OFF* */
/* ---------------------------------------------------------------------------
* list_attraccess: List access to attributes.
*/
NAMETAB attraccess_nametab[] = {
{(char *)"dark", 2, CA_WIZARD, AF_DARK},
{(char *)"deleted", 2, CA_WIZARD, AF_DELETED},
{(char *)"god", 1, CA_PUBLIC, AF_GOD},
{(char *)"hidden", 1, CA_WIZARD, AF_MDARK},
{(char *)"html", 2, CA_PUBLIC, AF_HTML},
{(char *)"ignore", 2, CA_WIZARD, AF_NOCMD},
{(char *)"internal", 2, CA_WIZARD, AF_INTERNAL},
{(char *)"is_lock", 4, CA_PUBLIC, AF_IS_LOCK},
{(char *)"locked", 1, CA_PUBLIC, AF_LOCK},
{(char *)"no_clone", 5, CA_PUBLIC, AF_NOCLONE},
{(char *)"no_command", 5, CA_PUBLIC, AF_NOPROG},
{(char *)"no_inherit", 4, CA_PUBLIC, AF_PRIVATE},
{(char *)"no_parse", 4, CA_PUBLIC, AF_NOPARSE},
{(char *)"private", 1, CA_PUBLIC, AF_ODARK},
{(char *)"regexp", 1, CA_PUBLIC, AF_REGEXP},
{(char *)"visual", 1, CA_PUBLIC, AF_VISUAL},
{(char *)"wizard", 1, CA_PUBLIC, AF_WIZARD},
{ NULL, 0, 0, 0}};
NAMETAB indiv_attraccess_nametab[] = {
{(char *)"hidden", 1, CA_WIZARD, AF_MDARK},
{(char *)"wizard", 1, CA_WIZARD, AF_WIZARD},
{(char *)"no_command", 4, CA_PUBLIC, AF_NOPROG},
{(char *)"no_inherit", 4, CA_PUBLIC, AF_PRIVATE},
{(char *)"no_parse", 4, CA_PUBLIC, AF_NOPARSE},
{(char *)"visual", 1, CA_PUBLIC, AF_VISUAL},
{(char *)"regexp", 1, CA_PUBLIC, AF_REGEXP},
{(char *)"html", 2, CA_PUBLIC, AF_HTML},
{ NULL, 0, 0, 0}};
/* *INDENT-ON* */
static void list_attraccess(player)
dbref player;
{
char *buff;
ATTR *ap;
buff = alloc_sbuf("list_attraccess");
for (ap = attr; ap->name; ap++) {
if (Read_attr(player, player, ap, player, 0)) {
sprintf(buff, "%s:", ap->name);
listset_nametab(player, attraccess_nametab,
ap->flags, buff, 1);
}
}
free_sbuf(buff);
}
/* ---------------------------------------------------------------------------
* cf_access: Change command or switch permissions.
*/
extern void FDECL(cf_log_notfound, (dbref, char *, const char *, char *));
CF_HAND(cf_access)
{
CMDENT *cmdp;
char *ap;
int set_switch;
for (ap = str; *ap && !isspace(*ap) && (*ap != '/'); ap++) ;
if (*ap == '/') {
set_switch = 1;
*ap++ = '\0';
} else {
set_switch = 0;
if (*ap)
*ap++ = '\0';
while (*ap && isspace(*ap))
ap++;
}
cmdp = (CMDENT *) hashfind(str, &mudstate.command_htab);
if (cmdp != NULL) {
if (set_switch)
return cf_ntab_access((int *)cmdp->switches, ap,
extra, player, cmd);
else
return cf_modify_bits(&(cmdp->perms), ap,
extra, player, cmd);
} else {
cf_log_notfound(player, cmd, "Command", str);
return -1;
}
}
/* ---------------------------------------------------------------------------
* cf_acmd_access: Chante command permissions for all attr-setting cmds.
*/
CF_HAND(cf_acmd_access)
{
CMDENT *cmdp;
ATTR *ap;
char *buff, *p, *q;
int failure, save;
buff = alloc_sbuf("cf_acmd_access");
for (ap = attr; ap->name; ap++) {
p = buff;
*p++ = '@';
for (q = (char *)ap->name; *q; p++, q++)
*p = ToLower(*q);
*p = '\0';
cmdp = (CMDENT *) hashfind(buff, &mudstate.command_htab);
if (cmdp != NULL) {
save = cmdp->perms;
failure = cf_modify_bits(&(cmdp->perms), str,
extra, player, cmd);
if (failure != 0) {
cmdp->perms = save;
free_sbuf(buff);
return -1;
}
}
}
free_sbuf(buff);
return 0;
}
/* ---------------------------------------------------------------------------
* cf_attr_access: Change access on an attribute.
*/
CF_HAND(cf_attr_access)
{
ATTR *ap;
char *sp;
for (sp = str; *sp && !isspace(*sp); sp++) ;
if (*sp)
*sp++ = '\0';
while (*sp && isspace(*sp))
sp++;
ap = atr_str(str);
if (ap != NULL)
return cf_modify_bits(&(ap->flags), sp, extra, player, cmd);
else {
cf_log_notfound(player, cmd, "Attribute", str);
return -1;
}
}
/* ---------------------------------------------------------------------------
* cf_cmd_alias: Add a command alias.
*/
CF_HAND(cf_cmd_alias)
{
char *alias, *orig, *ap, *tokst;
CMDENT *cmdp, *cmd2;
NAMETAB *nt;
int *hp;
alias = strtok_r(str, " \t=,", &tokst);
orig = strtok_r(NULL, " \t=,", &tokst);
if (!orig) /* we only got one argument to @alias. Bad. */
return -1;
for (ap = orig; *ap && (*ap != '/'); ap++) ;
if (*ap == '/') {
/* Switch form of command aliasing: create an alias for a
* command + a switch
*/
*ap++ = '\0';
/* Look up the command */
cmdp = (CMDENT *) hashfind(orig, (HASHTAB *) vp);
if (cmdp == NULL) {
cf_log_notfound(player, cmd, "Command", orig);
return -1;
}
/* Look up the switch */
nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap);
if (!nt) {
cf_log_notfound(player, cmd, "Switch", ap);
return -1;
}
/*
* Got it, create the new command table entry
*/
cmd2 = (CMDENT *) XMALLOC(sizeof(CMDENT), "cf_cmd_alias");
cmd2->cmdname = strsave(alias);
cmd2->switches = cmdp->switches;
cmd2->perms = cmdp->perms | nt->perm;
cmd2->extra = (cmdp->extra | nt->flag) & ~SW_MULTIPLE;
if (!(nt->flag & SW_MULTIPLE))
cmd2->extra |= SW_GOT_UNIQUE;
cmd2->callseq = cmdp->callseq;
/*
* KNOWN PROBLEM:
* We are not inheriting the hook that the 'original' command
* had -- we will have to add it manually (whereas an alias
* of a non-switched command is just another hashtable entry
* for the same command pointer and therefore gets the hook).
* This is preferable to having to search the hashtable for
* hooks when a hook is deleted, though.
*/
cmd2->pre_hook = NULL;
cmd2->post_hook = NULL;
cmd2->info.handler = cmdp->info.handler;
if (hashadd(cmd2->cmdname, (int *)cmd2, (HASHTAB *) vp)) {
XFREE(cmd2->cmdname, "cf_cmd_alias.2");
XFREE(cmd2, "cf_cmd_alias.3");
}
} else {
/* A normal (non-switch) alias */
hp = hashfind(orig, (HASHTAB *) vp);
if (hp == NULL) {
cf_log_notfound(player, cmd, "Entry", orig);
return -1;
}
hashadd(alias, hp, (HASHTAB *) vp);
}
return 0;
}
/* ---------------------------------------------------------------------------
* list_df_flags: List default flags at create time.
*/
static void list_df_flags(player)
dbref player;
{
char *playerb, *roomb, *thingb, *exitb, *robotb, *stripb, *buff;
playerb = decode_flags(player,
(mudconf.player_flags.word1 | TYPE_PLAYER),
mudconf.player_flags.word2,
mudconf.player_flags.word3);
roomb = decode_flags(player,
(mudconf.room_flags.word1 | TYPE_ROOM),
mudconf.room_flags.word2,
mudconf.room_flags.word3);
exitb = decode_flags(player,
(mudconf.exit_flags.word1 | TYPE_EXIT),
mudconf.exit_flags.word2,
mudconf.exit_flags.word3);
thingb = decode_flags(player,
(mudconf.thing_flags.word1 | TYPE_THING),
mudconf.thing_flags.word2,
mudconf.thing_flags.word3);
robotb = decode_flags(player,
(mudconf.robot_flags.word1 | TYPE_PLAYER),
mudconf.robot_flags.word2,
mudconf.robot_flags.word3);
stripb = decode_flags(player,
mudconf.stripped_flags.word1,
mudconf.stripped_flags.word2,
mudconf.stripped_flags.word3);
buff = alloc_lbuf("list_df_flags");
sprintf(buff,
"Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s Stripped...%s",
playerb, roomb, exitb, thingb, robotb, stripb);
raw_notify(player, buff);
free_lbuf(buff);
free_sbuf(playerb);
free_sbuf(roomb);
free_sbuf(exitb);
free_sbuf(thingb);
free_sbuf(robotb);
free_sbuf(stripb);
}
/* ---------------------------------------------------------------------------
* list_costs: List the costs of things.
*/
#define coin_name(s) (((s)==1) ? mudconf.one_coin : mudconf.many_coins)
static void list_costs(player)
dbref player;
{
char *buff;
buff = alloc_mbuf("list_costs");
*buff = '\0';
if (mudconf.quotas)
sprintf(buff, " and %d quota", mudconf.room_quota);
notify(player,
tprintf("Digging a room costs %d %s%s.",
mudconf.digcost, coin_name(mudconf.digcost), buff));
if (mudconf.quotas)
sprintf(buff, " and %d quota", mudconf.exit_quota);
notify(player,
tprintf("Opening a new exit costs %d %s%s.",
mudconf.opencost, coin_name(mudconf.opencost), buff));
notify(player,
tprintf("Linking an exit, home, or dropto costs %d %s.",
mudconf.linkcost, coin_name(mudconf.linkcost)));
if (mudconf.quotas)
sprintf(buff, " and %d quota", mudconf.thing_quota);
if (mudconf.createmin == mudconf.createmax)
raw_notify(player,
tprintf("Creating a new thing costs %d %s%s.",
mudconf.createmin,
coin_name(mudconf.createmin), buff));
else
raw_notify(player,
tprintf("Creating a new thing costs between %d and %d %s%s.",
mudconf.createmin, mudconf.createmax,
mudconf.many_coins, buff));
if (mudconf.quotas)
sprintf(buff, " and %d quota", mudconf.player_quota);
notify(player,
tprintf("Creating a robot costs %d %s%s.",
mudconf.robotcost, coin_name(mudconf.robotcost),
buff));
if (mudconf.killmin == mudconf.killmax) {
raw_notify(player,
tprintf("Killing costs %d %s, with a %d%% chance of success.",
mudconf.killmin, coin_name(mudconf.digcost),
(mudconf.killmin * 100) /
mudconf.killguarantee));
} else {
raw_notify(player,
tprintf("Killing costs between %d and %d %s.",
mudconf.killmin, mudconf.killmax,
mudconf.many_coins));
raw_notify(player,
tprintf("You must spend %d %s to guarantee success.",
mudconf.killguarantee,
coin_name(mudconf.killguarantee)));
}
raw_notify(player,
tprintf("Computationally expensive commands and functions (ie: @entrances, @find, @search, @stats (with an argument or switch), search(), and stats()) cost %d %s.",
mudconf.searchcost, coin_name(mudconf.searchcost)));
if (mudconf.machinecost > 0)
raw_notify(player,
tprintf("Each command run from the queue costs 1/%d %s.",
mudconf.machinecost, mudconf.one_coin));
if (mudconf.waitcost > 0) {
raw_notify(player,
tprintf("A %d %s deposit is charged for putting a command on the queue.",
mudconf.waitcost, mudconf.one_coin));
raw_notify(player, "The deposit is refunded when the command is run or canceled.");
}
if (mudconf.sacfactor == 0)
sprintf(buff, "%d", mudconf.sacadjust);
else if (mudconf.sacfactor == 1) {
if (mudconf.sacadjust < 0)
sprintf(buff, "<create cost> - %d", -mudconf.sacadjust);
else if (mudconf.sacadjust > 0)
sprintf(buff, "<create cost> + %d", mudconf.sacadjust);
else
sprintf(buff, "<create cost>");
} else {
if (mudconf.sacadjust < 0)
sprintf(buff, "(<create cost> / %d) - %d",
mudconf.sacfactor, -mudconf.sacadjust);
else if (mudconf.sacadjust > 0)
sprintf(buff, "(<create cost> / %d) + %d",
mudconf.sacfactor, mudconf.sacadjust);
else
sprintf(buff, "<create cost> / %d", mudconf.sacfactor);
}
raw_notify(player, tprintf("The value of an object is %s.", buff));
if (mudconf.clone_copy_cost)
raw_notify(player, "The default value of cloned objects is the value of the original object.");
else
raw_notify(player,
tprintf("The default value of cloned objects is %d %s.",
mudconf.createmin,
coin_name(mudconf.createmin)));
free_mbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_options: List boolean game options from mudconf.
* list_config: List non-boolean game options.
*/
extern void FDECL(list_options, (dbref));
static void list_params(player)
dbref player;
{
time_t now;
now = time(NULL);
raw_notify(player,
tprintf("Default Parents: Room...#%d Exit...#%d Thing...#%d Player...#%d",
mudconf.room_parent, mudconf.exit_parent,
mudconf.thing_parent, mudconf.player_parent));
raw_notify(player, "Limits:");
raw_notify(player,
tprintf(" Output...%d Queue...%d Recursion...%d Invocation...%d",
mudconf.output_limit, mudconf.queuemax,
mudconf.func_nest_lim, mudconf.func_invk_lim));
raw_notify(player,
tprintf(" Stacks...%d Variables...%d Structures...%d Instances...%d",
mudconf.stack_lim, mudconf.numvars_lim,
mudconf.struct_lim, mudconf.instance_lim));
raw_notify(player,
tprintf(" Objects...%d Allowance...%d Trace levels...%d Connect tries...%d",
mudconf.building_limit, mudconf.paylimit,
mudconf.trace_limit, mudconf.retry_limit));
if (mudconf.max_players >= 0)
raw_notify(player, tprintf(" Logins...%d", mudconf.max_players));
raw_notify(player,
tprintf("Nesting: Locks...%d Parents...%d Messages...%d Zones...%d",
mudconf.lock_nest_lim, mudconf.parent_nest_lim,
mudconf.ntfy_nest_lim, mudconf.zone_nest_lim));
raw_notify(player,
tprintf("Timeouts: Idle...%d Connect...%d Tries...%d Lag...%d",
mudconf.idle_timeout, mudconf.conn_timeout,
mudconf.retry_limit, mudconf.max_cmdsecs));
raw_notify(player,
tprintf("Money: Start...%d Daily...%d Singular: %s Plural: %s",
mudconf.paystart, mudconf.paycheck,
mudconf.one_coin, mudconf.many_coins));
if (mudconf.payfind > 0)
raw_notify(player, tprintf("Chance of finding money: 1 in %d",
mudconf.payfind));
raw_notify(player,
tprintf("Start Quotas: Total...%d Rooms...%d Exits...%d Things...%d Players...%d",
mudconf.start_quota,
mudconf.start_room_quota, mudconf.start_exit_quota,
mudconf.start_thing_quota, mudconf.start_player_quota));
raw_notify(player, "Dbrefs:");
raw_notify(player,
tprintf(" MasterRoom...#%d StartRoom...#%d StartHome...#%d DefaultHome...#%d",
mudconf.master_room, mudconf.start_room, mudconf.start_home,
mudconf.default_home));
if (Wizard(player)) {
raw_notify(player,
tprintf(" GuestChar...#%d GuestStart...#%d Freelist...#%d",
mudconf.guest_char, mudconf.guest_start_room,
mudstate.freelist));
raw_notify(player,
tprintf("Queue run sizes: No net activity... %d Activity... %d",
mudconf.queue_chunk, mudconf.active_q_chunk));
raw_notify(player,
tprintf("Intervals: Dump...%d Clean...%d Idlecheck...%d Optimize...%d",
mudconf.dump_interval, mudconf.check_interval,
mudconf.idle_interval, mudconf.dbopt_interval));
raw_notify(player,
tprintf("Timers: Dump...%d Clean...%d Idlecheck...%d",
(int) (mudstate.dump_counter - now),
(int) (mudstate.check_counter - now),
(int) (mudstate.idle_counter - now)));
raw_notify(player,
tprintf("Scheduling: Timeslice...%d Max_Quota...%d Increment...%d",
mudconf.timeslice, mudconf.cmd_quota_max,
mudconf.cmd_quota_incr));
raw_notify(player,
tprintf("Size of %s cache: Width...%d Depth...%d",
CACHING, mudconf.cache_width, mudconf.cache_depth));
}
}
/* ---------------------------------------------------------------------------
* list_vattrs: List user-defined attributes
*/
static void list_vattrs(player)
dbref player;
{
VATTR *va;
int na;
char *buff;
buff = alloc_lbuf("list_vattrs");
raw_notify(player, "--- User-Defined Attributes ---");
for (va = vattr_first(), na = 0; va; va = vattr_next(va), na++) {
if (!(va->flags & AF_DELETED)) {
sprintf(buff, "%s(%d):", va->name, va->number);
listset_nametab(player, attraccess_nametab, va->flags,
buff, 1);
}
}
raw_notify(player, tprintf("%d attributes, next=%d",
na, mudstate.attr_next));
free_lbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_hashstats: List information from hash tables
*/
static void list_hashstat(player, tab_name, htab)
dbref player;
HASHTAB *htab;
const char *tab_name;
{
char *buff;
buff = hashinfo(tab_name, htab);
raw_notify(player, buff);
free_mbuf(buff);
}
static void list_nhashstat(player, tab_name, htab)
dbref player;
NHSHTAB *htab;
const char *tab_name;
{
char *buff;
buff = nhashinfo(tab_name, htab);
raw_notify(player, buff);
free_mbuf(buff);
}
static void list_hashstats(player)
dbref player;
{
raw_notify(player, "Hash Stats Size Entries Deleted Empty Lookups Hits Checks Longest");
list_hashstat(player, "Commands", &mudstate.command_htab);
list_hashstat(player, "Logged-out Cmds", &mudstate.logout_cmd_htab);
list_hashstat(player, "Functions", &mudstate.func_htab);
list_hashstat(player, "User Functions", &mudstate.ufunc_htab);
list_hashstat(player, "Flags", &mudstate.flags_htab);
list_hashstat(player, "Powers", &mudstate.powers_htab);
list_hashstat(player, "Attr names", &mudstate.attr_name_htab);
list_hashstat(player, "Vattr names", &mudstate.vattr_name_htab);
list_hashstat(player, "Player Names", &mudstate.player_htab);
list_nhashstat(player, "Net Descriptors", &mudstate.desc_htab);
list_nhashstat(player, "Forwardlists", &mudstate.fwdlist_htab);
list_nhashstat(player, "Overlaid $-cmds", &mudstate.parent_htab);
list_nhashstat(player, "Object Stacks", &mudstate.objstack_htab);
list_hashstat(player, "Variables", &mudstate.vars_htab);
list_hashstat(player, "Structure Defs", &mudstate.structs_htab);
list_hashstat(player, "Component Defs", &mudstate.cdefs_htab);
list_hashstat(player, "Instances", &mudstate.instance_htab);
list_hashstat(player, "Instance Data", &mudstate.instdata_htab);
#ifdef USE_MAIL
if (mudconf.have_mailer)
list_nhashstat(player, "Mail messages", &mudstate.mail_htab);
#endif
#ifdef USE_COMSYS
if (mudconf.have_comsys) {
list_hashstat(player, "Channels", &mudstate.comsys_htab);
list_hashstat(player, "Channel aliases", &mudstate.calias_htab);
list_nhashstat(player, "Channel lists", &mudstate.comlist_htab);
}
#endif
}
static void list_textfiles(player)
dbref player;
{
int i;
raw_notify(player, "Help File Size Entries Deleted Empty Lookups Hits Checks Longest");
for (i = 0; i < mudstate.helpfiles; i++)
list_hashstat(player, mudstate.hfiletab[i], &mudstate.hfile_hashes[i]);
}
#ifndef MEMORY_BASED
/* These are from 'udb_cache.c'. */
extern time_t cs_ltime;
extern int cs_writes; /* total writes */
extern int cs_reads; /* total reads */
extern int cs_dbreads; /* total read-throughs */
extern int cs_dbwrites; /* total write-throughs */
extern int cs_dels; /* total deletes */
extern int cs_checks; /* total checks */
extern int cs_rhits; /* total reads filled from cache */
extern int cs_ahits; /* total reads filled active cache */
extern int cs_whits; /* total writes to dirty cache */
extern int cs_fails; /* attempts to grab nonexistent */
extern int cs_resets; /* total cache resets */
extern int cs_syncs; /* total cache syncs */
extern int cs_objects; /* total cache size */
#endif /* MEMORY_BASED */
#ifdef RADIX_COMPRESSION
extern int strings_compressed; /* Total number of compressed strings */
extern int strings_decompressed; /* Total number of decompressed
* strings
*/
extern int chars_in; /* Total characters compressed */
extern int symbols_out; /* Total symbols emitted */
#endif /* RADIX_COMPRESSION */
/* ---------------------------------------------------------------------------
* list_db_stats: Get useful info from the DB layer about hash stats, etc.
*/
static void list_db_stats(player)
dbref player;
{
#ifdef MEMORY_BASED
raw_notify(player, "Database is memory based.");
#else
raw_notify(player,
tprintf("DB Cache Stats Writes Reads (over %d seconds)",
(int) (time(NULL) - cs_ltime)));
raw_notify(player, tprintf("Calls %12d%12d", cs_writes, cs_reads));
raw_notify(player, tprintf("Cache Hits %12d%12d (%d in active cache)",
cs_whits, cs_rhits, cs_ahits));
raw_notify(player, tprintf("I/O %12d%12d",
cs_dbwrites, cs_dbreads));
raw_notify(player, tprintf("\nDeletes %12d", cs_dels));
raw_notify(player, tprintf("Checks %12d", cs_checks));
raw_notify(player, tprintf("Resets %12d", cs_resets));
raw_notify(player, tprintf("Syncs %12d", cs_syncs));
raw_notify(player, tprintf("Cache Size %12d", cs_objects));
#endif /* MEMORY_BASED */
#ifdef RADIX_COMPRESSION
raw_notify(player, "Compression statistics:");
raw_notify(player, tprintf("Strings compressed %d", strings_compressed));
raw_notify(player, tprintf("Strings decompressed %d", strings_decompressed));
raw_notify(player, tprintf("Compression ratio %d:%d", chars_in,
symbols_out + (symbols_out >> 1)));
#endif /* RADIX_COMPRESSION */
}
/* ---------------------------------------------------------------------------
* list_process: List local resource usage stats of the mush process.
* Adapted from code by Claudius@PythonMUCK,
* posted to the net by Howard/Dark_Lord.
*/
static void list_process(player)
dbref player;
{
int pid, psize, maxfds;
#ifdef HAVE_GETRUSAGE
struct rusage usage;
int ixrss, idrss, isrss, curr, last, dur;
getrusage(RUSAGE_SELF, &usage);
/*
* Calculate memory use from the aggregate totals
*/
curr = mudstate.mstat_curr;
last = 1 - curr;
dur = mudstate.mstat_secs[curr] - mudstate.mstat_secs[last];
if (dur > 0) {
ixrss = (mudstate.mstat_ixrss[curr] -
mudstate.mstat_ixrss[last]) / dur;
idrss = (mudstate.mstat_idrss[curr] -
mudstate.mstat_idrss[last]) / dur;
isrss = (mudstate.mstat_isrss[curr] -
mudstate.mstat_isrss[last]) / dur;
} else {
ixrss = 0;
idrss = 0;
isrss = 0;
}
#endif
#ifdef HAVE_GETDTABLESIZE
maxfds = getdtablesize();
#else
maxfds = sysconf(_SC_OPEN_MAX);
#endif
pid = getpid();
psize = getpagesize();
/*
* Go display everything
*/
raw_notify(player,
tprintf("Process ID: %10d %10d bytes per page",
pid, psize));
#ifdef HAVE_GETRUSAGE
raw_notify(player,
tprintf("Time used: %10d user %10d sys",
usage.ru_utime.tv_sec, usage.ru_stime.tv_sec));
/*
* raw_notify(player,
* * tprintf("Resident mem:%10d shared %10d private%10d stack",
* * ixrss, idrss, isrss));
*/
raw_notify(player,
tprintf("Integral mem:%10d shared %10d private%10d stack",
usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss));
raw_notify(player,
tprintf("Max res mem: %10d pages %10d bytes",
usage.ru_maxrss, (usage.ru_maxrss * psize)));
raw_notify(player,
tprintf("Page faults: %10d hard %10d soft %10d swapouts",
usage.ru_majflt, usage.ru_minflt, usage.ru_nswap));
raw_notify(player,
tprintf("Disk I/O: %10d reads %10d writes",
usage.ru_inblock, usage.ru_oublock));
raw_notify(player,
tprintf("Network I/O: %10d in %10d out",
usage.ru_msgrcv, usage.ru_msgsnd));
raw_notify(player,
tprintf("Context swi: %10d vol %10d forced %10d sigs",
usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals));
raw_notify(player,
tprintf("Descs avail: %10d", maxfds));
#endif
}
/* ---------------------------------------------------------------------------
* do_list: List information stored in internal structures.
*/
#define LIST_ATTRIBUTES 1
#define LIST_COMMANDS 2
#define LIST_COSTS 3
#define LIST_FLAGS 4
#define LIST_FUNCTIONS 5
#define LIST_GLOBALS 6
#define LIST_ALLOCATOR 7
#define LIST_LOGGING 8
#define LIST_DF_FLAGS 9
#define LIST_PERMS 10
#define LIST_ATTRPERMS 11
#define LIST_OPTIONS 12
#define LIST_HASHSTATS 13
#define LIST_BUFTRACE 14
#define LIST_CONF_PERMS 15
#define LIST_SITEINFO 16
#define LIST_POWERS 17
#define LIST_SWITCHES 18
#define LIST_VATTRS 19
#define LIST_DB_STATS 20 /* GAC 4/6/92 */
#define LIST_PROCESS 21
#define LIST_BADNAMES 22
#define LIST_CACHEOBJS 23
#define LIST_TEXTFILES 24
#define LIST_PARAMS 25
#define LIST_CF_RPERMS 26
/* *INDENT-OFF* */
NAMETAB list_names[] = {
{(char *)"allocations", 2, CA_WIZARD, LIST_ALLOCATOR},
{(char *)"attr_permissions", 5, CA_WIZARD, LIST_ATTRPERMS},
{(char *)"attributes", 2, CA_PUBLIC, LIST_ATTRIBUTES},
{(char *)"bad_names", 2, CA_WIZARD, LIST_BADNAMES},
{(char *)"buffers", 2, CA_WIZARD, LIST_BUFTRACE},
{(char *)"cache", 2, CA_WIZARD, LIST_CACHEOBJS},
{(char *)"commands", 3, CA_PUBLIC, LIST_COMMANDS},
{(char *)"config_permissions", 8, CA_GOD, LIST_CONF_PERMS},
{(char *)"config_read_perms", 4, CA_PUBLIC, LIST_CF_RPERMS},
{(char *)"costs", 3, CA_PUBLIC, LIST_COSTS},
{(char *)"db_stats", 2, CA_WIZARD, LIST_DB_STATS},
{(char *)"default_flags", 1, CA_PUBLIC, LIST_DF_FLAGS},
{(char *)"flags", 2, CA_PUBLIC, LIST_FLAGS},
{(char *)"functions", 2, CA_PUBLIC, LIST_FUNCTIONS},
{(char *)"globals", 1, CA_WIZARD, LIST_GLOBALS},
{(char *)"hashstats", 1, CA_WIZARD, LIST_HASHSTATS},
{(char *)"logging", 1, CA_GOD, LIST_LOGGING},
{(char *)"options", 1, CA_PUBLIC, LIST_OPTIONS},
{(char *)"params", 2, CA_PUBLIC, LIST_PARAMS},
{(char *)"permissions", 2, CA_WIZARD, LIST_PERMS},
{(char *)"powers", 2, CA_WIZARD, LIST_POWERS},
{(char *)"process", 2, CA_WIZARD, LIST_PROCESS},
{(char *)"site_information", 2, CA_WIZARD, LIST_SITEINFO},
{(char *)"switches", 2, CA_PUBLIC, LIST_SWITCHES},
{(char *)"textfiles", 1, CA_WIZARD, LIST_TEXTFILES},
{(char *)"user_attributes", 1, CA_WIZARD, LIST_VATTRS},
{ NULL, 0, 0, 0}};
/* *INDENT-ON* */
extern NAMETAB enable_names[];
extern NAMETAB logoptions_nametab[];
extern NAMETAB logdata_nametab[];
void do_list(player, cause, extra, arg)
dbref player, cause;
int extra;
char *arg;
{
int flagvalue;
flagvalue = search_nametab(player, list_names, arg);
switch (flagvalue) {
case LIST_ALLOCATOR:
list_bufstats(player);
break;
case LIST_BUFTRACE:
list_buftrace(player);
break;
case LIST_ATTRIBUTES:
list_attrtable(player);
break;
case LIST_COMMANDS:
list_cmdtable(player);
break;
case LIST_SWITCHES:
list_cmdswitches(player);
break;
case LIST_COSTS:
list_costs(player);
break;
case LIST_OPTIONS:
list_options(player);
break;
case LIST_HASHSTATS:
list_hashstats(player);
break;
case LIST_SITEINFO:
list_siteinfo(player);
break;
case LIST_FLAGS:
display_flagtab(player);
break;
case LIST_FUNCTIONS:
list_functable(player);
break;
case LIST_GLOBALS:
interp_nametab(player, enable_names, mudconf.control_flags,
(char *)"Global parameters:", (char *)"enabled",
(char *)"disabled");
break;
case LIST_DF_FLAGS:
list_df_flags(player);
break;
case LIST_PERMS:
list_cmdaccess(player);
break;
case LIST_CONF_PERMS:
list_cf_access(player);
break;
case LIST_CF_RPERMS:
list_cf_read_access(player);
break;
case LIST_POWERS:
display_powertab(player);
break;
case LIST_ATTRPERMS:
list_attraccess(player);
break;
case LIST_VATTRS:
list_vattrs(player);
break;
case LIST_LOGGING:
interp_nametab(player, logoptions_nametab, mudconf.log_options,
(char *)"Events Logged:", (char *)"enabled",
(char *)"disabled");
interp_nametab(player, logdata_nametab, mudconf.log_info,
(char *)"Information Logged:", (char *)"yes",
(char *)"no");
break;
case LIST_DB_STATS:
list_db_stats(player);
break;
case LIST_PROCESS:
list_process(player);
break;
case LIST_BADNAMES:
badname_list(player, "Disallowed names:");
break;
case LIST_CACHEOBJS:
#ifndef MEMORY_BASED
list_cached_objs(player);
#else
raw_notify(player, "No cached objects.");
#endif /* MEMORY_BASED */
break;
case LIST_TEXTFILES:
list_textfiles(player);
break;
case LIST_PARAMS:
list_params(player);
break;
default:
display_nametab(player, list_names,
(char *)"Unknown option. Use one of:", 1);
}
}