/* command.c - command parser and support routines */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char RCSid[] = "$Id: command.c,v 1.11 1995/03/20 23:59:47 ambar Exp $"; USE(RCSid); #endif #include "externs.h" #include "interface.h" #include "command.h" #include "functions.h" #include "match.h" #include "attrs.h" #include "flags.h" #include "alloc.h" #include "vattr.h" extern void FDECL(list_cf_access, (dbref)); extern void FDECL(list_siteinfo, (dbref)); #ifdef CACHE_OBJS #define CACHING "object" #else #define CACHING "attribute" #endif /* 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 /* --------------------------------------------------------------------------- * Switch tables for the various commands. */ #define SW_MULTIPLE 0x80000000 /* This sw may be spec'd w/others */ #define SW_GOT_UNIQUE 0x40000000 /* Already have a unique option */ #define SW_NOEVAL 0x20000000 /* Don't parse args before calling handler */ /* (typically via a switch alias) */ NAMETAB attrib_sw[] = { {(char *) "access", 1, CA_GOD, ATTRIB_ACCESS}, {(char *) "delete", 1, CA_GOD, ATTRIB_DELETE}, {(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}}; NAMETAB clone_sw[] = { {(char *) "cost", 1, CA_PUBLIC, CLONE_SET_COST}, {(char *) "inherit", 3, CA_PUBLIC, CLONE_INHERIT | SW_MULTIPLE}, {(char *) "inventory", 3, CA_PUBLIC, CLONE_INVENTORY}, {(char *) "location", 1, CA_PUBLIC, CLONE_LOCATION}, {(char *) "parent", 2, CA_PUBLIC, CLONE_PARENT | SW_MULTIPLE}, {(char *) "preserve", 2, CA_WIZARD, CLONE_PRESERVE | SW_MULTIPLE}, {NULL, 0, 0, 0}}; NAMETAB destroy_sw[] = { {(char *) "override", 8, CA_PUBLIC, DEST_OVERRIDE}, {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_WIZARD, 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}, {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 /* PUEBLO_SUPPORT */ {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 *) "parent", 1, CA_PUBLIC, EXAM_PARENT}, {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 *) "privileged", 1, CA_WIZARD, FN_PRIV}, {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_WIZARD, HALT_ALL}, {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 *) "controllock", 1, 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}, {NULL, 0, 0, 0}}; NAMETAB look_sw[] = { {(char *) "outside", 1, CA_PUBLIC, LOOK_OUTSIDE}, {NULL, 0, 0, 0}}; 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 parent_sw[] = { {(char *) "parent", 1, CA_PUBLIC, PARENT_PARENT}, {(char *) "zone", 1, CA_PUBLIC, PARENT_ZONE}, {NULL, 0, 0, 0}}; NAMETAB pemit_sw[] = { {(char *) "contents", 1, CA_PUBLIC, PEMIT_CONTENTS}, {(char *) "list", 1, CA_PUBLIC, PEMIT_LIST | SW_MULTIPLE}, {(char *) "object", 1, CA_PUBLIC, 0}, {(char *) "noeval", 1, CA_PUBLIC, SW_NOEVAL | SW_MULTIPLE}, #ifdef PUEBLO_SUPPORT {(char *) "html", 1, CA_PUBLIC, PEMIT_HTML | SW_MULTIPLE}, #endif /* PUEBLO_SUPPORT */ {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_WIZARD, 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 rwho_sw[] = { {(char *) "start", 3, CA_PUBLIC, RWHO_START}, {(char *) "stop", 3, CA_PUBLIC, RWHO_STOP}, {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 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_WIZARD, SAY_WALLEMIT}, {(char *) "no_prefix", 1, CA_WIZARD, SAY_NOTAG | SW_MULTIPLE}, {(char *) "pose", 1, CA_WIZARD, SAY_WALLPOSE}, {(char *) "wizard", 1, CA_WIZARD, SAY_WIZSHOUT | SW_MULTIPLE}, {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 *) "rwho", 1, CA_WIZARD, TWARP_RWHO | 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, 0, 0, CS_NO_ARGS, do_comment}, {(char *) "@admin", NULL, CA_GOD, 0, CS_TWO_ARG | CS_INTERP, do_admin}, {(char *) "@alias", NULL, CA_NO_GUEST | CA_NO_SLAVE, 0, CS_TWO_ARG, do_alias}, {(char *) "@apply_marked", NULL, CA_WIZARD | CA_GBL_INTERP, 0, CS_ONE_ARG | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND, do_apply_marked}, {(char *) "@attribute", attrib_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP, do_attribute}, {(char *) "@boot", boot_sw, CA_WIZARD, 0, CS_ONE_ARG | CS_INTERP, do_boot}, {(char *) "@chown", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, CHOWN_ONE, CS_TWO_ARG | CS_INTERP, do_chown}, {(char *) "@chownall", NULL, CA_WIZARD | CA_GBL_BUILD, CHOWN_ALL, CS_TWO_ARG | CS_INTERP, do_chownall}, {(char *) "@clone", clone_sw, CA_NO_SLAVE | CA_GBL_BUILD | CA_CONTENTS | CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_clone}, {(char *) "@create", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_CONTENTS | CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_create}, {(char *) "@cut", NULL, CA_WIZARD | CA_LOCATION, 0, CS_ONE_ARG | CS_INTERP, do_cut}, {(char *) "@dbck", NULL, CA_WIZARD, 0, CS_NO_ARGS, do_dbck}, {(char *) "@decompile", NULL, 0, 0, CS_TWO_ARG | CS_INTERP, do_decomp}, {(char *) "@destroy", destroy_sw, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, DEST_ONE, CS_ONE_ARG | CS_INTERP, do_destroy}, {(char *) "@dig", dig_sw, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0, CS_TWO_ARG | CS_ARGV | CS_INTERP, do_dig}, {(char *) "@disable", NULL, CA_WIZARD, GLOB_DISABLE, CS_ONE_ARG, do_global}, {(char *) "@doing", doing_sw, CA_PLAYER, 0, CS_ONE_ARG, do_doing}, {(char *) "@dolist", dolist_sw, CA_GBL_INTERP, 0, CS_TWO_ARG | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND, do_dolist}, {(char *) "@drain", NULL, CA_GBL_INTERP | CA_NO_SLAVE | CA_NO_GUEST, NFY_DRAIN, CS_TWO_ARG, do_notify}, {(char *) "@dump", dump_sw, CA_WIZARD, 0, CS_NO_ARGS, do_dump}, {(char *) "@edit", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_TWO_ARG | CS_ARGV | CS_STRIP_AROUND, do_edit}, {(char *) "@emit", emit_sw, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "@enable", NULL, CA_WIZARD, GLOB_ENABLE, CS_ONE_ARG, do_global}, {(char *) "@entrances", NULL, CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP, do_entrances}, {(char *) "@femit", femit_sw, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE, PEMIT_FEMIT, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "@find", NULL, 0, 0, CS_ONE_ARG | CS_INTERP, do_find}, {(char *) "@fixdb", fixdb_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP, do_fixdb}, {(char *) "@force", NULL, CA_NO_SLAVE | CA_GBL_INTERP | CA_NO_GUEST, FRC_COMMAND, CS_TWO_ARG | CS_INTERP | CS_CMDARG, do_force}, {(char *) "@fpose", fpose_sw, CA_LOCATION | CA_NO_SLAVE, PEMIT_FPOSE, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "@fsay", NULL, CA_LOCATION | CA_NO_SLAVE, PEMIT_FSAY, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "@function", function_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP, do_function}, {(char *) "@halt", halt_sw, CA_NO_SLAVE, 0, CS_ONE_ARG | CS_INTERP, do_halt}, {(char *) "@kick", NULL, CA_WIZARD, QUEUE_KICK, CS_ONE_ARG | CS_INTERP, do_queue}, {(char *) "@last", NULL, CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP, do_last}, {(char *) "@link", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_link}, {(char *) "@list", NULL, 0, 0, CS_ONE_ARG | CS_INTERP, do_list}, {(char *) "@list_file", NULL, CA_WIZARD, 0, CS_ONE_ARG | CS_INTERP, do_list_file}, {(char *) "@listmotd", listmotd_sw, 0, MOTD_LIST, CS_ONE_ARG, do_motd}, {(char *) "@lock", lock_sw, CA_NO_SLAVE | CA_GBL_BUILD, 0, CS_TWO_ARG | CS_INTERP, do_lock}, {(char *) "@mark", mark_sw, CA_WIZARD, SRCH_MARK, CS_ONE_ARG | CS_NOINTERP, do_search}, {(char *) "@mark_all", markall_sw, CA_WIZARD, MARK_SET, CS_NO_ARGS, do_markall}, {(char *) "@motd", motd_sw, CA_WIZARD, 0, CS_ONE_ARG, do_motd}, {(char *) "@mudwho", NULL, CA_NO_SLAVE, 0, CS_TWO_ARG | CS_INTERP, do_mudwho}, {(char *) "@mvattr", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0, CS_TWO_ARG | CS_ARGV, do_mvattr}, {(char *) "@name", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_name}, {(char *) "@newpassword", NULL, CA_WIZARD, PASS_ANY, CS_TWO_ARG, do_newpassword}, {(char *) "@notify", notify_sw, CA_GBL_INTERP | CA_NO_SLAVE | CA_NO_GUEST, 0, CS_TWO_ARG, do_notify}, {(char *) "@oemit", NULL, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE, PEMIT_OEMIT, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "@open", open_sw, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0, CS_TWO_ARG | CS_ARGV | CS_INTERP, do_open}, {(char *) "@parent", parent_sw, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0, CS_TWO_ARG, do_parent}, {(char *) "@password", NULL, CA_NO_GUEST, PASS_MINE, CS_TWO_ARG, do_password}, {(char *) "@pcreate", NULL, CA_WIZARD | CA_GBL_BUILD, PCRE_PLAYER, CS_TWO_ARG, do_pcreate}, {(char *) "@pemit", pemit_sw, CA_NO_GUEST | CA_NO_SLAVE, PEMIT_PEMIT, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "@poor", NULL, CA_GOD, 0, CS_ONE_ARG | CS_INTERP, do_poor}, {(char *) "@ps", ps_sw, 0, 0, CS_ONE_ARG | CS_INTERP, do_ps}, {(char *) "@quota", quota_sw, 0, 0, CS_TWO_ARG | CS_INTERP, do_quota}, {(char *) "@readcache", NULL, CA_WIZARD, 0, CS_NO_ARGS, do_readcache}, {(char *) "@robot", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST | CA_PLAYER, PCRE_ROBOT, CS_TWO_ARG, do_pcreate}, {(char *) "@rwho", rwho_sw, CA_GOD, 0, CS_NO_ARGS, do_rwho}, {(char *) "@search", NULL, 0, SRCH_SEARCH, CS_ONE_ARG | CS_NOINTERP, do_search}, {(char *) "@set", NULL /* set_sw */ , CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0, CS_TWO_ARG, do_set}, {(char *) "@shutdown", shutdown_sw, CA_WIZARD, 0, CS_ONE_ARG, do_shutdown}, {(char *) "@stats", stats_sw, 0, 0, CS_ONE_ARG | CS_INTERP, do_stats}, {(char *) "@sweep", sweep_sw, 0, 0, CS_ONE_ARG, do_sweep}, {(char *) "@switch", switch_sw, CA_GBL_INTERP, 0, CS_TWO_ARG | CS_ARGV | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND, do_switch}, {(char *) "@teleport", NULL, CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_teleport}, {(char *) "@timewarp", warp_sw, CA_WIZARD, 0, CS_ONE_ARG | CS_INTERP, do_timewarp}, {(char *) "@toad", toad_sw, CA_WIZARD, 0, CS_TWO_ARG | CS_INTERP, do_toad}, {(char *) "@trigger", trig_sw, CA_GBL_INTERP, 0, CS_TWO_ARG | CS_ARGV, do_trigger}, {(char *) "@unlink", NULL, CA_NO_SLAVE | CA_GBL_BUILD, 0, CS_ONE_ARG | CS_INTERP, do_unlink}, {(char *) "@unlock", lock_sw, CA_NO_SLAVE | CA_GBL_BUILD, 0, CS_ONE_ARG | CS_INTERP, do_unlock}, {(char *) "@verb", NULL, CA_GBL_INTERP | CA_NO_SLAVE, 0, CS_TWO_ARG | CS_ARGV | CS_INTERP | CS_STRIP_AROUND, do_verb}, {(char *) "@wait", NULL, CA_GBL_INTERP, 0, CS_TWO_ARG | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND, do_wait}, {(char *) "@wall", wall_sw, CA_WIZARD, SAY_SHOUT, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "@wipe", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0, CS_ONE_ARG | CS_INTERP, do_wipe}, {(char *) "drop", drop_sw, CA_NO_SLAVE | CA_CONTENTS | CA_LOCATION | CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP, do_drop}, {(char *) "enter", enter_sw, CA_LOCATION, 0, CS_ONE_ARG | CS_INTERP, do_enter}, {(char *) "examine", examine_sw, 0, 0, CS_ONE_ARG | CS_INTERP, do_examine}, {(char *) "get", get_sw, CA_LOCATION | CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP, do_get}, {(char *) "give", give_sw, CA_LOCATION | CA_NO_GUEST, 0, CS_TWO_ARG | CS_INTERP, do_give}, {(char *) "goto", goto_sw, CA_LOCATION, 0, CS_ONE_ARG | CS_INTERP, do_move}, {(char *) "help", NULL, 0, HELP_HELP, CS_ONE_ARG, do_help}, {(char *) "inventory", NULL, 0, LOOK_INVENTORY, CS_NO_ARGS, do_inventory}, {(char *) "kill", NULL, CA_NO_GUEST | CA_NO_SLAVE, KILL_KILL, CS_TWO_ARG | CS_INTERP, do_kill}, {(char *) "leave", leave_sw, CA_LOCATION, 0, CS_NO_ARGS | CS_INTERP, do_leave}, {(char *) "look", look_sw, CA_LOCATION, LOOK_LOOK, CS_ONE_ARG | CS_INTERP, do_look}, {(char *) "news", NULL, 0, HELP_NEWS, CS_ONE_ARG, do_help}, {(char *) "page", NULL, CA_NO_SLAVE, 0, CS_TWO_ARG | CS_INTERP, do_page}, {(char *) "pose", pose_sw, CA_LOCATION | CA_NO_SLAVE, SAY_POSE, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "say", NULL, CA_LOCATION | CA_NO_SLAVE, SAY_SAY, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "score", NULL, 0, LOOK_SCORE, CS_NO_ARGS, do_score}, {(char *) "slay", NULL, CA_WIZARD, KILL_SLAY, CS_TWO_ARG | CS_INTERP, do_kill}, {(char *) "use", NULL, CA_NO_SLAVE | CA_GBL_INTERP, 0, CS_ONE_ARG | CS_INTERP, do_use}, {(char *) "version", NULL, 0, 0, CS_NO_ARGS, do_version}, {(char *) "whisper", NULL, CA_LOCATION | CA_NO_SLAVE, PEMIT_WHISPER, CS_TWO_ARG | CS_INTERP, do_pemit}, {(char *) "wizhelp", NULL, CA_WIZARD, HELP_WIZHELP, CS_ONE_ARG, do_help}, {(char *) "\\", NULL, CA_NO_GUEST | CA_LOCATION | CF_DARK | CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "#", NULL, CA_NO_SLAVE | CA_GBL_INTERP | CF_DARK, 0, CS_ONE_ARG | CS_INTERP | CS_CMDARG, do_force_prefixed}, {(char *) ":", NULL, CA_LOCATION | CF_DARK | CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "\"", NULL, CA_LOCATION | CF_DARK | CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG | CS_INTERP, do_say}, {(char *) "&", NULL, CA_NO_GUEST | CA_NO_SLAVE | CF_DARK, 0, CS_TWO_ARG, do_setvattr}, {(char *) NULL, NULL, 0, 0, 0, NULL}}; CMDENT *prefix_cmds[256]; CMDENT *goto_cmdp; void NDECL(init_cmdtab) { CMDENT *cp; ATTR *ap; char *p, *q; int anum; char *cbuff; hashinit(&mudstate.command_htab, 511); /* 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; if (ap->flags & (AF_WIZARD | AF_MDARK)) { cp->perms |= CA_WIZARD; } cp->extra = ap->number; cp->callseq = CS_TWO_ARG; cp->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); /* 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 (anum = 0; anum < A_USER_START; anum++) prefix_cmds[anum] = 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); goto_cmdp = (CMDENT *) hashfind("goto", &mudstate.command_htab); } /* --------------------------------------------------------------------------- * check_access: Check if player has access to function. */ int check_access(player, mask) dbref player; int mask; { int succ, fail; if (mask & CA_DISABLED) 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_IMMORTAL)) { if (Immortal(player)) succ++; else fail++; } if ((succ == 0) && (mask & CA_BUILDER)) { if (Builder(player)) succ++; else fail++; } if ((succ == 0) && (mask & CA_ROBOT)) { if (Robot(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_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; char *args[MAX_ARG]; int nargs, i, fail, interp, key, xkey; #define Protect(x) (cmdp->perms & x) /* Perform object type checks. */ fail = 0; if (Protect(CA_LOCATION) && !Has_location(player)) fail++; if (Protect(CA_CONTENTS) && !Has_contents(player)) fail++; if (Protect(CA_PLAYER) && !isPlayer(player)) fail++; if (fail > 0) { 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, "Permission denied."); return; } /* Check global flags */ if (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 & SW_MULTIPLE)) { if (i == 1) { notify(player, "Illegal combination of switches."); return; } i = 1; } else { xkey &= ~SW_MULTIPLE; } key |= xkey; switchp = buf1; } while (buf1); } else if (switchp) { notify(player, tprintf("Command %s does not take switches.", cmdp->cmdname)); return; } /* We are allowed to run the command. Now, call the handler using the * appropriate calling sequence and arguments. */ /* 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->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->handler)) (player, unp_command); break; } /* Interpret if necessary */ if (interp & EV_EVAL) buf1 = exec(player, cause, interp | EV_FCHECK | EV_TOP, arg, cargs, ncargs); else buf1 = parse_to(&arg, '\0', interp | EV_TOP); /* Call the correct handler */ if (cmdp->callseq & CS_CMDARG) { (*(cmdp->handler)) (player, cause, key, buf1, cargs, ncargs); } else { (*(cmdp->handler)) (player, cause, key, buf1); } /* Free the buffer if one was allocated */ if (interp & EV_EVAL) 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 = exec(player, cause, EV_STRIP | EV_FCHECK | EV_EVAL | EV_TOP, buf2, cargs, ncargs); 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->handler)) (player, cause, key, buf1, args, nargs, cargs, ncargs); } else { (*(cmdp->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 = exec(player, cause, interp | EV_FCHECK | EV_TOP, arg, cargs, ncargs); } 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->handler)) (player, cause, key, buf1, buf2, cargs, ncargs); } else { (*(cmdp->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; } 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; int succ, aflags, i, got_stop; dbref exit, aowner, parent; CMDENT *cmdp; cache_reset(0); /* Robustify player */ cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *) "< process_command >"; if (!command) 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) && !(isPlayer(player) && interactive))) { notify(Owner(player), tprintf("Attempt to execute command by halted object #%d", player)); mudstate.debug_cmd = cmdsave; return command; } STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL") log_name_and_loc(player); lcbuf = alloc_lbuf("process_command.LOG.allcmds"); sprintf(lcbuf, " entered: '%s'", command); log_text(lcbuf); free_lbuf(lcbuf); 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.curr_cmd = preserve_cmd; mudstate.debug_cmd = command; if (mudconf.space_compress) { p = q = command; while (*p) { while (*p && !isspace(*p)) *q++ = *p++; /* scan over word */ while (*p && isspace(*p)) p++; /* smash spaces */ if (*p) *q++ = ' '; /* separate words */ } *q = '\0'; /* terminate string */ } /* Reset the cache so that unreferenced attributes may be flushed */ cache_reset(); /* 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; } /* Check for the HOME command */ if (string_compare(command, "home") == 0) { 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) { move_exit(player, exit, 0, "You can't go that way.", 0); 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) { move_exit(player, exit, 1, NULL, 0); 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) { 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. */ free_lbuf(lcbuf); lcbuf = exec(player, cause, EV_EVAL | EV_FCHECK | EV_STRIP | EV_TOP, command, args, nargs); succ = 0; /* Idea for enter/leave aliases from R'nice@TinyTIM */ if (Has_location(player) && Good_obj(Location(player))) { /* Check for a leave alias */ p = atr_pget(Location(player), A_LALIAS, &aowner, &aflags); if (p && *p) { if (matches_exit_from_list(lcbuf, p)) { free_lbuf(lcbuf); free_lbuf(p); do_leave(player, player, 0); return preserve_cmd; } } free_lbuf(p); /* Check for enter aliases */ DOLIST(exit, Contents(Location(player))) { p = atr_pget(exit, A_EALIAS, &aowner, &aflags); if (p && *p) { if (matches_exit_from_list(lcbuf, p)) { free_lbuf(lcbuf); free_lbuf(p); do_enter_internal(player, exit, 0); 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 ((!isPlayer(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. */ if (!succ && mudconf.local_masters) { if (Has_location(player)) { parent = Parent(Location(player)); while (!succ && !got_stop && Good_obj(parent) && Zone(parent)) { if (Has_contents(parent)) { succ += list_check(Contents(parent), player, AMATCH_CMD, lcbuf, preserve_cmd, 0, &got_stop); } parent = Parent(parent); } /* Here's a hack: we check the secondary "zone" parent, which * is used ONLY for this particular sort of match. */ if (mudconf.parent_zones && (Typeof(Location(player)) == TYPE_ROOM)) { parent = Next(Location(player)); while (!succ && !got_stop && Good_obj(parent) && Zone(parent)) { if (Has_contents(parent)) { succ += list_check(Contents(parent), player, AMATCH_CMD, lcbuf, preserve_cmd, 0, &got_stop); } parent = Parent(parent); } } } if (!succ) { parent = Parent(player); if ((parent != Location(player)) && (parent != Parent(Location(player)))) { while (!succ && !got_stop && Good_obj(parent) && Zone(parent)) { if (Has_contents(parent)) { succ += list_check(Contents(parent), player, AMATCH_CMD, lcbuf, preserve_cmd, 0, &got_stop); } parent = Parent(parent); } } } } /* If we didn't find anything, try in the master room */ if (!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); lcbuf = alloc_lbuf("process_commands.LOG.badcmd"); sprintf(lcbuf, " entered: '%s'", preserve_cmd); log_text(lcbuf); free_lbuf(lcbuf); ENDLOG } mudstate.debug_cmd = cmdsave; return preserve_cmd; } /* --------------------------------------------------------------------------- * powers_nametab: Extended powers table. * IMPORTANT - Keep this table in sync with the POW_xxx #defines in externs.h */ NAMETAB powers_nametab[] = { {(char *) "change_quotas", 3, CA_WIZARD, CA_WIZARD}, {(char *) "chown_anywhere", 6, CA_WIZARD, CA_GOD}, {(char *) "chown_mine", 7, CA_WIZARD, CA_WIZARD}, {(char *) "chown_others", 7, CA_WIZARD, CA_WIZARD}, {(char *) "chown_players", 7, CA_WIZARD, CA_GOD}, {(char *) "control_global", 2, CA_WIZARD, CA_WIZARD}, {(char *) "expanded_who", 3, CA_WIZARD, CA_WIZARD}, {(char *) "examine_global", 3, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "find_unfindable", 2, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "free_money", 6, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "free_quota", 6, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "grab_player", 1, CA_WIZARD, CA_WIZARD}, {(char *) "ignore_rst_flags", 1, CA_WIZARD, CA_WIZARD}, {(char *) "join_player", 1, CA_WIZARD, CA_WIZARD}, {(char *) "long_fingers", 1, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "no_boot", 4, CA_WIZARD, CA_GOD}, {(char *) "no_toad", 4, CA_WIZARD, CA_WIZARD}, {(char *) "rename_myself", 1, CA_WIZARD, CA_NO_GUEST | CA_NO_SLAVE}, {(char *) "see_admin_flags", 6, CA_WIZARD, CA_WIZARD}, {(char *) "see_all_queue", 6, CA_WIZARD, CA_WIZARD}, {(char *) "see_hidden", 5, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {(char *) "see_inviz_attrs", 5, CA_WIZARD, CA_WIZARD}, {(char *) "see_maint_flags", 5, CA_WIZARD, CA_GOD}, {(char *) "set_admin_attrs", 11, CA_WIZARD, CA_WIZARD}, {(char *) "set_admin_flags", 11, CA_WIZARD, CA_WIZARD}, {(char *) "set_maint_attrs", 11, CA_WIZARD, CA_WIZARD}, {(char *) "set_maint_flags", 11, CA_WIZARD, CA_WIZARD}, {(char *) "stat_any", 3, CA_WIZARD, CA_WIZARD}, {(char *) "steal_money", 3, CA_WIZARD, CA_WIZARD}, {(char *) "tel_anywhere", 6, CA_WIZARD, CA_WIZARD}, {(char *) "tel_unrestricted", 6, CA_WIZARD, CA_GOD}, {(char *) "unkillable", 1, CA_WIZARD, CA_WIZARD | CA_IMMORTAL}, {NULL, 0, 0, 0}}; /* --------------------------------------------------------------------------- * 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 (isPlayer(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'; notify(player, buf); free_lbuf(buf); } /* --------------------------------------------------------------------------- * list_ntab_flags: List flags field of an ntab. */ static void list_ntab_flags(player, ntab, flaglist) dbref player; NAMETAB *ntab, *flaglist; { char *buff; NAMETAB *np; buff = alloc_sbuf("list_attraccess"); for (np = ntab; np->name; np++) { if (check_access(player, np->perm)) { sprintf(buff, "%s:", np->name); listset_nametab(player, flaglist, np->flag, buff, 1); } } free_sbuf(buff); } /* --------------------------------------------------------------------------- * list_cmdaccess: List access commands. */ NAMETAB access_nametab[] = { {(char *) "god", 2, CA_GOD, CA_GOD}, {(char *) "wizard", 3, CA_WIZARD, CA_WIZARD}, {(char *) "builder", 6, CA_WIZARD, CA_BUILDER}, {(char *) "immortal", 3, CA_WIZARD, CA_IMMORTAL}, {(char *) "robot", 2, CA_WIZARD, CA_ROBOT}, {(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 *) "global_build", 8, CA_PUBLIC, CA_GBL_BUILD}, {(char *) "global_interp", 8, CA_PUBLIC, CA_GBL_INTERP}, {(char *) "disabled", 4, CA_GOD, CA_DISABLED}, {(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 *) "dark", 4, CA_GOD, CF_DARK}, {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); } /* --------------------------------------------------------------------------- * 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", 2, 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_command", 4, 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 *) "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 *) "html", 2, CA_PUBLIC, AF_HTML}, {(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 *) "wizard", 1, CA_WIZARD, AF_WIZARD}, {NULL, 0, 0, 0}}; 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 CF_HDCL(cf_modify_bits); 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; CMDENT *cmdp, *cmd2; NAMETAB *nt; int *hp; alias = strtok(str, " \t=,"); orig = strtok(NULL, " \t=,"); 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; cmd2->handler = cmdp->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, *buff; playerb = decode_flags(player, (mudconf.player_flags.word1 | TYPE_PLAYER), mudconf.player_flags.word2); roomb = decode_flags(player, (mudconf.room_flags.word1 | TYPE_ROOM), mudconf.room_flags.word2); exitb = decode_flags(player, (mudconf.exit_flags.word1 | TYPE_EXIT), mudconf.exit_flags.word2); thingb = decode_flags(player, (mudconf.thing_flags.word1 | TYPE_THING), mudconf.thing_flags.word2); robotb = decode_flags(player, (mudconf.robot_flags.word1 | TYPE_PLAYER), mudconf.robot_flags.word2); buff = alloc_lbuf("list_df_flags"); sprintf(buff, "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s", playerb, roomb, exitb, thingb, robotb); notify(player, buff); free_lbuf(buff); free_sbuf(playerb); free_sbuf(roomb); free_sbuf(exitb); free_sbuf(thingb); free_sbuf(robotb); } /* --------------------------------------------------------------------------- * 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) notify(player, tprintf("Creating a new thing costs %d %s%s.", mudconf.createmin, coin_name(mudconf.createmin), buff)); else 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) { 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 { notify(player, tprintf("Killing costs between %d and %d %s.", mudconf.killmin, mudconf.killmax, mudconf.many_coins)); notify(player, tprintf("You must spend %d %s to guarantee success.", mudconf.killguarantee, coin_name(mudconf.killguarantee))); } 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) notify(player, tprintf("Each command run from the queue costs 1/%d %s.", mudconf.machinecost, mudconf.one_coin)); if (mudconf.waitcost > 0) { notify(player, tprintf("A %d %s deposit is charged for putting a command on the queue.", mudconf.waitcost, mudconf.one_coin)); notify(player, "The deposit is refunded when the command is run or canceled."); } if (mudconf.sacfactor == 0) ltos(buff, 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); } notify(player, tprintf("The value of an object is %s.", buff)); if (mudconf.clone_copy_cost) notify(player, "The default value of cloned objects is the value of the original object."); else notify(player, tprintf("The default value of cloned objects is %d %s.", mudconf.createmin, coin_name(mudconf.createmin))); free_mbuf(buff); } /* --------------------------------------------------------------------------- * list_options: List more game options from mudconf. */ static const char *switchd[] = {"/first", "/all"}; static const char *examd[] = {"/brief", "/full"}; static const char *ed[] = {"Disabled", "Enabled"}; static const char *ud[] = {"Down", "Up"}; static void list_options(player) dbref player; { char *buff; time_t now; int i; now = time(NULL); /* -- Configuration Options related to Building -- */ if (mudconf.quotas) notify(player, "Building quotas are enforced."); else notify(player, "Building quotas are not enforced."); notify(player, tprintf("There is a limit of %d objects in the database.", mudconf.building_limit)); if (mudconf.typed_quotas) notify(player, "Quotas are managed by object type."); if (mudconf.name_spaces) notify(player, "Player names may contain spaces."); else notify(player, "Player names may not contain spaces."); /* -- Configuration Options related to Programming -- */ notify(player, tprintf("Players may have at most %d commands in the queue at one time.", mudconf.queuemax)); if (mudconf.req_cmds_flag) notify(player, "Objects are only searched for $-commands if set COMMANDS."); if (mudconf.match_mine) { if (mudconf.match_mine_pl) notify(player, "All objects search themselves for $-commands."); else notify(player, "Objects other than players search themselves for $-commands."); } else notify(player, "Objects do not search themselves for $-commands."); #ifdef NO_LAG_CHECK notify(player, "CPU usage warnings are disabled."); #else notify(player, "CPU usage warnings are enabled."); #endif /* NO_LAG_CHECK */ #ifdef FLOATING_POINTS notify(player, "MUSH arithmetic operations use floating-point numbers."); #else notify(player, "MUSH arithmetic operations use integers."); #endif /* FLOATING_POINTS */ if (mudconf.trace_topdown) { notify(player, "Trace output is presented top-down (whole expression first, then sub-exprs)."); notify(player, tprintf("Only %d lines of trace output are displayed.", mudconf.trace_limit)); } else { notify(player, "Trace output is presented bottom-up (subexpressions first)."); } #ifdef PUEBLO_SUPPORT notify(player, "The Pueblo client HTML extensions are supported."); #endif /* PUEBLO_SUPPORT */ if (mudconf.fascist_tport) notify(player, "You may only @teleport out of locations that are JUMP_OK or that you control."); if (mudconf.parent_control) notify(player, "The 'ControlLock' lock may be inherited from parents."); /* -- Configuration Options related to Speaking -- */ if (mudconf.pemit_players) notify(player, "The '@pemit' command may be used to emit to faraway players."); else notify(player, "The '@pemit' command cannot be used to emit to faraway players."); if (mudconf.pemit_any) notify(player, "The '@pemit' command may be used to emit to any remote object."); else notify(player, "The '@pemit' command may not be used to emit to any remote object."); #ifdef PARANOID_EMIT notify(player, "The '@emit' commands use strict permissions checking."); #endif /* PARANOID_EMIT */ if (mudconf.player_listen) notify(player, "The @Listen/@Ahear attribute set works on player objects."); else notify(player, "The @Listen/@Ahear attribute set does not work on player objects."); #ifdef COMMA_IN_SAY notify(player, "There is a comma in the output of the 'say' command."); #endif /* COMMA_IN_SAY */ if (!mudconf.quiet_whisper) notify(player, "The 'whisper' command lets others in the room with you know you whispered."); if (!mudconf.robot_speak) notify(player, "Robots are not allowed to speak in public areas."); /* -- Default Command Behaviors -- */ notify(player, tprintf("The default switch for the '@switch' command is %s.", switchd[mudconf.switch_df_all])); notify(player, tprintf("The default switch for the 'examine' command is %s.", examd[mudconf.exam_public])); /* -- Configuration Options related to Looking and other Information */ if (mudconf.ex_flags) notify(player, "The 'examine' command lists the flag names for the object's flags."); if (mudconf.pub_flags) notify(player, "The 'flags()' function will return the flags of any object."); if (mudconf.read_rem_desc) notify(player, "The 'get()' function will return the description of faraway objects,"); if (mudconf.read_rem_name) notify(player, "The 'name()' function will return the name of faraway objects."); if (!mudconf.quiet_look) notify(player, "The 'look' command shows visible attributes in addition to the description."); if (mudconf.see_own_dark) notify(player, "The 'look' command lists DARK objects owned by you."); if (!mudconf.dark_sleepers) notify(player, "The 'look' command shows disconnected players."); if (mudconf.terse_look) notify(player, "The 'look' command obeys the TERSE flag."); if (!mudconf.terse_contents) notify(player, "The TERSE flag suppresses listing the contents of a location."); if (!mudconf.terse_exits) notify(player, "The TERSE flag suppresses listing obvious exits in a location."); if (!mudconf.terse_movemsg) notify(player, "The TERSE flag suppresses enter/leave/succ/drop messages generated by moving."); if (mudconf.sweep_dark) notify(player, "Players may @sweep dark locations."); /* -- End of Mortal-Visible Configuration Options -- */ if (!Wizard(player)) return; buff = alloc_mbuf("list_options"); notify(player, tprintf("%d commands are run from the queue when there is no net activity.", mudconf.queue_chunk)); notify(player, tprintf("%d commands are run from the queue when there is net activity.", mudconf.active_q_chunk)); if (mudconf.idle_wiz_dark) notify(player, "Wizards idle for longer than the default timeout are automatically set DARK."); if (mudconf.safe_unowned) notify(player, "Objects not owned by you are automatically considered SAFE."); if (mudconf.paranoid_alloc) notify(player, "The buffer pools are checked for consistency on each allocate or free."); notify(player, tprintf("The %s cache is %d entries wide by %d entries deep.", CACHING, mudconf.cache_width, mudconf.cache_depth)); if (mudconf.cache_names) notify(player, "A separate object name cache is used."); if (mudconf.cache_steal_dirty) notify(player, "Old modified cache entries may be reused when allocating a new entry."); if (mudconf.fork_dump) { notify(player, "Database dumps are performed by a fork()ed process."); if (mudconf.fork_vfork) notify(player, "The 'vfork()' call is used to perform the fork."); } if (mudconf.use_global_aconn) notify(player, "Global aconnects and disconnects are executed by Master Room objects."); if (mudconf.local_masters) { notify(player, "Objects set ZONE are treated as local master rooms."); if (mudconf.parent_zones) notify(player, "Rooms can have a secondary parent for ZONE command checks."); } if (mudconf.max_players >= 0) notify(player, tprintf("There may be at most %d players logged in at once.", mudconf.max_players)); notify(player, tprintf("Players are given %d %s each day they connect.", mudconf.paycheck, mudconf.many_coins)); notify(player, tprintf("Earning money is difficult if you have more than %d %s.", mudconf.paylimit, mudconf.many_coins)); if (mudconf.payfind > 0) notify(player, tprintf("Players have a 1 in %d chance of finding a %s each time they move.", mudconf.payfind, mudconf.one_coin)); notify(player, tprintf("The head of the object freelist is #%d.", mudstate.freelist)); switch (mudconf.sig_action) { case SA_DFLT: notify(player, "Fatal signals are not caught."); break; case SA_RESIG: notify(player, "Fatal signals cause a panic dump and are resignalled from the signal handler."); break; case SA_RETRY: notify(player, "Fatal signals cause a panic dump and control returns to the point of signal."); break; } sprintf(buff, "Intervals: Dump...%d Clean...%d Idlecheck...%d Rwho...%d", mudconf.dump_interval, mudconf.check_interval, mudconf.idle_interval, mudconf.rwho_interval); notify(player, buff); sprintf(buff, "Timers: Dump...%d Clean...%d Idlecheck...%d Rwho...%d", (int)(mudstate.dump_counter - now), (int)(mudstate.check_counter - now), (int)(mudstate.idle_counter - now), (int)(mudstate.rwho_counter - now)); notify(player, buff); sprintf(buff, "Timeouts: Idle...%d Connect...%d Tries...%d Lag...%d", mudconf.idle_timeout, mudconf.conn_timeout, mudconf.retry_limit, mudconf.max_cmdsecs); notify(player, buff); sprintf(buff, "Scheduling: Timeslice...%d Max_Quota...%d Increment...%d", mudconf.timeslice, mudconf.cmd_quota_max, mudconf.cmd_quota_incr); notify(player, buff); sprintf(buff, "Compression: Spaces...%s", ed[mudconf.space_compress]); notify(player, buff); sprintf(buff, "Guests: %d Guests active: ", mudconf.num_guests); for (i = 0; i < mudconf.num_guests; i++) sprintf(buff + strlen(buff), " #%d", mudconf.guest_chars[i]); notify(player, buff); sprintf(buff, "MasterRoom...#%d StartRoom...#%d StartHome...#%d DefaultHome...#%d", mudconf.master_room, mudconf.start_room, mudconf.start_home, mudconf.default_home); notify(player, buff); sprintf(buff, "New characters: %s...%d Quota...%d Rooms...%d Exits...%d Things...%d Players...%d", mudconf.many_coins, mudconf.paystart, mudconf.start_quota, mudconf.start_room_quota, mudconf.start_exit_quota, mudconf.start_thing_quota, mudconf.start_player_quota); notify(player, buff); sprintf(buff, "Limits: Output...%d Recursion...%d Invocation...%d Parents...%d", mudconf.output_limit, mudconf.func_nest_lim, mudconf.func_invk_lim, mudconf.parent_nest_lim); notify(player, buff); sprintf(buff, "Rwho: Host...%s Port...%d Connection...%s Transmit...%s", mudconf.rwho_host, mudconf.rwho_info_port, ud[mudstate.rwho_on], ed[mudconf.rwho_transmit]); notify(player, buff); free_mbuf(buff); } /* --------------------------------------------------------------------------- * list_vattrs: List user-defined attributes */ static void list_vattrs(player) dbref player; { VATTR *va; int na; char *buff; buff = alloc_lbuf("list_vattrs"); 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); } } 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); 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); notify(player, buff); free_mbuf(buff); } static void list_hashstats(player) dbref player; { 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, "Flags", &mudstate.flags_htab); list_hashstat(player, "Attr names", &mudstate.attr_name_htab); list_nhashstat(player, "Attr numbers", &mudstate.attr_num_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_hashstat(player, "News topics", &mudstate.news_htab); list_hashstat(player, "Help topics", &mudstate.help_htab); list_hashstat(player, "Wizhelp topics", &mudstate.wizhelp_htab); list_vhashstats(player); } /* 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 */ #ifdef IN_MEM_COMPRESSION extern int strings_compressed; /* total number of strings compressed */ extern int strings_decompressed;/* total number of strings decompressed */ extern int chars_in; /* Total number of characters compressed */ extern int symbols_out; /* Total number of symbols emitted */ #endif /* --------------------------------------------------------------------------- * list_db_stats: Get useful info from the DB layer about hash stats, etc. */ static void list_db_stats(player) dbref player; { notify(player, tprintf("DB Cache Stats Writes Reads (over %d seconds)", time(0) - cs_ltime)); notify(player, tprintf("Calls %12d%12d", cs_writes, cs_reads)); notify(player, tprintf("Cache Hits %12d%12d (%d in active cache)", cs_whits, cs_rhits, cs_ahits)); notify(player, tprintf("I/O %12d%12d", cs_dbwrites, cs_dbreads)); notify(player, tprintf("\nDeletes %12d", cs_dels)); notify(player, tprintf("Checks %12d", cs_checks)); notify(player, tprintf("Resets %12d", cs_resets)); notify(player, tprintf("Syncs %12d", cs_syncs)); notify(player, tprintf("Cache Size %12d", cs_objects)); #ifdef IN_MEM_COMPRESSION notify(player, "Compression Statistics:"); notify(player, tprintf("strings compressed %d", strings_compressed)); notify(player, tprintf("strings decompressed %d", strings_decompressed)); notify(player, tprintf("compression ratio %d:%d", chars_in, symbols_out + (symbols_out >> 1))); #endif } /* --------------------------------------------------------------------------- * 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; #ifdef HAVE_GETRUSAGE struct rusage usage; #else #ifdef HAVE_GET_PROCESS_STATS timeval_t *tv; struct process_stats *pst, *cpst; #endif #endif pid = getpid(); #ifdef HAVE_GETPAGESIZE psize = getpagesize(); #else psize = sysconf(NM_BLOODY_PAGE_SYMBOL); #endif /* Go display everything */ notify(player, tprintf("Process ID: %10d %10d bytes per page", pid, psize)); #ifdef HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &usage); notify(player, tprintf("Time used: %10d user %10d sys", usage.ru_utime.tv_sec, usage.ru_stime.tv_sec)); notify(player, tprintf("Integral mem:%10d shared %10d private%10d stack", usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss)); notify(player, tprintf("Max res mem: %10d pages %10d bytes", usage.ru_maxrss, (usage.ru_maxrss * psize))); notify(player, tprintf("Page faults: %10d hard %10d soft %10d swapouts", usage.ru_majflt, usage.ru_minflt, usage.ru_nswap)); notify(player, tprintf("Disk I/O: %10d reads %10d writes", usage.ru_inblock, usage.ru_oublock)); notify(player, tprintf("Network I/O: %10d in %10d out", usage.ru_msgrcv, usage.ru_msgsnd)); notify(player, tprintf("Context swi: %10d vol %10d forced %10d sigs", usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals)); #else #ifdef HAVE_GET_PROCESS_STATS /* Sequent: Dynix/PTX */ pst = (struct process_stats *) XMALLOC(sizeof(struct process_stats), "list_process_pst"); cpst = (struct process_stats *) XMALLOC(sizeof(struct process_stats), "list_process_cpst"); tv = (struct timeval *) XMALLOC(sizeof(struct timeval), "list_process_tv"); if (get_process_stats(tv, PS_SELF, pst, cpst) < 0) { free(tv); free(pst); free(cpst); return; } free(tv); free(cpst); notify(player, tprintf("Time used: %10d user %10d sys", pst->ps_utime.tv_sec, pst->ps_stime.tv_sec)); notify(player, tprintf("Max res mem: %10d pages %10d bytes", pst->ps_maxrss, (pst->ps_maxrss * psize))); notify(player, tprintf("Page faults: %10d hard %10d soft %10d swapouts", pst->ps_pagein, pst->ps_reclaim, pst->ps_swap)); notify(player, tprintf("Disk I/O: %10d reads %10d writes", pst->ps_bread, pst->ps_bwrite)); notify(player, tprintf("Context swi: %10d vol %10d forced %10d sigs", pst->ps_volcsw, pst->ps_involcsw, pst->ps_signal)); free(pst); #endif /* HAVE_GET_PROCESS_STATS */ #endif /* HAVE_GETRUSAGE */ } /* --------------------------------------------------------------------------- * 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 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 *) "commands", 3, CA_PUBLIC, LIST_COMMANDS}, {(char *) "config_permissions", 3, CA_GOD, LIST_CONF_PERMS}, {(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 *) "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 *) "user_attributes", 1, CA_WIZARD, LIST_VATTRS}, {NULL, 0, 0, 0}}; 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_POWERS: list_ntab_flags(player, powers_nametab, access_nametab); 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; default: display_nametab(player, list_names, (char *) "Unknown option. Use one of:", 1); } }