/*! \file command.cpp * \brief Command parser and support routines. * * $Id$ * * The functions here crack command lists into commands, decode switches, and * match commands to built-in and softcoded commands. This is one of the * three parsers in the server. The other two parsers are for functions * (see eval.cpp) and locks (boolexp.cpp). */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "externs.h" #include "attrs.h" #include "command.h" #include "comsys.h" #include "functions.h" #include "mguests.h" #include "powers.h" #include "vattr.h" #include "pcre.h" // Switch tables for the various commands. // static NAMETAB attrib_sw[] = { {T("access"), 1, CA_GOD, ATTRIB_ACCESS}, {T("delete"), 1, CA_GOD, ATTRIB_DELETE}, {T("rename"), 1, CA_GOD, ATTRIB_RENAME}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB boot_sw[] = { {T("port"), 1, CA_WIZARD, BOOT_PORT|SW_MULTIPLE}, {T("quiet"), 1, CA_WIZARD, BOOT_QUIET|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB cboot_sw[] = { {T("quiet"), 1, CA_PUBLIC, CBOOT_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB comtitle_sw[] = { {T("off"), 2, CA_PUBLIC, COMTITLE_OFF}, {T("on"), 2, CA_PUBLIC, COMTITLE_ON}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB cemit_sw[] = { {T("noheader"), 1, CA_PUBLIC, CEMIT_NOHEADER}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB chown_sw[] = { {T("nostrip"), 1, CA_PUBLIC, CHOWN_NOSTRIP}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB clone_sw[] = { {T("cost"), 1, CA_PUBLIC, CLONE_SET_COST}, {T("inherit"), 3, CA_PUBLIC, CLONE_INHERIT|SW_MULTIPLE}, {T("inventory"), 3, CA_PUBLIC, CLONE_INVENTORY}, {T("location"), 1, CA_PUBLIC, CLONE_LOCATION}, {T("nostrip"), 2, CA_WIZARD, CLONE_NOSTRIP|SW_MULTIPLE}, {T("parent"), 2, CA_PUBLIC, CLONE_FROM_PARENT|SW_MULTIPLE}, {T("preserve"), 2, CA_WIZARD, CLONE_PRESERVE|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB clist_sw[] = { {T("full"), 0, CA_PUBLIC, CLIST_FULL}, {T("headers"), 0, CA_PUBLIC, CLIST_HEADERS}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB cset_sw[] = { {T("anon"), 1, CA_PUBLIC, CSET_SPOOF}, {T("header"), 1, CA_PUBLIC, CSET_HEADER}, {T("list"), 2, CA_PUBLIC, CSET_LIST}, {T("log") , 3, CA_PUBLIC, CSET_LOG}, {T("loud"), 3, CA_PUBLIC, CSET_LOUD}, {T("mute"), 1, CA_PUBLIC, CSET_QUIET}, {T("nospoof"), 1, CA_PUBLIC, CSET_NOSPOOF}, {T("object"), 1, CA_PUBLIC, CSET_OBJECT}, {T("private"), 2, CA_PUBLIC, CSET_PRIVATE}, {T("public"), 2, CA_PUBLIC, CSET_PUBLIC}, {T("quiet"), 1, CA_PUBLIC, CSET_QUIET}, {T("spoof"), 1, CA_PUBLIC, CSET_SPOOF}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB dbck_sw[] = { {T("full"), 1, CA_WIZARD, DBCK_FULL}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB decomp_sw[] = { {T("dbref"), 1, CA_PUBLIC, DECOMP_DBREF}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB destroy_sw[] = { {T("instant"), 4, CA_PUBLIC, DEST_INSTANT|SW_MULTIPLE}, {T("override"), 8, CA_PUBLIC, DEST_OVERRIDE|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB dig_sw[] = { {T("teleport"), 1, CA_PUBLIC, DIG_TELEPORT}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB doing_sw[] = { {T("header"), 1, CA_PUBLIC, DOING_HEADER}, {T("message"), 1, CA_PUBLIC, DOING_MESSAGE}, {T("poll"), 1, CA_PUBLIC, DOING_POLL}, {T("quiet"), 1, CA_PUBLIC, DOING_QUIET|SW_MULTIPLE}, {T("unique"), 1, CA_PUBLIC, DOING_UNIQUE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB dolist_sw[] = { {T("delimit"), 1, CA_PUBLIC, DOLIST_DELIMIT}, {T("notify"), 1, CA_PUBLIC, DOLIST_NOTIFY|SW_MULTIPLE}, {T("space"), 1, CA_PUBLIC, DOLIST_SPACE}, {(UTF8 *) NULL, 0, 0, 0} }; #ifdef QUERY_SLAVE static NAMETAB query_sw[] = { {T("sql"), 1, CA_PUBLIC, QUERY_SQL}, {(UTF8 *) NULL, 0, 0, 0} }; #endif // QUERY_SLAVE static NAMETAB drop_sw[] = { {T("quiet"), 1, CA_PUBLIC, DROP_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB dump_sw[] = { {T("flatfile"), 1, CA_WIZARD, DUMP_FLATFILE|SW_MULTIPLE}, {T("structure"), 1, CA_WIZARD, DUMP_STRUCT|SW_MULTIPLE}, {T("text"), 1, CA_WIZARD, DUMP_TEXT|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB emit_sw[] = { {T("here"), 2, CA_PUBLIC, SAY_HERE|SW_MULTIPLE}, {T("html"), 2, CA_PUBLIC, SAY_HTML|SW_MULTIPLE}, {T("room"), 1, CA_PUBLIC, SAY_ROOM|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB enter_sw[] = { {T("quiet"), 1, CA_PUBLIC, MOVE_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB examine_sw[] = { {T("brief"), 1, CA_PUBLIC, EXAM_BRIEF}, {T("debug"), 1, CA_WIZARD, EXAM_DEBUG}, {T("full"), 1, CA_PUBLIC, EXAM_LONG}, {T("parent"), 1, CA_PUBLIC, EXAM_PARENT}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB femit_sw[] = { {T("here"), 1, CA_PUBLIC, PEMIT_HERE|SW_MULTIPLE}, {T("room"), 1, CA_PUBLIC, PEMIT_ROOM|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB fixdb_sw[] = { {T("contents"), 1, CA_GOD, FIXDB_CON}, {T("exits"), 1, CA_GOD, FIXDB_EXITS}, {T("location"), 1, CA_GOD, FIXDB_LOC}, {T("next"), 1, CA_GOD, FIXDB_NEXT}, {T("owner"), 1, CA_GOD, FIXDB_OWNER}, {T("pennies"), 1, CA_GOD, FIXDB_PENNIES}, {T("rename"), 1, CA_GOD, FIXDB_NAME}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB flag_sw[] = { {T("remove"), 1, CA_GOD, FLAG_REMOVE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB fpose_sw[] = { {T("default"), 1, CA_PUBLIC, 0}, {T("nospace"), 1, CA_PUBLIC, SAY_NOSPACE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB function_sw[] = { {T("delete"), 1, CA_WIZARD, FN_DELETE}, {T("list"), 1, CA_WIZARD, FN_LIST}, {T("preserve"), 3, CA_WIZARD, FN_PRES|SW_MULTIPLE}, {T("privileged"), 3, CA_WIZARD, FN_PRIV|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB get_sw[] = { {T("quiet"), 1, CA_PUBLIC, GET_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB give_sw[] = { {T("quiet"), 1, CA_WIZARD, GIVE_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB goto_sw[] = { {T("quiet"), 1, CA_PUBLIC, MOVE_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB halt_sw[] = { {T("all"), 1, CA_PUBLIC, HALT_ALL}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB hook_sw[] = { {T("after"), 3, CA_GOD, HOOK_AFTER}, {T("before"), 3, CA_GOD, HOOK_BEFORE}, {T("clear"), 3, CA_GOD, HOOK_CLEAR|SW_MULTIPLE}, {T("fail"), 1, CA_GOD, HOOK_AFAIL}, {T("ignore"), 3, CA_GOD, HOOK_IGNORE}, {T("igswitch"), 3, CA_GOD, HOOK_IGSWITCH}, {T("list"), 3, CA_GOD, HOOK_LIST}, {T("permit"), 3, CA_GOD, HOOK_PERMIT}, {(UTF8 *)NULL, 0, 0, 0} }; static NAMETAB icmd_sw[] = { {T("check"), 2, CA_GOD, ICMD_CHECK}, {T("clear"), 2, CA_GOD, ICMD_CLEAR}, {T("croom"), 2, CA_GOD, ICMD_CROOM}, {T("disable"), 1, CA_GOD, ICMD_DISABLE}, {T("droom"), 2, CA_GOD, ICMD_DROOM}, {T("ignore"), 1, CA_GOD, ICMD_IGNORE}, {T("iroom"), 2, CA_GOD, ICMD_IROOM}, {T("lroom"), 2, CA_GOD, ICMD_LROOM}, {T("lallroom"), 2, CA_GOD, ICMD_LALLROOM}, {T("off"), 2, CA_GOD, ICMD_OFF}, {T("on"), 2, CA_GOD, ICMD_ON}, {(UTF8 *)NULL, 0, 0, 0} }; static NAMETAB leave_sw[] = { {T("quiet"), 1, CA_PUBLIC, MOVE_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB listmotd_sw[] = { {T("brief"), 1, CA_WIZARD, MOTD_BRIEF}, {(UTF8 *) NULL, 0, 0, 0} }; NAMETAB lock_sw[] = { {T("defaultlock"), 1, CA_PUBLIC, A_LOCK}, {T("droplock"), 1, CA_PUBLIC, A_LDROP}, {T("enterlock"), 1, CA_PUBLIC, A_LENTER}, {T("getfromlock"), 1, CA_PUBLIC, A_LGET}, {T("givelock"), 1, CA_PUBLIC, A_LGIVE}, {T("leavelock"), 2, CA_PUBLIC, A_LLEAVE}, {T("linklock"), 2, CA_PUBLIC, A_LLINK}, {T("maillock"), 1, CA_PUBLIC, A_LMAIL}, {T("openlock"), 1, CA_PUBLIC, A_LOPEN}, {T("pagelock"), 3, CA_PUBLIC, A_LPAGE}, {T("parentlock"), 3, CA_PUBLIC, A_LPARENT}, {T("receivelock"), 1, CA_PUBLIC, A_LRECEIVE}, {T("speechlock"), 1, CA_PUBLIC, A_LSPEECH}, {T("teloutlock"), 2, CA_PUBLIC, A_LTELOUT}, {T("tportlock"), 2, CA_PUBLIC, A_LTPORT}, {T("uselock"), 1, CA_PUBLIC, A_LUSE}, {T("userlock"), 4, CA_PUBLIC, A_LUSER}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB look_sw[] = { {T("outside"), 1, CA_PUBLIC, LOOK_OUTSIDE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB mail_sw[] = { {T("abort"), 2, CA_PUBLIC, MAIL_ABORT}, {T("alias"), 4, CA_PUBLIC, MAIL_ALIAS}, {T("alist"), 4, CA_PUBLIC, MAIL_ALIST}, {T("bcc"), 1, CA_PUBLIC, MAIL_BCC}, {T("cc"), 2, CA_PUBLIC, MAIL_CC}, {T("clear"), 2, CA_PUBLIC, MAIL_CLEAR}, {T("debug"), 2, CA_PUBLIC, MAIL_DEBUG}, {T("dstats"), 2, CA_PUBLIC, MAIL_DSTATS}, {T("edit"), 1, CA_PUBLIC, MAIL_EDIT}, {T("file"), 2, CA_PUBLIC, MAIL_FILE}, {T("folder"), 3, CA_PUBLIC, MAIL_FOLDER}, {T("forward"), 3, CA_PUBLIC, MAIL_FORWARD}, {T("fstats"), 2, CA_PUBLIC, MAIL_FSTATS}, {T("fwd"), 2, CA_PUBLIC, MAIL_FORWARD}, {T("list"), 1, CA_PUBLIC, MAIL_LIST}, {T("nuke"), 1, CA_PUBLIC, MAIL_NUKE}, {T("proof"), 2, CA_PUBLIC, MAIL_PROOF}, {T("purge"), 2, CA_PUBLIC, MAIL_PURGE}, {T("quick"), 3, CA_PUBLIC, MAIL_QUICK}, {T("quote"), 3, CA_PUBLIC, MAIL_QUOTE|SW_MULTIPLE}, {T("read"), 3, CA_PUBLIC, MAIL_READ}, {T("reply"), 3, CA_PUBLIC, MAIL_REPLY}, {T("replyall"), 6, CA_PUBLIC, MAIL_REPLYALL}, {T("retract"), 3, CA_PUBLIC, MAIL_RETRACT}, {T("review"), 3, CA_PUBLIC, MAIL_REVIEW}, {T("safe"), 2, CA_PUBLIC, MAIL_SAFE}, {T("send"), 2, CA_PUBLIC, MAIL_SEND}, {T("stats"), 2, CA_PUBLIC, MAIL_STATS}, {T("tag"), 1, CA_PUBLIC, MAIL_TAG}, {T("unclear"), 3, CA_PUBLIC, MAIL_UNCLEAR}, {T("untag"), 3, CA_PUBLIC, MAIL_UNTAG}, {T("urgent"), 2, CA_PUBLIC, MAIL_URGENT}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB malias_sw[] = { {T("add"), 1, CA_PUBLIC, MALIAS_ADD}, {T("chown"), 1, CA_PUBLIC, MALIAS_CHOWN}, {T("desc"), 1, CA_PUBLIC, MALIAS_DESC}, {T("delete"), 1, CA_PUBLIC, MALIAS_DELETE}, {T("list"), 1, CA_PUBLIC, MALIAS_LIST}, {T("remove"), 1, CA_PUBLIC, MALIAS_REMOVE}, {T("rename"), 1, CA_PUBLIC, MALIAS_RENAME}, {T("status"), 1, CA_PUBLIC, MALIAS_STATUS}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB mark_sw[] = { {T("clear"), 1, CA_PUBLIC, MARK_CLEAR}, {T("set"), 1, CA_PUBLIC, MARK_SET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB markall_sw[] = { {T("clear"), 1, CA_PUBLIC, MARK_CLEAR}, {T("set"), 1, CA_PUBLIC, MARK_SET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB motd_sw[] = { {T("brief"), 1, CA_WIZARD, MOTD_BRIEF|SW_MULTIPLE}, {T("connect"), 1, CA_WIZARD, MOTD_ALL}, {T("down"), 1, CA_WIZARD, MOTD_DOWN}, {T("full"), 1, CA_WIZARD, MOTD_FULL}, {T("list"), 1, CA_PUBLIC, MOTD_LIST}, {T("wizard"), 1, CA_WIZARD, MOTD_WIZ}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB notify_sw[] = { {T("all"), 1, CA_PUBLIC, NFY_NFYALL}, {T("first"), 1, CA_PUBLIC, NFY_NFY}, {T("quiet"), 1, CA_PUBLIC, NFY_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB open_sw[] = { {T("inventory"), 1, CA_PUBLIC, OPEN_INVENTORY}, {T("location"), 1, CA_PUBLIC, OPEN_LOCATION}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB page_sw[] = { {T("noeval"), 1, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB pemit_sw[] = { {T("contents"), 1, CA_PUBLIC, PEMIT_CONTENTS|SW_MULTIPLE}, {T("html"), 1, CA_PUBLIC, PEMIT_HTML|SW_MULTIPLE}, {T("list"), 1, CA_PUBLIC, PEMIT_LIST|SW_MULTIPLE}, {T("noeval"), 1, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, {T("object"), 1, CA_PUBLIC, 0}, {T("silent"), 1, CA_PUBLIC, 0}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB pose_sw[] = { {T("default"), 1, CA_PUBLIC, 0}, {T("noeval"), 3, CA_PUBLIC, SW_NOEVAL|SW_MULTIPLE}, {T("nospace"), 3, CA_PUBLIC, SAY_NOSPACE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB ps_sw[] = { {T("all"), 1, CA_PUBLIC, PS_ALL|SW_MULTIPLE}, {T("brief"), 1, CA_PUBLIC, PS_BRIEF}, {T("long"), 1, CA_PUBLIC, PS_LONG}, {T("summary"), 1, CA_PUBLIC, PS_SUMM}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB quota_sw[] = { {T("all"), 1, CA_GOD, QUOTA_ALL|SW_MULTIPLE}, {T("fix"), 1, CA_WIZARD, QUOTA_FIX}, {T("remaining"), 1, CA_WIZARD, QUOTA_REM|SW_MULTIPLE}, {T("set"), 1, CA_WIZARD, QUOTA_SET}, {T("total"), 1, CA_WIZARD, QUOTA_TOT|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB say_sw[] = { {T("noeval"), 1, CA_PUBLIC, SAY_NOEVAL|SW_NOEVAL|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB set_sw[] = { {T("quiet"), 1, CA_PUBLIC, SET_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB stats_sw[] = { {T("all"), 1, CA_PUBLIC, STAT_ALL}, {T("me"), 1, CA_PUBLIC, STAT_ME}, {T("player"), 1, CA_PUBLIC, STAT_PLAYER}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB sweep_sw[] = { {T("commands"), 3, CA_PUBLIC, SWEEP_COMMANDS|SW_MULTIPLE}, {T("connected"), 3, CA_PUBLIC, SWEEP_CONNECT|SW_MULTIPLE}, {T("exits"), 1, CA_PUBLIC, SWEEP_EXITS|SW_MULTIPLE}, {T("here"), 1, CA_PUBLIC, SWEEP_HERE|SW_MULTIPLE}, {T("inventory"), 1, CA_PUBLIC, SWEEP_ME|SW_MULTIPLE}, {T("listeners"), 1, CA_PUBLIC, SWEEP_LISTEN|SW_MULTIPLE}, {T("players"), 1, CA_PUBLIC, SWEEP_PLAYER|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB switch_sw[] = { {T("all"), 1, CA_PUBLIC, SWITCH_ANY}, {T("default"), 1, CA_PUBLIC, SWITCH_DEFAULT}, {T("first"), 1, CA_PUBLIC, SWITCH_ONE}, {T("notify"), 1, CA_PUBLIC, SWITCH_NOTIFY|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB teleport_sw[] = { {T("list"), 1, CA_PUBLIC, TELEPORT_LIST|SW_MULTIPLE}, {T("loud"), 1, CA_PUBLIC, TELEPORT_DEFAULT}, {T("quiet"), 1, CA_PUBLIC, TELEPORT_QUIET}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB timecheck_sw[] = { {T("log"), 1, CA_WIZARD, TIMECHK_LOG | SW_MULTIPLE}, {T("reset"), 1, CA_WIZARD, TIMECHK_RESET | SW_MULTIPLE}, {T("screen"), 1, CA_WIZARD, TIMECHK_SCREEN | SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB toad_sw[] = { {T("no_chown"), 1, CA_WIZARD, TOAD_NO_CHOWN|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB trig_sw[] = { {T("quiet"), 1, CA_PUBLIC, TRIG_QUIET}, {T("notify"), 1, CA_PUBLIC, TRIG_NOTIFY|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB wait_sw[] = { {T("until"), 1, CA_PUBLIC, WAIT_UNTIL}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB verb_sw[] = { {T("no_name"), 3, CA_PUBLIC, VERB_NONAME}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB wall_sw[] = { {T("admin"), 1, CA_ADMIN, SHOUT_ADMIN|SW_MULTIPLE}, {T("emit"), 1, CA_ANNOUNCE, SHOUT_EMIT|SW_MULTIPLE}, {T("no_prefix"), 1, CA_ANNOUNCE, SHOUT_NOTAG|SW_MULTIPLE}, {T("pose"), 1, CA_ANNOUNCE, SHOUT_POSE|SW_MULTIPLE}, {T("wizard"), 1, CA_ANNOUNCE, SHOUT_WIZARD|SW_MULTIPLE}, {(UTF8 *) NULL, 0, 0, 0} }; static NAMETAB warp_sw[] = { {T("check"), 1, CA_WIZARD, TWARP_CLEAN|SW_MULTIPLE}, {T("dump"), 1, CA_WIZARD, TWARP_DUMP|SW_MULTIPLE}, {T("events"), 1, CA_WIZARD, TWARP_EVENTS|SW_MULTIPLE}, {T("idle"), 1, CA_WIZARD, TWARP_IDLE|SW_MULTIPLE}, {T("queue"), 1, CA_WIZARD, TWARP_QUEUE|SW_MULTIPLE}, {(UTF8 *) 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 */ static CMDENT_NO_ARG command_table_no_arg[] = { {T("@@"), NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_comment}, {T("@backup"), NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, do_backup}, {T("@dbck"), dbck_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_dbck}, {T("@dbclean"), NULL, CA_GOD, 0, CS_NO_ARGS, 0, do_dbclean}, {T("@dump"), dump_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_dump}, {T("@mark_all"), markall_sw, CA_WIZARD, MARK_SET, CS_NO_ARGS, 0, do_markall}, {T("@readcache"), NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, do_readcache}, {T("@restart"), NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_NO_ARGS, 0, do_restart}, #ifndef WIN32 {T("@startslave"), NULL, CA_WIZARD, 0, CS_NO_ARGS, 0, boot_slave}, #endif // !WIN32 {T("@timecheck"), timecheck_sw, CA_WIZARD, 0, CS_NO_ARGS, 0, do_timecheck}, {T("clearcom"), NULL, CA_NO_SLAVE, 0, CS_NO_ARGS, 0, do_clearcom}, {T("info"), NULL, CA_PUBLIC, CMD_INFO, CS_NO_ARGS, 0, logged_out0}, {T("inventory"), NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_inventory}, {T("leave"), leave_sw, CA_LOCATION, 0, CS_NO_ARGS, 0, do_leave}, {T("logout"), NULL, CA_PUBLIC, CMD_LOGOUT, CS_NO_ARGS, 0, logged_out0}, {T("quit"), NULL, CA_PUBLIC, CMD_QUIT, CS_NO_ARGS, 0, logged_out0}, {T("report"), NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_report}, {T("score"), NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_score}, {T("version"), NULL, CA_PUBLIC, 0, CS_NO_ARGS, 0, do_version}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG command_table_one_arg[] = { {T("@boot"), boot_sw, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_boot}, {T("@ccreate"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_ONE_ARG, 0, do_createchannel}, {T("@cdestroy"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_ONE_ARG, 0, do_destroychannel}, {T("@clist"), clist_sw, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_chanlist}, {T("@cut"), NULL, CA_WIZARD|CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_cut}, {T("@cwho"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_channelwho}, {T("@destroy"), destroy_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, DEST_ONE, CS_ONE_ARG|CS_INTERP, 0, do_destroy}, {T("@disable"), NULL, CA_WIZARD, GLOB_DISABLE, CS_ONE_ARG, 0, do_global}, {T("@doing"), doing_sw, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_doing}, {T("@emit"), emit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_INTERP, 0, do_say}, {T("@enable"), NULL, CA_WIZARD, GLOB_ENABLE, CS_ONE_ARG, 0, do_global}, {T("@entrances"), NULL, CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_entrances}, {T("@eval"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_eval}, {T("@find"), NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_find}, {T("@halt"), halt_sw, CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_halt}, {T("@hook"), hook_sw, CA_GOD, 0, CS_ONE_ARG|CS_INTERP, 0, do_hook}, {T("@kick"), NULL, CA_WIZARD, QUEUE_KICK, CS_ONE_ARG|CS_INTERP, 0, do_queue}, {T("@last"), NULL, CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_last}, {T("@list"), NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_list}, {T("@list_file"), NULL, CA_WIZARD, 0, CS_ONE_ARG|CS_INTERP, 0, do_list_file}, {T("@listcommands"), NULL, CA_GOD, 0, CS_ONE_ARG, 0, do_listcommands}, {T("@listmotd"), listmotd_sw,CA_PUBLIC, MOTD_LIST, CS_ONE_ARG, 0, do_motd}, {T("@mark"), mark_sw, CA_WIZARD, SRCH_MARK, CS_ONE_ARG|CS_NOINTERP, 0, do_search}, {T("@motd"), motd_sw, CA_WIZARD, 0, CS_ONE_ARG, 0, do_motd}, {T("@nemit"), emit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_say}, {T("@poor"), NULL, CA_GOD, 0, CS_ONE_ARG|CS_INTERP, 0, do_poor}, {T("@ps"), ps_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_ps}, {T("@quitprogram"), NULL, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_quitprog}, {T("@search"), NULL, CA_PUBLIC, SRCH_SEARCH, CS_ONE_ARG|CS_NOINTERP, 0, do_search}, {T("@shutdown"), NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_shutdown}, {T("@stats"), stats_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_stats}, {T("@sweep"), sweep_sw, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_sweep}, {T("@timewarp"), warp_sw, CA_WIZARD, 0, CS_ONE_ARG|CS_INTERP, 0, do_timewarp}, {T("@unlink"), NULL, CA_NO_SLAVE|CA_GBL_BUILD, 0, CS_ONE_ARG|CS_INTERP, 0, do_unlink}, {T("@unlock"), lock_sw, CA_NO_SLAVE, 0, CS_ONE_ARG|CS_INTERP, 0, do_unlock}, {T("@wall"), wall_sw, CA_ANNOUNCE, SHOUT_DEFAULT, CS_ONE_ARG|CS_INTERP, 0, do_shout}, {T("@wipe"), NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_ONE_ARG|CS_INTERP, 0, do_wipe}, {T("allcom"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_allcom}, {T("comlist"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_comlist}, {T("delcom"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_delcom}, {T("doing"), NULL, CA_PUBLIC, CMD_DOING, CS_ONE_ARG, 0, logged_out1}, {T("drop"), drop_sw, CA_NO_SLAVE|CA_CONTENTS|CA_LOCATION|CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_drop}, {T("enter"), enter_sw, CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_enter}, {T("examine"), examine_sw, CA_PUBLIC, 0, CS_ONE_ARG|CS_INTERP, 0, do_examine}, {T("get"), get_sw, CA_LOCATION|CA_NO_GUEST, 0, CS_ONE_ARG|CS_INTERP, 0, do_get}, #if defined(FIRANMUX) {T("goto"), goto_sw, CA_LOCATION|CA_NO_IMMOBILE, 0, CS_ONE_ARG|CS_INTERP, 0, do_move}, #else {T("goto"), goto_sw, CA_LOCATION, 0, CS_ONE_ARG|CS_INTERP, 0, do_move}, #endif // FIRANMUX {T("look"), look_sw, CA_LOCATION, LOOK_LOOK, CS_ONE_ARG|CS_INTERP, 0, do_look}, {T("outputprefix"), NULL, CA_PUBLIC, CMD_PREFIX, CS_ONE_ARG, 0, logged_out1}, {T("outputsuffix"), NULL, CA_PUBLIC, CMD_SUFFIX, CS_ONE_ARG, 0, logged_out1}, {T("pose"), pose_sw, CA_LOCATION|CA_NO_SLAVE, SAY_POSE, CS_ONE_ARG|CS_INTERP, 0, do_say}, {T("puebloclient"), NULL, CA_PUBLIC, CMD_PUEBLOCLIENT, CS_ONE_ARG, 0, logged_out1}, {T("say"), say_sw, CA_LOCATION|CA_NO_SLAVE, SAY_SAY, CS_ONE_ARG|CS_INTERP, 0, do_say}, {T("session"), NULL, CA_PUBLIC, CMD_SESSION, CS_ONE_ARG, 0, logged_out1}, {T("think"), NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, 0, do_think}, {T("train"), NULL, CA_PUBLIC, 0, CS_ONE_ARG, 0, do_train}, {T("use"), NULL, CA_NO_SLAVE|CA_GBL_INTERP, 0, CS_ONE_ARG|CS_INTERP, 0, do_use}, {T("who"), NULL, CA_PUBLIC, CMD_WHO, CS_ONE_ARG, 0, logged_out1}, {T("\\"), NULL, CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {T(":"), NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {T(";"), NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {T("\""), NULL, CA_LOCATION|CF_DARK|CA_NO_SLAVE, SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say}, {T("-"), NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_ONE_ARG|CS_LEADIN, 0, do_postpend}, {T("~"), NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_ONE_ARG|CS_LEADIN, 0, do_prepend}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_ONE_ARG_CMDARG command_table_one_arg_cmdarg[] = { {T("@apply_marked"), NULL, CA_WIZARD|CA_GBL_INTERP, 0, CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_apply_marked}, {T("#"), NULL, CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK, 0, CS_ONE_ARG|CS_INTERP|CS_CMDARG, 0, do_force_prefixed}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG command_table_two_arg[] = { {T("@addcommand"), NULL, CA_GOD, 0, CS_TWO_ARG, 0, do_addcommand}, {T("@admin"), NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_admin}, {T("@alias"), NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_alias}, {T("@attribute"), attrib_sw, CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_attribute}, {T("@cboot"), cboot_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_chboot}, {T("@ccharge"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 1, CS_TWO_ARG, 0, do_editchannel}, {T("@cchown"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_editchannel}, {T("@cemit"), cemit_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_cemit}, {T("@chown"), chown_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, CHOWN_ONE, CS_TWO_ARG|CS_INTERP, 0, do_chown}, {T("@chownall"), chown_sw, CA_WIZARD|CA_GBL_BUILD, CHOWN_ALL, CS_TWO_ARG|CS_INTERP, 0, do_chownall}, {T("@chzone"), NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_INTERP, 0, do_chzone}, {T("@clone"), clone_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_clone}, {T("@coflags"), NULL, CA_NO_SLAVE, 4, CS_TWO_ARG, 0, do_editchannel}, {T("@cpflags"), NULL, CA_NO_SLAVE, 3, CS_TWO_ARG, 0, do_editchannel}, {T("@create"), NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_create}, {T("@cset"), cset_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_chopen}, {T("@decompile"), decomp_sw, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_decomp}, {T("@delcommand"), NULL, CA_GOD, 0, CS_TWO_ARG, 0, do_delcommand}, {T("@drain"), NULL, CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST, NFY_DRAIN, CS_TWO_ARG, 0, do_notify}, {T("@femit"), femit_sw, CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, PEMIT_FEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("@fixdb"), fixdb_sw, CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_fixdb}, {T("@flag"), flag_sw, CA_GOD, 0, CS_TWO_ARG, 0, do_flag}, {T("@forwardlist"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_forwardlist}, {T("@fpose"), fpose_sw, CA_LOCATION|CA_NO_SLAVE, PEMIT_FPOSE, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("@fsay"), NULL, CA_LOCATION|CA_NO_SLAVE, PEMIT_FSAY, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("@function"), function_sw,CA_GOD, 0, CS_TWO_ARG|CS_INTERP, 0, do_function}, {T("@link"), NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_link}, {T("@lock"), lock_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_lock}, {T("@log"), NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_log}, {T("@mail"), mail_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_mail}, {T("@malias"), malias_sw, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_malias}, {T("@moniker"), NULL, CA_NO_GUEST|CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_moniker}, {T("@name"), NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_name}, {T("@newpassword"), NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_newpassword}, {T("@notify"), notify_sw, CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_notify}, {T("@npemit"), pemit_sw, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_PEMIT, CS_TWO_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_pemit}, {T("@oemit"), NULL, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_OEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("@parent"), NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_parent}, {T("@password"), NULL, CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_password}, {T("@pcreate"), NULL, CA_WIZARD|CA_GBL_BUILD, PCRE_PLAYER, CS_TWO_ARG, 0, do_pcreate}, {T("@pemit"), pemit_sw, CA_NO_GUEST|CA_NO_SLAVE, PEMIT_PEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("@power"), NULL, CA_PUBLIC, 0, CS_TWO_ARG, 0, do_power}, {T("@program"), NULL, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_prog}, {T("@quota"), quota_sw, CA_PUBLIC, 0, CS_TWO_ARG|CS_INTERP, 0, do_quota}, {T("@robot"), NULL, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER, PCRE_ROBOT, CS_TWO_ARG, 0, do_pcreate}, #ifdef REALITY_LVLS {T("@rxlevel"), NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_rxlevel}, #endif {T("@set"), set_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG, 0, do_set}, {T("@teleport"), teleport_sw,CA_NO_GUEST, TELEPORT_DEFAULT, CS_TWO_ARG|CS_INTERP, 0, do_teleport}, #ifdef REALITY_LVLS {T("@txlevel"), NULL, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_txlevel}, #endif {T("@toad"), toad_sw, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP, 0, do_toad}, {T("@email"), NULL, CA_WIZARD, 0, CS_TWO_ARG, 0, do_plusemail}, {T("addcom"), NULL, CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_addcom}, {T("comtitle"), comtitle_sw,CA_NO_SLAVE, 0, CS_TWO_ARG, 0, do_comtitle}, {T("give"), give_sw, CA_LOCATION|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP, 0, do_give}, {T("kill"), NULL, CA_NO_GUEST|CA_NO_SLAVE, KILL_KILL, CS_TWO_ARG|CS_INTERP, 0, do_kill}, {T("page"), page_sw, CA_NO_SLAVE, 0, CS_TWO_ARG|CS_INTERP, 0, do_page}, {T("slay"), NULL, CA_WIZARD, KILL_SLAY, CS_TWO_ARG|CS_INTERP, 0, do_kill}, {T("whisper"), NULL, CA_LOCATION|CA_NO_SLAVE, PEMIT_WHISPER, CS_TWO_ARG|CS_INTERP, 0, do_pemit}, {T("&"), NULL, CA_NO_GUEST|CA_NO_SLAVE|CF_DARK, 0, CS_TWO_ARG|CS_LEADIN, 0, do_setvattr}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV command_table_two_arg_argv[] = { {T("@cpattr"), NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV, 0, do_cpattr}, {T("@dig"), dig_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_dig}, {T("@edit"), NULL, CA_NO_SLAVE|CA_NO_GUEST, 0, CS_TWO_ARG|CS_ARGV|CS_STRIP_AROUND, 0, do_edit}, {T("@icmd"), icmd_sw, CA_GOD, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_icmd}, {T("@mvattr"), NULL, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0, CS_TWO_ARG|CS_ARGV, 0, do_mvattr}, {T("@open"), open_sw, CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP, 0, do_open}, {T("@trigger"), trig_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV, 0, do_trigger}, {T("@verb"), verb_sw, CA_GBL_INTERP|CA_NO_SLAVE, 0, CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP_AROUND, 0, do_verb}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_CMDARG command_table_two_arg_cmdarg[] = { {T("@assert"), NULL, CA_PUBLIC, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_assert}, {T("@break"), NULL, CA_PUBLIC, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_break}, {T("@dolist"), dolist_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_dolist}, {T("@force"), NULL, CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST, 0, CS_TWO_ARG|CS_INTERP|CS_CMDARG, 0, do_force}, #ifdef QUERY_SLAVE {T("@query"), query_sw, CA_WIZARD, 0, CS_TWO_ARG|CS_INTERP|CS_CMDARG, 0, do_query}, #endif {T("@wait"), wait_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_wait}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT_TWO_ARG_ARGV_CMDARG command_table_two_arg_argv_cmdarg[] = { {T("@if"), NULL, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_if}, {T("@switch"), switch_sw, CA_GBL_INTERP, 0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_switch}, {(UTF8 *)NULL, NULL, 0, 0, 0, 0, NULL} }; static CMDENT *prefix_cmds[256]; static CMDENT *goto_cmdp; void commands_no_arg_add(CMDENT_NO_ARG cmdent[]) { CMDENT_NO_ARG *cp0a; for (cp0a = cmdent; cp0a->cmdname; cp0a++) { if (!hashfindLEN(cp0a->cmdname, strlen((char *)cp0a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp0a->cmdname, strlen((char *)cp0a->cmdname), cp0a, &mudstate.command_htab); } } } void commands_one_arg_add(CMDENT_ONE_ARG cmdent[]) { CMDENT_ONE_ARG *cp1a; for (cp1a = cmdent; cp1a->cmdname; cp1a++) { if (!hashfindLEN(cp1a->cmdname, strlen((char *)cp1a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp1a->cmdname, strlen((char *)cp1a->cmdname), cp1a, &mudstate.command_htab); } } } void commands_one_arg_cmdarg_add(CMDENT_ONE_ARG_CMDARG cmdent[]) { CMDENT_ONE_ARG_CMDARG *cp1ac; for (cp1ac = cmdent; cp1ac->cmdname; cp1ac++) { if (!hashfindLEN(cp1ac->cmdname, strlen((char *)cp1ac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp1ac->cmdname, strlen((char *)cp1ac->cmdname), cp1ac, &mudstate.command_htab); } } } void commands_two_arg_add(CMDENT_TWO_ARG cmdent[]) { CMDENT_TWO_ARG *cp2a; for (cp2a = cmdent; cp2a->cmdname; cp2a++) { if (!hashfindLEN(cp2a->cmdname, strlen((char *)cp2a->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2a->cmdname, strlen((char *)cp2a->cmdname), cp2a, &mudstate.command_htab); } } } void commands_two_arg_argv_add(CMDENT_TWO_ARG_ARGV cmdent[]) { CMDENT_TWO_ARG_ARGV *cp2aa; for (cp2aa = cmdent; cp2aa->cmdname; cp2aa++) { if (!hashfindLEN(cp2aa->cmdname, strlen((char *)cp2aa->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2aa->cmdname, strlen((char *)cp2aa->cmdname), cp2aa, &mudstate.command_htab); } } } void commands_two_arg_cmdarg_add(CMDENT_TWO_ARG_CMDARG cmdent[]) { CMDENT_TWO_ARG_CMDARG *cp2ac; for (cp2ac = cmdent; cp2ac->cmdname; cp2ac++) { if (!hashfindLEN(cp2ac->cmdname, strlen((char *)cp2ac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2ac->cmdname, strlen((char *)cp2ac->cmdname), cp2ac, &mudstate.command_htab); } } } void commands_two_arg_argv_cmdarg_add(CMDENT_TWO_ARG_ARGV_CMDARG cmdent[]) { CMDENT_TWO_ARG_ARGV_CMDARG *cp2aac; for (cp2aac = cmdent; cp2aac->cmdname; cp2aac++) { if (!hashfindLEN(cp2aac->cmdname, strlen((char *)cp2aac->cmdname), &mudstate.command_htab)) { hashaddLEN(cp2aac->cmdname, strlen((char *)cp2aac->cmdname), cp2aac, &mudstate.command_htab); } } } void init_cmdtab(void) { ATTR *ap; // Load attribute-setting commands. // for (ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } size_t nBuffer; bool bValid; UTF8 *cbuff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT_TWO_ARG *cp2a = NULL; try { cp2a = new CMDENT_TWO_ARG; } catch (...) { ; // Nothing. } if (NULL != cp2a) { cp2a->cmdname = StringClone(cbuff); cp2a->perms = CA_NO_GUEST | CA_NO_SLAVE; cp2a->switches = NULL; if (ap->flags & (AF_WIZARD | AF_MDARK)) { cp2a->perms |= CA_WIZARD; } cp2a->extra = ap->number; cp2a->callseq = CS_TWO_ARG; cp2a->hookmask = 0; cp2a->handler = do_setattr; hashaddLEN(cp2a->cmdname, nBuffer, cp2a, &mudstate.command_htab); } else { ISOUTOFMEMORY(cp2a); } } // Load the builtin commands // commands_no_arg_add(command_table_no_arg); commands_one_arg_add(command_table_one_arg); commands_one_arg_cmdarg_add(command_table_one_arg_cmdarg); commands_two_arg_add(command_table_two_arg); commands_two_arg_argv_add(command_table_two_arg_argv); commands_two_arg_cmdarg_add(command_table_two_arg_cmdarg); commands_two_arg_argv_cmdarg_add(command_table_two_arg_argv_cmdarg); set_prefix_cmds(); goto_cmdp = (CMDENT *) hashfindLEN((char *)"goto", strlen("goto"), &mudstate.command_htab); } /*! \brief Fills in the table of single-character prefix commands. * * Command entries for known prefix commands (" : ; \ # & - ~) * are copied from the regular command table. Entries for all other starting * characters are set to \c NULL. * * \return None. */ void set_prefix_cmds() { for (int i = 0; i < 256; i++) { prefix_cmds[i] = NULL; } #define SET_PREFIX_CMD(s) prefix_cmds[(unsigned char)(s)[0]] = \ (CMDENT *) hashfindLEN((char *)(s), 1, &mudstate.command_htab) SET_PREFIX_CMD("\""); SET_PREFIX_CMD(":"); SET_PREFIX_CMD(";"); SET_PREFIX_CMD("\\"); SET_PREFIX_CMD("#"); SET_PREFIX_CMD("&"); SET_PREFIX_CMD("-"); SET_PREFIX_CMD("~"); #undef SET_PREFIX_CMD } // --------------------------------------------------------------------------- // check_access: Check if player has access to function. // bool check_access(dbref player, int mask) { if (mask & (CA_DISABLED|CA_STATIC)) { return false; } if ( God(player) || mudstate.bReadingConfiguration) { return true; } if (mask & CA_MUSTBE_MASK) { // Since CA_GOD by itself is a frequent case, for the sake of // performance, we test CA_GOD specifically. If CA_GOD were ever // combined with anything, it would be passed through to the general // case. // if ((mask & CA_MUSTBE_MASK) == CA_GOD) { return false; } // Since God(player) is always false here, CA_GOD is still handled by // the following code even though it doesn't appear in any of the // cases explicitly. CA_WIZARD by itself is also a common case, but // since we have have a bit (mask & CA_MUSTBE_MASK), and since that // bit is not a lone CA_GOD bit (handled above), and since CA_WIZARD // it tested first below, it doesn't make sense to test CA_WIZARD // as a special case. // if (!( ((mask & CA_WIZARD) && Wizard(player)) || ((mask & CA_ADMIN) && WizRoy(player)) || ((mask & CA_BUILDER) && Builder(player)) || ((mask & CA_STAFF) && Staff(player)) || ((mask & CA_HEAD) && Head(player)) || ((mask & CA_ANNOUNCE) && Announce(player)) || ((mask & CA_IMMORTAL) && Immortal(player)) || ((mask & CA_UNINS) && Uninspected(player)) || ((mask & CA_ROBOT) && Robot(player)))) { return false; } } // Check for forbidden flags. // if ( (mask & CA_CANTBE_MASK) && !Wizard(player)) { if ( ((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)) #if defined(FIRANMUX) // || ((mask & CA_NO_IMMOBILE) && Immobile(player)) || ((mask & CA_NO_RESTRICTED) && Restricted(player)) #endif // FIRANMUX || ((mask & CA_NO_UNINS) && Uninspected(player))) { return false; } } return true; } /***************************************************************************** * Process the various hook calls. * Idea taken from TinyMUSH3, code from RhostMUSH, ported by Jake Nelson. * Hooks processed: before, after, ignore, permit, fail *****************************************************************************/ static bool process_hook(dbref executor, dbref thing, UTF8 *s_uselock, ATTR *hk_attr, bool save_flg) { UNUSED_PARAMETER(s_uselock); bool retval = true; if (hk_attr) { dbref aowner; int aflags; int anum = hk_attr->number; UTF8 *atext = atr_get("process_hook.1060", thing, anum, &aowner, &aflags); if (atext[0] && !(aflags & AF_NOPROG)) { reg_ref **preserve = NULL; if (save_flg) { preserve = PushRegisters(MAX_GLOBAL_REGS); save_global_regs(preserve); } UTF8 *buff, *bufc; bufc = buff = alloc_lbuf("process_hook"); mux_exec(atext, buff, &bufc, thing, executor, executor, AttrTrace(aflags, EV_FCHECK|EV_EVAL), NULL, 0); *bufc = '\0'; if (save_flg) { restore_global_regs(preserve); PopRegisters(preserve, MAX_GLOBAL_REGS); } retval = xlate(buff); free_lbuf(buff); } free_lbuf(atext); } return retval; } static UTF8 *hook_name(const UTF8 *pCommand, int key) { char *keylet; switch (key) { case HOOK_AFAIL: keylet = "AF"; break; case HOOK_AFTER: keylet = "A"; break; case HOOK_BEFORE: keylet = "B"; break; case HOOK_IGNORE: keylet = "I"; break; case HOOK_PERMIT: keylet = "P"; break; default: return NULL; } const UTF8 *cmdName = pCommand; if ( pCommand[0] && !pCommand[1]) { switch (pCommand[0]) { case '"' : cmdName = T("say"); break; case ':' : case ';' : cmdName = T("pose"); break; case '\\': cmdName = T("@emit"); break; case '#' : cmdName = T("@force"); break; case '&' : cmdName = T("@set"); break; case '-' : cmdName = T("@mail"); break; case '~' : cmdName = T("@mail"); break; } } UTF8 *s_uselock = alloc_sbuf("command_hook.hookname"); mux_sprintf(s_uselock, SBUF_SIZE, "%s_%s", keylet, cmdName); return s_uselock; } /* --------------------------------------------------------------------------- * process_cmdent: Perform indicated command with passed args. */ static void process_cmdent(CMDENT *cmdp, UTF8 *switchp, dbref executor, dbref caller, dbref enactor, int eval, bool interactive, UTF8 *arg, UTF8 *unp_command, UTF8 *cargs[], int ncargs) { // Perform object type checks. // if (Invalid_Objtype(executor)) { notify(executor, T("Command incompatible with executor type.")); return; } // Check if we have permission to execute the command. // if (!check_access(executor, cmdp->perms)) { notify(executor, NOPERM_MESSAGE); return; } // Check global flags // if ( !Builder(executor) && Protect(CA_GBL_BUILD) && !(mudconf.control_flags & CF_BUILD)) { notify(executor, T("Sorry, building is not allowed now.")); return; } if (Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP)) { notify(executor, T("Sorry, queueing and triggering are not allowed now.")); return; } UTF8 *s_uselock; UTF8 *buf1, *buf2, tchar, *bp, *str, *buff, *j, *new0; UTF8 *args[MAX_ARG]; int nargs, i, interp, key, xkey, aflags; dbref aowner; UTF8 *aargs[NUM_ENV_VARS]; ADDENT *add; ATTR *hk_ap2; 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 = (UTF8 *)strchr((char *)switchp, '/'); if (buf1) { *buf1++ = '\0'; } if (!search_nametab(executor, cmdp->switches, switchp, &xkey)) { if (xkey == -1) { notify(executor, tprintf("Unrecognized switch '%s' for command '%s'.", switchp, cmdp->cmdname)); return; } else if (xkey == -2) { notify(executor, NOPERM_MESSAGE); return; } } else if (!(xkey & SW_MULTIPLE)) { if (i == 1) { notify(executor, T("Illegal combination of switches.")); return; } i = 1; } else { xkey &= ~SW_MULTIPLE; } key |= xkey; switchp = buf1; } while (buf1); } else if (switchp && !(cmdp->callseq & CS_ADDED)) { notify(executor, tprintf("Command %s does not take switches.", cmdp->cmdname)); return; } // 'Before' hooks. // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson. // if ( (cmdp->hookmask & HOOK_BEFORE) && Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { s_uselock = hook_name(cmdp->cmdname, HOOK_BEFORE); hk_ap2 = atr_str(s_uselock); process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } // We are allowed to run the command. Now, call the handler using // the appropriate calling sequence and arguments. // //if ((cmdp->callseq & CS_INTERP) && (key & SW_NOEVAL)) if (key & SW_NOEVAL) { // The user specified /noeval on a @pemit or a @npemit, // just do EV_STRIP_CURLY and remove the SW_NOEVAL from the // 'key'. // interp = 0; key &= ~SW_NOEVAL; } else if ( (cmdp->callseq & CS_INTERP) || !( interactive || (cmdp->callseq & CS_NOINTERP))) { // If the command is interpreted, or we're interactive (and // the command isn't specified CS_NOINTERP), eval the args. // interp = EV_EVAL | EV_STRIP_CURLY; } else if (cmdp->callseq & CS_STRIP) { interp = EV_STRIP_CURLY; } else if (cmdp->callseq & CS_STRIP_AROUND) { interp = EV_STRIP_AROUND; } else { interp = 0; } int nargs2; switch (cmdp->callseq & CS_NARG_MASK) { case CS_NO_ARGS: // (no args) (*(((CMDENT_NO_ARG *)cmdp)->handler))(executor, caller, enactor, key); break; case CS_ONE_ARG: // // If an unparsed command, just give it to the handler // #if 0 // This never happens. // if (cmdp->callseq & CS_UNPARSE) { (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, unp_command); break; } #endif // 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; // Copy and skip first character for CS_LEADIN, to // prevent the \ prefix command from escaping part of // its argument. // if (cmdp->callseq & CS_LEADIN) { *bp++ = *str++; } mux_exec(str, buf1, &bp, executor, caller, enactor, eval|interp|EV_FCHECK|EV_TOP, cargs, ncargs); *bp = '\0'; } else { buf1 = parse_to(&arg, '\0', interp | EV_TOP); } // Call the correct handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_ONE_ARG_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, cargs, ncargs); } else if (cmdp->callseq & CS_ADDED) { for (add = cmdp->addent; add != NULL; add = add->next) { buff = atr_get("process_cmdent.1347", add->thing, add->atr, &aowner, &aflags); // Attribute should contain at least two characters and first // character is '$'. // if ( AMATCH_CMD != buff[0] || '\0' == buff[1]) { free_lbuf(buff); break; } // Skip the '$' character and the next to allow "$::cmd". // size_t iBuff; for (iBuff = 2; '\0' != buff[iBuff] && ':' != buff[iBuff]; iBuff++) { ; // Nothing. } if ('\0' == buff[iBuff]) { free_lbuf(buff); break; } buff[iBuff++] = '\0'; if (!(cmdp->callseq & CS_LEADIN)) { for (j = unp_command; *j && (*j != ' '); j++) { ; // Nothing. } } else { for (j = unp_command; *j; j++) { ; // Nothing. } } new0 = alloc_lbuf("process_cmdent.soft"); bp = new0; if (!*j) { // No args. // if (!(cmdp->callseq & CS_LEADIN)) { safe_str(cmdp->cmdname, new0, &bp); } else { safe_str(unp_command, new0, &bp); } if (switchp) { safe_chr('/', new0, &bp); safe_str(switchp, new0, &bp); } *bp = '\0'; } else { j++; safe_str(cmdp->cmdname, new0, &bp); if (switchp) { safe_chr('/', new0, &bp); safe_str(switchp, new0, &bp); } safe_chr(' ', new0, &bp); safe_str(j, new0, &bp); *bp = '\0'; } if ( ( (aflags & AF_REGEXP) && regexp_match(buff + 1, new0, ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), aargs, NUM_ENV_VARS)) || ( (aflags & AF_REGEXP) == 0 && wild(buff + 1, new0, aargs, NUM_ENV_VARS))) { CLinearTimeAbsolute lta; wait_que(add->thing, caller, executor, AttrTrace(aflags, 0), false, lta, NOTHING, 0, buff + iBuff, NUM_ENV_VARS, aargs, mudstate.global_regs); for (i = 0; i < NUM_ENV_VARS; i++) { if (aargs[i]) { free_lbuf(aargs[i]); } } } free_lbuf(new0); free_lbuf(buff); } } else { (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, caller, enactor, eval, 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: // = // Interpret ARG1 // buf2 = parse_to(&arg, '=', EV_STRIP_TS); nargs2 = 0; if (buf2) { if (arg) { nargs2 = 2; } else { nargs2 = 1; } } // Handle when no '=' was specified. // if (!arg || (arg && !*arg)) { arg = &tchar; *arg = '\0'; } buf1 = bp = alloc_lbuf("process_cmdent.2"); mux_exec(buf2, buf1, &bp, executor, caller, enactor, eval|EV_STRIP_CURLY|EV_FCHECK|EV_EVAL|EV_TOP, cargs, ncargs); *bp = '\0'; if (cmdp->callseq & CS_ARGV) { // Arg2 is ARGV style. Go get the args. // parse_arglist(executor, caller, enactor, arg, '\0', eval|interp|EV_STRIP_LS|EV_STRIP_TS, args, MAX_ARG, cargs, ncargs, &nargs); // Call the correct command handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_TWO_ARG_ARGV_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, args, nargs, cargs, ncargs); } else { (*(((CMDENT_TWO_ARG_ARGV *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, args, nargs); } // Free the argument buffers. // for (i = 0; i < nargs; i++) { free_lbuf(args[i]); } } else { // Arg2 is normal style. Interpret if needed. // if (interp & EV_EVAL) { buf2 = bp = alloc_lbuf("process_cmdent.3"); mux_exec(arg, buf2, &bp, executor, caller, enactor, eval|interp|EV_FCHECK|EV_TOP, cargs, ncargs); *bp = '\0'; } else if (cmdp->callseq & CS_UNPARSE) { buf2 = parse_to(&arg, '\0', eval|interp|EV_TOP|EV_NO_COMPRESS); } else { buf2 = parse_to(&arg, '\0', eval|interp|EV_STRIP_LS|EV_STRIP_TS|EV_TOP); } // Call the correct command handler. // if (cmdp->callseq & CS_CMDARG) { (*(((CMDENT_TWO_ARG_CMDARG *)cmdp)->handler))(executor, caller, enactor, eval, key, buf1, buf2, cargs, ncargs); } else { (*(((CMDENT_TWO_ARG *)cmdp)->handler))(executor, caller, enactor, key, nargs2, 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; } // 'After' hooks. // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson. // if ( (cmdp->hookmask & HOOK_AFTER) && Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { s_uselock = hook_name(cmdp->cmdname, HOOK_AFTER); hk_ap2 = atr_str(s_uselock); (void)process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } return; } static int cmdtest(dbref player, const UTF8 *cmd) { UTF8 *buff1; const UTF8 *pt1, *pt2; dbref aowner; int aflags, rval; rval = 0; buff1 = atr_get("cmdtest.1573", player, A_CMDCHECK, &aowner, &aflags); pt1 = buff1; while (pt1 && *pt1) { pt2 = (const UTF8 *)strchr((const char *)pt1, ':'); if (!pt2 || (pt2 == pt1)) break; if (!strncmp((const char *)pt2+1, (const char *)cmd, strlen((const char *)cmd))) { if (*(pt2-1) == '1') rval = 1; else rval = 2; break; } pt1 = (const UTF8 *)strchr((const char *)pt2+1,' '); if (pt1 && *pt1) { while (mux_isspace(*pt1)) { pt1++; } } } free_lbuf(buff1); return rval; } static int zonecmdtest(dbref player, const UTF8 *cmd) { if (!Good_obj(player) || God(player)) { return 0; } dbref loc = Location(player); int i_ret = 0; if (Good_obj(loc)) { i_ret = cmdtest(loc, cmd); if (i_ret == 0) { dbref zone = Zone(loc); if ( Good_obj(zone) && ( isRoom(zone) || isThing(zone))) { i_ret = cmdtest(zone, cmd); } } } return i_ret; } static int higcheck(dbref executor, dbref caller, dbref enactor, CMDENT *cmdp, const UTF8 *pCommand) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(pCommand); if ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { UTF8 *s_uselock; ATTR *checkattr; bool bResult; if (cmdp->hookmask & HOOK_IGNORE) { s_uselock = hook_name(cmdp->cmdname, HOOK_IGNORE); checkattr = atr_str(s_uselock); bResult = process_hook(executor, mudconf.hook_obj, s_uselock, checkattr, true); free_sbuf(s_uselock); if (!bResult) { return 2; } } if (cmdp->hookmask & HOOK_PERMIT) { s_uselock = hook_name(cmdp->cmdname, HOOK_PERMIT); checkattr = atr_str(s_uselock); bResult = process_hook(executor, mudconf.hook_obj, s_uselock, checkattr, true); free_sbuf(s_uselock); if (!bResult) { return 1; } } } return 0; } static void hook_fail(dbref executor, CMDENT *cmdp, const UTF8 *pCommand) { UNUSED_PARAMETER(pCommand); if ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) { UTF8 *s_uselock = hook_name(cmdp->cmdname, HOOK_AFAIL); ATTR *hk_ap2 = atr_str(s_uselock); process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false); free_sbuf(s_uselock); } } // --------------------------------------------------------------------------- // process_command: Execute a command. // UTF8 *process_command ( dbref executor, dbref caller, dbref enactor, int eval, bool interactive, UTF8 *arg_command, UTF8 *args[], int nargs ) { static UTF8 preserve_cmd[LBUF_SIZE]; UTF8 *pOriginalCommand = arg_command; static UTF8 SpaceCompressCommand[LBUF_SIZE]; static UTF8 LowerCaseCommand[LBUF_SIZE]; UTF8 *pCommand; UTF8 *p, *q, *arg, *pSlash, *bp, check2[2]; const UTF8 *cmdsave; int aflags; dbref exit, aowner; CMDENT *cmdp; // Robustify player. // cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = T("< process_command >"); mudstate.nStackNest = 0; mudstate.bStackLimitReached = false; *(check2 + 1) = '\0'; mux_assert(pOriginalCommand); if (!Good_obj(executor)) { STARTLOG(LOG_BUGS, T("CMD"), T("PLYR")); log_printf("Bad player in process_command: %d", executor); ENDLOG; mudstate.debug_cmd = cmdsave; return pOriginalCommand; } // Make sure player isn't going or halted. // if ( Going(executor) || ( Halted(executor) && !( isPlayer(executor) && interactive))) { notify(Owner(executor), tprintf("Attempt to execute command by halted object #%d", executor)); mudstate.debug_cmd = cmdsave; return pOriginalCommand; } if ( Suspect(executor) && (mudconf.log_options & LOG_SUSPECTCMDS)) { STARTLOG(LOG_SUSPECTCMDS, T("CMD"), T("SUSP")); log_name_and_loc(executor); log_text(T(" entered: ")); log_text(pOriginalCommand); ENDLOG; } else { STARTLOG(LOG_ALLCOMMANDS, T("CMD"), T("ALL")); log_name_and_loc(executor); log_text(T(" entered: ")); log_text(pOriginalCommand); 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(executor)) { notify(Owner(executor), tprintf("%s] %s", Name(executor), pOriginalCommand)); } // Eat leading whitespace, and space-compress if configured. // while (mux_isspace(*pOriginalCommand)) { pOriginalCommand++; } mux_strncpy(preserve_cmd, pOriginalCommand, LBUF_SIZE-1); mudstate.debug_cmd = pOriginalCommand; mudstate.curr_cmd = preserve_cmd; if (mudconf.space_compress) { // Compress out the spaces and use that as the command // pCommand = SpaceCompressCommand; p = pOriginalCommand; q = SpaceCompressCommand; while ( *p && q < SpaceCompressCommand + LBUF_SIZE) { while ( *p && !mux_isspace(*p) && q < SpaceCompressCommand + LBUF_SIZE) { *q++ = *p++; } while (mux_isspace(*p)) { p++; } if ( *p && q < SpaceCompressCommand + LBUF_SIZE) { *q++ = ' '; } } *q = '\0'; } else { // Don't compress the spaces. Use the original command // (without leading spaces) as the command to use. // pCommand = pOriginalCommand; } // 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. // UTF8 i = (UTF8)pCommand[0]; int cval = 0; int hval = 0; if ( '\0' != i && NULL != prefix_cmds[i]) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // *check2 = i; if (CmdCheck(executor)) { cval = cmdtest(executor, check2); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), check2); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, check2); } if (prefix_cmds[i]->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, prefix_cmds[i], pCommand); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (prefix_cmds[i]->hookmask & HOOK_AFAIL) { hook_fail(executor, prefix_cmds[i], pCommand); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } process_cmdent(prefix_cmds[i], NULL, executor, caller, enactor, eval, interactive, pCommand, pCommand, args, nargs); if (mudstate.bStackLimitReached) { STARTLOG(LOG_ALWAYS, T("CMD"), T("SPAM")); log_name_and_loc(executor); log_text(T(" entered: ")); log_text(pOriginalCommand); ENDLOG; } mudstate.bStackLimitReached = false; mudstate.debug_cmd = cmdsave; return preserve_cmd; } } if ( mudconf.have_comsys && !Slave(executor) && !do_comsystem(executor, pCommand)) { mudstate.debug_cmd = cmdsave; return preserve_cmd; } // Check for the HOME command. // if ( Has_location(executor) && string_compare(pCommand, T("home")) == 0) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore. // if (CmdCheck(executor)) { cval = cmdtest(executor, T("home")); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), T("home")); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, T("home")); } if (cval != 2) { if (!check_access(executor, mudconf.restrict_home)) { notify(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } if (cval == 1) { notify(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } if ( ( Fixed(executor) || Fixed(Owner(executor))) && !WizRoy(executor)) { notify(executor, mudconf.fixed_home_msg); mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_move(executor, caller, enactor, eval, 0, (UTF8 *)"home"); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } // Only check for exits if we may use the goto command. // if (check_access(executor, goto_cmdp->perms)) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // Master room exits are not affected. // if (CmdCheck(executor)) { cval = cmdtest(executor, T("goto")); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), T("goto")); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, T("goto")); } if (goto_cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, goto_cmdp, T("goto")); } else { hval = 0; } if ( cval != 2 && hval != 2) { // Check for an exit name. // init_match_check_keys(executor, pCommand, TYPE_EXIT); match_exit_with_parents(); exit = last_match_result(); if (exit != NOTHING) { if (cval || hval) { if (goto_cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, goto_cmdp, T("goto")); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } move_exit(executor, exit, false, T("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(executor, pCommand, TYPE_EXIT); match_master_exit(); exit = last_match_result(); if (exit != NOTHING) { move_exit(executor, exit, true, 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 LowerCaseCommand after // the lower-cased command. // // Make lowercase command // size_t nLowerCaseCommand = 0, iPos = 0; while ( pCommand[iPos] && !mux_isspace(pCommand[iPos]) && nLowerCaseCommand < LBUF_SIZE - 1) { LowerCaseCommand[nLowerCaseCommand] = mux_tolower_ascii(pCommand[iPos]); iPos++; nLowerCaseCommand++; } LowerCaseCommand[nLowerCaseCommand] = '\0'; // Skip spaces before arg // while (mux_isspace(pCommand[iPos])) { iPos++; } // Remember where arg starts // arg = pCommand + iPos; // Strip off any command switches and save them. // pSlash = (UTF8 *)strchr((char *)LowerCaseCommand, '/'); if (pSlash) { nLowerCaseCommand = pSlash - LowerCaseCommand; *pSlash++ = '\0'; } // Check for a builtin command (or an alias of a builtin command) // cmdp = (CMDENT *)hashfindLEN(LowerCaseCommand, nLowerCaseCommand, &mudstate.command_htab); /* If command is checked to ignore NONMATCHING switches, fall through */ if (cmdp) { // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, cmdp->cmdname); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), cmdp->cmdname); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, cmdp->cmdname); } if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, LowerCaseCommand); } else { hval = 0; } // If the command contains a switch, but the command doesn't support // any switches or the command contains one that isn't supported, // HOOK_IGSWITCH will allow us to treat the entire command as if it // weren't a built-in command. // int flagvalue; if ( (cmdp->hookmask & HOOK_IGSWITCH) && pSlash) { if (cmdp->switches) { search_nametab(executor, cmdp->switches, pSlash, &flagvalue); if (flagvalue & SW_MULTIPLE) { MUX_STRTOK_STATE ttswitch; // All the switches given a command shouldn't exceed 200 chars together UTF8 switch_buff[200]; UTF8 *switch_ptr; mux_strncpy(switch_buff, pSlash, sizeof(switch_buff)-1); mux_strtok_src(&ttswitch, switch_buff); mux_strtok_ctl(&ttswitch, T("/")); switch_ptr = mux_strtok_parse(&ttswitch); while ( switch_ptr && *switch_ptr) { search_nametab(executor, cmdp->switches, switch_ptr, &flagvalue); if (flagvalue == -1) { break; } switch_ptr = mux_strtok_parse(&ttswitch); } } if (flagvalue == -1) { cval = 2; } } else { // Switch exists but no switches allowed for command. // cval = 2; } } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, LowerCaseCommand); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } 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 original command. // We skip over the command and a single space to position // arg at the arguments. // arg = pCommand = pOriginalCommand; while (*arg && !mux_isspace(*arg)) { arg++; } if (*arg) { // We stopped on the space, advance to next. // arg++; } } process_cmdent(cmdp, pSlash, executor, caller, enactor, eval, interactive, arg, pCommand, args, nargs); if (mudstate.bStackLimitReached) { STARTLOG(LOG_ALWAYS, T("CMD"), T("SPAM")); log_name_and_loc(executor); log_text(T(" entered: ")); log_text(pOriginalCommand); ENDLOG; } mudstate.bStackLimitReached = false; 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. // bp = LowerCaseCommand; mux_exec(pCommand, LowerCaseCommand, &bp, executor, caller, enactor, eval|EV_EVAL|EV_FCHECK|EV_STRIP_CURLY|EV_TOP, args, nargs); *bp = '\0'; bool succ = false; // Idea for enter/leave aliases from R'nice@TinyTIM // if (Has_location(executor) && Good_obj(Location(executor))) { // Check for a leave alias. // p = atr_pget(Location(executor), A_LALIAS, &aowner, &aflags); if (*p) { if (matches_exit_from_list(LowerCaseCommand, p)) { free_lbuf(p); // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, T("leave")); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), T("leave")); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, T("leave")); } cmdp = (CMDENT *)hashfindLEN("leave", strlen("leave"), &mudstate.command_htab); if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, T("leave")); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, T("leave")); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_leave(executor, caller, executor, 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } } free_lbuf(p); DOLIST(exit, Contents(Location(executor))) { p = atr_pget(exit, A_EALIAS, &aowner, &aflags); if (*p) { if (matches_exit_from_list(LowerCaseCommand, p)) { free_lbuf(p); // Check for enter aliases. // // CmdCheck tests for @icmd. higcheck tests for i/p hooks. // Both from RhostMUSH. // cval/hval values: 0 normal, 1 disable, 2 ignore // if (CmdCheck(executor)) { cval = cmdtest(executor, T("enter")); } else if (CmdCheck(Owner(executor))) { cval = cmdtest(Owner(executor), T("enter")); } else { cval = 0; } if (cval == 0) { cval = zonecmdtest(executor, T("enter")); } cmdp = (CMDENT *)hashfindLEN("enter", strlen("enter"), &mudstate.command_htab); if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT)) { hval = higcheck(executor, caller, enactor, cmdp, T("enter")); } else { hval = 0; } if ( cval != 2 && hval != 2) { if ( cval == 1 || hval == 1) { if (cmdp->hookmask & HOOK_AFAIL) { hook_fail(executor, cmdp, T("enter")); } else { notify(executor, NOPERM_MESSAGE); } mudstate.debug_cmd = cmdsave; return preserve_cmd; } do_enter_internal(executor, exit, false); mudstate.debug_cmd = cmdsave; return preserve_cmd; } else if (cval == 1) { notify_quiet(executor, NOPERM_MESSAGE); mudstate.debug_cmd = cmdsave; return preserve_cmd; } } } free_lbuf(p); } } // Check for $-command matches on me. // if (mudconf.match_mine && !No_Command(executor)) { if ( ( !isPlayer(executor) || mudconf.match_mine_pl) && atr_match(executor, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true)) { succ = true; } } // Check for $-command matches on nearby things and on my room. // if (Has_location(executor)) { succ |= list_check(Contents(Location(executor)), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); if (!No_Command(Location(executor))) { succ |= atr_match(Location(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } // Check for $-command matches in my inventory. // if (Has_contents(executor)) { succ |= list_check(Contents(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } if ( !succ && mudconf.have_zones) { // now do check on zones. // dbref zone = Zone(executor); dbref loc = Location(executor); dbref zone_loc = NOTHING; if ( Good_obj(loc) && Good_obj(zone_loc = Zone(loc))) { if (isRoom(zone_loc)) { // zone of player's location is a parent room. // if (loc != zone) { // check parent room exits. // init_match_check_keys(executor, pCommand, TYPE_EXIT); match_zone_exit(); exit = last_match_result(); if (exit != NOTHING) { move_exit(executor, exit, true, NULL, 0); mudstate.debug_cmd = cmdsave; return preserve_cmd; } succ |= list_check(Contents(zone_loc), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); // end of parent room checks. // } } else { // try matching commands on area zone object. // if (!No_Command(zone_loc)) { succ |= atr_match(zone_loc, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } } // End of matching on zone of player's location. // // if nothing matched with parent room/zone object, try matching // zone commands on the player's personal zone. // if ( !succ && Good_obj(zone) && !No_Command(zone) && zone_loc != zone) { succ |= atr_match(zone, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true); } } // 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), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, false); if (!No_Command(mudconf.master_room)) { succ |= atr_match(mudconf.master_room, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, false); } } } // If we still didn't find anything, tell how to get help. // if (!succ) { if ( Good_obj(mudconf.global_error_obj) && !Going(mudconf.global_error_obj)) { UTF8 *errtext = atr_get("process_command.2491", mudconf.global_error_obj, A_VA, &aowner, &aflags); UTF8 *errbuff = alloc_lbuf("process_command.error_msg"); UTF8 *errbufc = errbuff; mux_exec(errtext, errbuff, &errbufc, mudconf.global_error_obj, caller, enactor, AttrTrace(aflags, EV_EVAL|EV_FCHECK|EV_STRIP_CURLY|EV_TOP), &pCommand, 1); notify(executor, errbuff); free_lbuf(errtext); free_lbuf(errbuff); } else { // We use LowerCaseCommand for another purpose. // notify(executor, T("Huh? (Type \"help\" for help.)")); STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD"); log_name_and_loc(executor); log_text(T(" entered: ")); log_text(pCommand); ENDLOG; } } mudstate.debug_cmd = cmdsave; return preserve_cmd; } // --------------------------------------------------------------------------- // list_cmdtable: List internal commands. // static void list_cmdtable(dbref player) { UTF8 *buf = alloc_lbuf("list_cmdtable"); UTF8 *bp = buf; ITL itl; ItemToList_Init(&itl, buf, &bp); ItemToList_AddString(&itl, T("Commands:")); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { ItemToList_AddString(&itl, cmdp->cmdname); } } } ItemToList_Final(&itl); *bp = '\0'; // Players get the list of logged-out cmds too // if (isPlayer(player)) { display_nametab(player, logout_cmdtable, buf, true); } else { notify(player, buf); } free_lbuf(buf); } // --------------------------------------------------------------------------- // list_attrtable: List available attributes. // static void list_attrtable(dbref player) { ATTR *ap; UTF8 *buf = alloc_lbuf("list_attrtable"); UTF8 *bp = buf; ITL itl; ItemToList_Init(&itl, buf, &bp); ItemToList_AddString(&itl, T("Attributes:")); for (ap = AttrTable; ap->name; ap++) { if (See_attr(player, player, ap)) { ItemToList_AddString(&itl, ap->name); } } ItemToList_Final(&itl); *bp = '\0'; raw_notify(player, buf); free_lbuf(buf); } // --------------------------------------------------------------------------- // list_cmdaccess: List access commands. // NAMETAB access_nametab[] = { {T("builder"), 6, CA_WIZARD, CA_BUILDER}, #if !defined(FIRANMUX) {T("dark"), 4, CA_GOD, CF_DARK}, #endif // FIRANMUX {T("disabled"), 4, CA_GOD, CA_DISABLED}, {T("global_build"), 8, CA_PUBLIC, CA_GBL_BUILD}, {T("global_interp"), 8, CA_PUBLIC, CA_GBL_INTERP}, {T("god"), 2, CA_GOD, CA_GOD}, {T("head"), 2, CA_WIZARD, CA_HEAD}, {T("immortal"), 3, CA_WIZARD, CA_IMMORTAL}, {T("need_location"), 6, CA_PUBLIC, CA_LOCATION}, {T("need_contents"), 6, CA_PUBLIC, CA_CONTENTS}, {T("need_player"), 6, CA_PUBLIC, CA_PLAYER}, {T("no_haven"), 4, CA_PUBLIC, CA_NO_HAVEN}, #if defined(FIRANMUX) {T("no_immobile"), 5, CA_WIZARD, CA_NO_IMMOBILE}, {T("no_restricted"), 6, CA_WIZARD, CA_NO_RESTRICTED}, #endif // FIRANMUX {T("no_robot"), 4, CA_WIZARD, CA_NO_ROBOT}, {T("no_slave"), 5, CA_PUBLIC, CA_NO_SLAVE}, {T("no_suspect"), 5, CA_WIZARD, CA_NO_SUSPECT}, {T("no_guest"), 5, CA_WIZARD, CA_NO_GUEST}, {T("no_uninspected"), 5, CA_WIZARD, CA_NO_UNINS}, {T("robot"), 2, CA_WIZARD, CA_ROBOT}, {T("staff"), 4, CA_WIZARD, CA_STAFF}, {T("static"), 4, CA_GOD, CA_STATIC}, {T("uninspected"), 5, CA_WIZARD, CA_UNINS}, {T("wizard"), 3, CA_WIZARD, CA_WIZARD}, {(UTF8 *)NULL, 0, 0, 0} }; static void list_cmdaccess(dbref player) { ATTR *ap; UTF8 *buff = alloc_sbuf("list_cmdaccess"); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if ( check_access(player, cmdp->perms) && !(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff, true); } } } free_sbuf(buff); for (ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } size_t nBuffer; bool bValid; UTF8 *buff2 = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT *cmdp = (CMDENT *)hashfindLEN(buff2, nBuffer, &mudstate.command_htab); if (cmdp == NULL) { continue; } if (!check_access(player, cmdp->perms)) { continue; } if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); listset_nametab(player, access_nametab, cmdp->perms, buff2, true); } } } // --------------------------------------------------------------------------- // list_cmdswitches: List switches for commands. // static void list_cmdswitches(dbref player) { UTF8 *buff = alloc_sbuf("list_cmdswitches"); { CMDENT_NO_ARG *cmdp; for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_ONE_ARG *cmdp; for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_ONE_ARG_CMDARG *cmdp; for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG *cmdp; for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_ARGV *cmdp; for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_CMDARG *cmdp; for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp; for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++) { if (cmdp->switches) { if (check_access(player, cmdp->perms)) { if (!(cmdp->perms & CF_DARK)) { mux_sprintf(buff, SBUF_SIZE, "%.60s:", cmdp->cmdname); display_nametab(player, cmdp->switches, buff, false); } } } } } free_sbuf(buff); } // --------------------------------------------------------------------------- // list_attraccess: List access to attributes. // NAMETAB attraccess_nametab[] = { {T("const"), 1, CA_PUBLIC, AF_CONST}, {T("dark"), 2, CA_WIZARD, AF_DARK}, {T("deleted"), 2, CA_WIZARD, AF_DELETED}, {T("god"), 1, CA_PUBLIC, AF_GOD}, {T("hidden"), 1, CA_WIZARD, AF_MDARK}, {T("ignore"), 2, CA_WIZARD, AF_NOCMD}, {T("internal"), 2, CA_WIZARD, AF_INTERNAL}, {T("is_lock"), 4, CA_PUBLIC, AF_IS_LOCK}, {T("locked"), 1, CA_PUBLIC, AF_LOCK}, {T("no_command"), 4, CA_PUBLIC, AF_NOPROG}, {T("no_inherit"), 4, CA_PUBLIC, AF_PRIVATE}, {T("private"), 1, CA_PUBLIC, AF_ODARK}, {T("regexp"), 1, CA_PUBLIC, AF_REGEXP}, {T("visual"), 1, CA_PUBLIC, AF_VISUAL}, {T("wizard"), 1, CA_PUBLIC, AF_WIZARD}, {(UTF8 *) NULL, 0, 0, 0} }; NAMETAB indiv_attraccess_nametab[] = { {T("case"), 1, CA_PUBLIC, AF_CASE}, {T("hidden"), 1, CA_WIZARD, AF_MDARK}, {T("html"), 2, CA_PUBLIC, AF_HTML}, {T("no_command"), 4, CA_PUBLIC, AF_NOPROG}, {T("no_inherit"), 4, CA_PUBLIC, AF_PRIVATE}, {T("no_name"), 4, CA_PUBLIC, AF_NONAME}, {T("no_parse"), 4, CA_PUBLIC, AF_NOPARSE}, {T("regexp"), 1, CA_PUBLIC, AF_REGEXP}, {T("trace"), 1, CA_PUBLIC, AF_TRACE}, {T("visual"), 1, CA_PUBLIC, AF_VISUAL}, {T("wizard"), 1, CA_WIZARD, AF_WIZARD}, {(UTF8 *) NULL, 0, 0, 0} }; static void list_attraccess(dbref player) { ATTR *ap; UTF8 *buff = alloc_sbuf("list_attraccess"); for (ap = AttrTable; ap->name; ap++) { if (bCanReadAttr(player, player, ap, false)) { mux_sprintf(buff, SBUF_SIZE, "%s:", ap->name); listset_nametab(player, attraccess_nametab, ap->flags, buff, true); } } free_sbuf(buff); } // --------------------------------------------------------------------------- // cf_access: Change command or switch permissions. // CF_HAND(cf_access) { UNUSED_PARAMETER(vp); CMDENT *cmdp; UTF8 *ap; bool set_switch; for (ap = str; *ap && !mux_isspace(*ap) && (*ap != '/'); ap++) ; if (*ap == '/') { set_switch = true; *ap++ = '\0'; } else { set_switch = false; if (*ap) { *ap++ = '\0'; } while (mux_isspace(*ap)) { ap++; } } cmdp = (CMDENT *)hashfindLEN(str, strlen((char *)str), &mudstate.command_htab); if (cmdp != NULL) { if (set_switch) { return cf_ntab_access((int *)cmdp->switches, ap, pExtra, nExtra, player, cmd); } else { return cf_modify_bits(&(cmdp->perms), ap, pExtra, nExtra, player, cmd); } } else { if (!mux_stricmp(str, T("home"))) { return cf_modify_bits(&(mudconf.restrict_home), ap, pExtra, nExtra, player, cmd); } cf_log_notfound(player, cmd, T("Command"), str); return -1; } } // --------------------------------------------------------------------------- // cf_acmd_access: Change command permissions for all attr-setting cmds. // CF_HAND(cf_acmd_access) { UNUSED_PARAMETER(vp); ATTR *ap; for (ap = AttrTable; ap->name; ap++) { size_t nBuffer; bool bValid; UTF8 *buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid); if (!bValid) { continue; } CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab); if (cmdp != NULL) { int save = cmdp->perms; int failure = cf_modify_bits(&(cmdp->perms), str, pExtra, nExtra, player, cmd); if (failure != 0) { cmdp->perms = save; return -1; } } } return 0; } // --------------------------------------------------------------------------- // cf_attr_access: Change access on an attribute. // CF_HAND(cf_attr_access) { UNUSED_PARAMETER(vp); ATTR *ap; UTF8 *sp; for (sp = str; *sp && !mux_isspace(*sp); sp++) { ; // Nothing } if (*sp) { *sp++ = '\0'; } while (mux_isspace(*sp)) { sp++; } ap = atr_str((UTF8 *)str); if (ap) { return cf_modify_bits(&(ap->flags), sp, pExtra, nExtra, player, cmd); } else { cf_log_notfound(player, cmd, T("Attribute"), str); return -1; } } // --------------------------------------------------------------------------- // cf_cmd_alias: Add a command alias. // CF_HAND(cf_cmd_alias) { UNUSED_PARAMETER(pExtra); UNUSED_PARAMETER(nExtra); UTF8 *ap; CMDENT *cmdp, *cmd2; NAMETAB *nt; MUX_STRTOK_STATE tts; mux_strtok_src(&tts, str); mux_strtok_ctl(&tts, T(" \t=,")); UTF8 *alias = mux_strtok_parse(&tts); UTF8 *orig = mux_strtok_parse(&tts); 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 *) hashfindLEN(orig, strlen((char *)orig), (CHashTable *) vp); if (cmdp == NULL || cmdp->switches == NULL) { cf_log_notfound(player, cmd, T("Command"), orig); return -1; } // Look up the switch // nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap); if (!nt) { cf_log_notfound(player, cmd, T("Switch"), ap); return -1; } if (!hashfindLEN(alias, strlen((char *)alias), (CHashTable *)vp)) { // Create the new command table entry. // cmd2 = (CMDENT *)MEMALLOC(sizeof(CMDENT)); ISOUTOFMEMORY(cmd2); cmd2->cmdname = StringClone(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; hashaddLEN(cmd2->cmdname, strlen((char *)cmd2->cmdname), cmd2, (CHashTable *) vp); } } else { // A normal (non-switch) alias // void *hp = hashfindLEN(orig, strlen((char *)orig), (CHashTable *) vp); if (hp == NULL) { cf_log_notfound(player, cmd, T("Entry"), orig); return -1; } hashaddLEN(alias, strlen((char *)alias), hp, (CHashTable *) vp); } return 0; } // --------------------------------------------------------------------------- // list_df_flags: List default flags at create time. // static void list_df_flags(dbref player) { FLAGSET fs; fs = mudconf.player_flags; fs.word[FLAG_WORD1] |= TYPE_PLAYER; UTF8 *playerb = decode_flags(player, &fs); fs = mudconf.room_flags; fs.word[FLAG_WORD1] |= TYPE_ROOM; UTF8 *roomb = decode_flags(player, &fs); fs = mudconf.exit_flags; fs.word[FLAG_WORD1] |= TYPE_EXIT; UTF8 *exitb = decode_flags(player, &fs); fs = mudconf.thing_flags; fs.word[FLAG_WORD1] |= TYPE_THING; UTF8 *thingb = decode_flags(player, &fs); fs = mudconf.robot_flags; fs.word[FLAG_WORD1] |= TYPE_PLAYER; UTF8 *robotb = decode_flags(player, &fs); UTF8 *buff = alloc_lbuf("list_df_flags"); mux_sprintf(buff, LBUF_SIZE, "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s", playerb, roomb, exitb, thingb, robotb); free_sbuf(playerb); free_sbuf(roomb); free_sbuf(exitb); free_sbuf(thingb); free_sbuf(robotb); raw_notify(player, buff); free_lbuf(buff); } // --------------------------------------------------------------------------- // list_costs: List the costs of things. // #define coin_name(s) (((s)==1) ? mudconf.one_coin : mudconf.many_coins) static void list_costs(dbref player) { UTF8 *buff = alloc_mbuf("list_costs"); if (mudconf.quotas) { mux_sprintf(buff, MBUF_SIZE, " 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) { mux_sprintf(buff, MBUF_SIZE, " 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) { mux_sprintf(buff, MBUF_SIZE, " 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) { mux_sprintf(buff, MBUF_SIZE, " 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) { int chance = 100; if (0 < mudconf.killguarantee) { chance = (mudconf.killmin * 100) / mudconf.killguarantee; } raw_notify(player, tprintf("Killing costs %d %s, with a %d%% chance of success.", mudconf.killmin, coin_name(mudconf.digcost), chance)); } else { int cost_surething; raw_notify(player, tprintf("Killing costs between %d and %d %s.", mudconf.killmin, mudconf.killmax, mudconf.many_coins)); if (0 < mudconf.killguarantee) { cost_surething = mudconf.killguarantee; } else { cost_surething = mudconf.killmin; } raw_notify(player, tprintf("You must spend %d %s to guarantee success.", cost_surething, coin_name(cost_surething))); } 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, T("The deposit is refunded when the command is run or canceled.")); } if (mudconf.sacfactor == 0) { mux_ltoa(mudconf.sacadjust, buff); } else if (mudconf.sacfactor == 1) { if (mudconf.sacadjust < 0) mux_sprintf(buff, MBUF_SIZE, " - %d", -mudconf.sacadjust); else if (mudconf.sacadjust > 0) mux_sprintf(buff, MBUF_SIZE, " + %d", mudconf.sacadjust); else mux_sprintf(buff, MBUF_SIZE, ""); } else { if (mudconf.sacadjust < 0) mux_sprintf(buff, MBUF_SIZE, "( / %d) - %d", mudconf.sacfactor, -mudconf.sacadjust); else if (mudconf.sacadjust > 0) mux_sprintf(buff, MBUF_SIZE, "( / %d) + %d", mudconf.sacfactor, mudconf.sacadjust); else mux_sprintf(buff, MBUF_SIZE, " / %d", mudconf.sacfactor); } raw_notify(player, tprintf("The value of an object is %s.", buff)); if (mudconf.clone_copy_cost) raw_notify(player, T("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 more game options from mudconf. // static const UTF8 *switchd[] = { T("/first"), T("/all") }; static const UTF8 *examd[] = { T("/brief"), T("/full") }; static const UTF8 *ed[] = { T("Disabled"), T("Enabled") }; static void list_options(dbref player) { UTF8 *buff; CLinearTimeAbsolute ltaNow; ltaNow.GetUTC(); if (mudconf.quotas) raw_notify(player, T("Building quotas are enforced.")); if (mudconf.name_spaces) raw_notify(player, T("Player names may contain spaces.")); else raw_notify(player, T("Player names may not contain spaces.")); if (!mudconf.robot_speak) raw_notify(player, T("Robots are not allowed to speak in public areas.")); if (mudconf.player_listen) raw_notify(player, T("The @Listen/@Ahear attribute set works on player objects.")); if (mudconf.ex_flags) raw_notify(player, T("The 'examine' command lists the flag names for the object's flags.")); if (!mudconf.quiet_look) raw_notify(player, T("The 'look' command shows visible attributes in addition to the description.")); if (mudconf.see_own_dark) raw_notify(player, T("The 'look' command lists DARK objects owned by you.")); if (!mudconf.dark_sleepers) raw_notify(player, T("The 'look' command shows disconnected players.")); if (mudconf.terse_look) raw_notify(player, T("The 'look' command obeys the TERSE flag.")); if (mudconf.trace_topdown) { raw_notify(player, T("Trace output is presented top-down (whole expression first, then sub-exprs).")); raw_notify(player, tprintf("Only %d lines of trace output are displayed.", mudconf.trace_limit)); } else { raw_notify(player, T("Trace output is presented bottom-up (subexpressions first).")); } if (!mudconf.quiet_whisper) raw_notify(player, T("The 'whisper' command lets others in the room with you know you whispered.")); if (mudconf.pemit_players) raw_notify(player, T("The '@pemit' command may be used to emit to faraway players.")); if (!mudconf.terse_contents) raw_notify(player, T("The TERSE flag suppresses listing the contents of a location.")); if (!mudconf.terse_exits) raw_notify(player, T("The TERSE flag suppresses listing obvious exits in a location.")); if (!mudconf.terse_movemsg) raw_notify(player, T("The TERSE flag suppresses enter/leave/succ/drop messages generated by moving.")); if (mudconf.pub_flags) raw_notify(player, T("The 'flags()' function will return the flags of any object.")); if (mudconf.read_rem_desc) raw_notify(player, T("The 'get()' function will return the description of faraway objects,")); if (mudconf.read_rem_name) raw_notify(player, T("The 'name()' function will return the name of faraway objects.")); raw_notify(player, tprintf("The default switch for the '@switch' command is %s.", switchd[mudconf.switch_df_all])); raw_notify(player, tprintf("The default switch for the 'examine' command is %s.", examd[mudconf.exam_public])); if (mudconf.sweep_dark) raw_notify(player, T("Players may @sweep dark locations.")); if (mudconf.fascist_tport) raw_notify(player, T("You may only @teleport out of locations that are JUMP_OK or that you control.")); raw_notify(player, tprintf("Players may have at most %d commands in the queue at one time.", mudconf.queuemax)); if (mudconf.match_mine) { if (mudconf.match_mine_pl) raw_notify(player, T("All objects search themselves for $-commands.")); else raw_notify(player, T("Objects other than players search themselves for $-commands.")); } if (!Wizard(player)) return; buff = alloc_mbuf("list_options"); raw_notify(player, tprintf("%d commands are run from the queue when there is no net activity.", mudconf.queue_chunk)); raw_notify(player, tprintf("%d commands are run from the queue when there is net activity.", mudconf.active_q_chunk)); if (mudconf.idle_wiz_dark) raw_notify(player, T("Wizards idle for longer than the default timeout are automatically set DARK.")); if (mudconf.safe_unowned) raw_notify(player, T("Objects not owned by you are automatically considered SAFE.")); if (mudconf.paranoid_alloc) raw_notify(player, T("The buffer pools are checked for consistency on each allocate or free.")); if (mudconf.cache_names) raw_notify(player, T("A separate name cache is used.")); #ifndef WIN32 if (mudconf.fork_dump) { raw_notify(player, T("Database dumps are performed by a fork()ed process.")); } #endif if (mudconf.max_players >= 0) raw_notify(player, tprintf("There may be at most %d players logged in at once.", mudconf.max_players)); if (mudconf.quotas) mux_sprintf(buff, MBUF_SIZE, " and %d quota", mudconf.start_quota); else *buff = '\0'; raw_notify(player, tprintf("New players are given %d %s to start with.", mudconf.paystart, mudconf.many_coins)); raw_notify(player, tprintf("Players are given %d %s each day they connect.", mudconf.paycheck, mudconf.many_coins)); raw_notify(player, tprintf("Earning money is difficult if you have more than %d %s.", mudconf.paylimit, mudconf.many_coins)); if (mudconf.payfind > 0) raw_notify(player, tprintf("Players have a 1 in %d chance of finding a %s each time they move.", mudconf.payfind, mudconf.one_coin)); raw_notify(player, tprintf("The head of the object freelist is #%d.", mudstate.freelist)); mux_sprintf(buff, MBUF_SIZE, "Intervals: Dump...%d Clean...%d Idlecheck...%d", mudconf.dump_interval, mudconf.check_interval, mudconf.idle_interval); raw_notify(player, buff); CLinearTimeDelta ltdDump = mudstate.dump_counter - ltaNow; CLinearTimeDelta ltdCheck = mudstate.check_counter - ltaNow; CLinearTimeDelta ltdIdle = mudstate.idle_counter - ltaNow; long lDump = ltdDump.ReturnSeconds(); long lCheck = ltdCheck.ReturnSeconds(); long lIdle = ltdIdle.ReturnSeconds(); mux_sprintf(buff, MBUF_SIZE, "Timers: Dump...%ld Clean...%ld Idlecheck...%ld", lDump, lCheck, lIdle); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Timeouts: Idle...%d Connect...%d Tries...%d", mudconf.idle_timeout, mudconf.conn_timeout, mudconf.retry_limit); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Scheduling: Timeslice...%s Max_Quota...%d Increment...%d", mudconf.timeslice.ReturnSecondsString(3),mudconf.cmd_quota_max, mudconf.cmd_quota_incr); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Spaces...%s Savefiles...%s", ed[mudconf.space_compress], ed[mudconf.compress_db]); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "New characters: Room...#%d Home...#%d DefaultHome...#%d Quota...%d", mudconf.start_room, mudconf.start_home, mudconf.default_home, mudconf.start_quota); raw_notify(player, buff); mux_sprintf(buff, MBUF_SIZE, "Misc: GuestChar...#%d IdleQueueChunk...%d ActiveQueueChunk...%d Master_room...#%d", mudconf.guest_char, mudconf.queue_chunk, mudconf.active_q_chunk, mudconf.master_room); raw_notify(player, buff); free_mbuf(buff); } // --------------------------------------------------------------------------- // list_vattrs: List user-defined attributes // static void list_vattrs(dbref player, UTF8 *s_mask) { bool wild_mtch = s_mask && s_mask[0] != '\0'; UTF8 *buff = alloc_lbuf("list_vattrs"); // If wild_match, then only list attributes that match wildcard(s) // UTF8 *p = tprintf("--- User-Defined Attributes %s---", wild_mtch ? "(wildmatched) " : ""); raw_notify(player, p); ATTR *va; int na; int wna = 0; for (va = vattr_first(), na = 0; va; va = vattr_next(va), na++) { if (!(va->flags & AF_DELETED)) { // We need to be extremely careful that s_mask is !null and valid // if (wild_mtch) { mudstate.wild_invk_ctr = 0; if (!quick_wild(s_mask, va->name)) { continue; } wna++; } mux_sprintf(buff, LBUF_SIZE, "%s(%d):", va->name, va->number); listset_nametab(player, attraccess_nametab, va->flags, buff, true); } } if (wild_mtch) { p = tprintf("%d attributes matched, %d attributes total, next=%d", wna, na, mudstate.attr_next); } else { p = tprintf("%d attributes, next=%d", na, mudstate.attr_next); } raw_notify(player, p); free_lbuf(buff); } size_t LeftJustifyString(UTF8 *field, size_t nWidth, const UTF8 *value) { size_t n = strlen((char *)value); if (n > nWidth) { n = nWidth; } memcpy(field, value, n); memset(field+n, ' ', nWidth-n); return nWidth; } size_t RightJustifyNumber(UTF8 *field, size_t nWidth, INT64 value, UTF8 chFill) { UTF8 buffer[I64BUF_SIZE]; size_t nReturn = 0; if (nWidth < sizeof(buffer)) { size_t n = mux_i64toa(value, buffer); if (n < sizeof(buffer)) { nReturn = n; if (n < nWidth) { memset(field, chFill, nWidth-n); field += nWidth-n; nReturn = nWidth; } memcpy(field, buffer, n); } } return nReturn; } // list_hashstats: List information from hash tables // static void list_hashstat(dbref player, const UTF8 *tab_name, CHashTable *htab) { unsigned int hashsize; int entries, max_scan; INT64 deletes, scans, hits, checks; htab->GetStats(&hashsize, &entries, &deletes, &scans, &hits, &checks, &max_scan); UTF8 buff[MBUF_SIZE]; UTF8 *p = buff; p += LeftJustifyString(p, 13, tab_name); *p++ = ' '; p += RightJustifyNumber(p, 4, hashsize, ' '); *p++ = ' '; p += RightJustifyNumber(p, 6, entries, ' '); *p++ = ' '; p += RightJustifyNumber(p, 7, deletes, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, scans, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, hits, ' '); *p++ = ' '; p += RightJustifyNumber(p, 13, checks, ' '); *p++ = ' '; p += RightJustifyNumber(p, 4, max_scan, ' '); *p = '\0'; raw_notify(player, buff); } static void list_hashstats(dbref player) { raw_notify(player, T("Hash Stats Size Num Del Lookups Hits Probes Long")); list_hashstat(player, T("Commands"), &mudstate.command_htab); list_hashstat(player, T("Logout Cmds"), &mudstate.logout_cmd_htab); list_hashstat(player, T("Functions"), &mudstate.func_htab); list_hashstat(player, T("Flags"), &mudstate.flags_htab); list_hashstat(player, T("Powers"), &mudstate.powers_htab); list_hashstat(player, T("Attr Names"), &mudstate.attr_name_htab); list_hashstat(player, T("Vattr Names"), &mudstate.vattr_name_htab); list_hashstat(player, T("Player Names"), &mudstate.player_htab); list_hashstat(player, T("Net Descr."), &mudstate.desc_htab); list_hashstat(player, T("Fwd. lists"), &mudstate.fwdlist_htab); list_hashstat(player, T("Excl. $-cmds"), &mudstate.parent_htab); list_hashstat(player, T("Mail Messages"), &mudstate.mail_htab); list_hashstat(player, T("Channel Names"), &mudstate.channel_htab); #if !defined(MEMORY_BASED) list_hashstat(player, T("Attr. Cache"), &mudstate.acache_htab); #endif // MEMORY_BASED for (int i = 0; i < mudstate.nHelpDesc; i++) { list_hashstat(player, mudstate.aHelpDesc[i].pBaseFilename, mudstate.aHelpDesc[i].ht); } } // --------------------------------------------------------------------------- // list_db_stats: Get useful info from the DB layer about hash stats, etc. // static void list_db_stats(dbref player) { #ifdef MEMORY_BASED raw_notify(player, T("Database is memory based.")); #else // MEMORY_BASED CLinearTimeAbsolute lsaNow; lsaNow.GetUTC(); CLinearTimeDelta ltd = lsaNow - cs_ltime; raw_notify(player, tprintf("DB Cache Stats Writes Reads (over %d seconds)", ltd.ReturnSeconds())); raw_notify(player, tprintf("Calls %12d%12d", cs_writes, cs_reads)); raw_notify(player, tprintf("\nDeletes %12d", cs_dels)); raw_notify(player, tprintf("Syncs %12d", cs_syncs)); raw_notify(player, tprintf("I/O %12d%12d", cs_dbwrites, cs_dbreads)); raw_notify(player, tprintf("Cache Hits %12d%12d", cs_whits, cs_rhits)); #endif // MEMORY_BASED } // --------------------------------------------------------------------------- // list_process: List local resource usage stats of the mux process. // Adapted from code by Claudius@PythonMUCK, // posted to the net by Howard/Dark_Lord. // static void list_process(dbref player) { #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 // HAVE_GETRUSAGE #ifdef WIN32 #ifdef HAVE_GETRUSAGE int maxfds = FD_SETSIZE; #endif // HAVE_GETRUSAGE #else // WIN32 #ifdef HAVE_GETDTABLESIZE int maxfds = getdtablesize(); #else // HAVE_GETDTABLESIZE int maxfds = sysconf(_SC_OPEN_MAX); #endif // HAVE_GETDTABLESIZE int psize = getpagesize(); #endif // WIN32 // Go display everything // #ifdef WIN32 raw_notify(player, tprintf("Process ID: %10d", game_pid)); #else // WIN32 raw_notify(player, tprintf("Process ID: %10d %10d bytes per page", game_pid, psize)); #endif // WIN32 #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 // HAVE_GETRUSAGE } //---------------------------------------------------------------------------- // list_rlevels // #ifdef REALITY_LVLS static void list_rlevels(dbref player) { int i; raw_notify(player, T("Reality levels:")); for (i = 0; i < mudconf.no_levels; ++i) { raw_notify(player, tprintf(" Level: %-20.20s Value: 0x%08x Desc: %s", mudconf.reality_level[i].name, mudconf.reality_level[i].value, mudconf.reality_level[i].attr)); } raw_notify(player, T("--Completed.")); } #endif // REALITY_LVLS // --------------------------------------------------------------------------- // 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 #define LIST_PROCESS 21 #define LIST_BADNAMES 22 #define LIST_RESOURCES 23 #define LIST_GUESTS 24 #ifdef REALITY_LVLS #define LIST_RLEVELS 25 #endif NAMETAB list_names[] = { {T("allocations"), 2, CA_WIZARD, LIST_ALLOCATOR}, {T("attr_permissions"), 5, CA_WIZARD, LIST_ATTRPERMS}, {T("attributes"), 2, CA_PUBLIC, LIST_ATTRIBUTES}, {T("bad_names"), 2, CA_WIZARD, LIST_BADNAMES}, {T("buffers"), 2, CA_WIZARD, LIST_BUFTRACE}, {T("commands"), 3, CA_PUBLIC, LIST_COMMANDS}, {T("config_permissions"), 3, CA_GOD, LIST_CONF_PERMS}, {T("costs"), 3, CA_PUBLIC, LIST_COSTS}, {T("db_stats"), 2, CA_WIZARD, LIST_DB_STATS}, {T("default_flags"), 1, CA_PUBLIC, LIST_DF_FLAGS}, {T("flags"), 2, CA_PUBLIC, LIST_FLAGS}, {T("functions"), 2, CA_PUBLIC, LIST_FUNCTIONS}, {T("globals"), 2, CA_WIZARD, LIST_GLOBALS}, {T("hashstats"), 1, CA_WIZARD, LIST_HASHSTATS}, {T("logging"), 1, CA_GOD, LIST_LOGGING}, {T("options"), 1, CA_PUBLIC, LIST_OPTIONS}, {T("permissions"), 2, CA_WIZARD, LIST_PERMS}, {T("powers"), 2, CA_WIZARD, LIST_POWERS}, {T("process"), 2, CA_WIZARD, LIST_PROCESS}, {T("resources"), 1, CA_WIZARD, LIST_RESOURCES}, {T("site_information"), 2, CA_WIZARD, LIST_SITEINFO}, {T("switches"), 2, CA_PUBLIC, LIST_SWITCHES}, {T("user_attributes"), 1, CA_WIZARD, LIST_VATTRS}, {T("guests"), 2, CA_WIZARD, LIST_GUESTS}, #ifdef REALITY_LVLS {T("rlevels"), 3, CA_PUBLIC, LIST_RLEVELS}, #endif {(UTF8 *) NULL, 0, 0, 0} }; void do_list(dbref executor, dbref caller, dbref enactor, int eval, int extra, UTF8 *arg) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); UNUSED_PARAMETER(extra); MUX_STRTOK_STATE tts; mux_strtok_src(&tts, arg); mux_strtok_ctl(&tts, T(" \t=,")); UTF8 *s_option = mux_strtok_parse(&tts); int flagvalue; if (!search_nametab(executor, list_names, arg, &flagvalue)) { if (flagvalue == -1) { display_nametab(executor, list_names, T("Unknown option. Use one of:"), true); } else { notify(executor, NOPERM_MESSAGE); } return; } switch (flagvalue) { case LIST_ALLOCATOR: list_bufstats(executor); break; case LIST_BUFTRACE: list_buftrace(executor); break; case LIST_ATTRIBUTES: list_attrtable(executor); break; case LIST_COMMANDS: list_cmdtable(executor); break; case LIST_SWITCHES: list_cmdswitches(executor); break; case LIST_COSTS: list_costs(executor); break; case LIST_OPTIONS: list_options(executor); break; case LIST_HASHSTATS: list_hashstats(executor); break; case LIST_SITEINFO: list_siteinfo(executor); break; case LIST_FLAGS: display_flagtab(executor); break; case LIST_FUNCTIONS: list_functable(executor); break; case LIST_GLOBALS: interp_nametab(executor, enable_names, mudconf.control_flags, T("Global parameters:"), T("enabled"), T("disabled")); break; case LIST_DF_FLAGS: list_df_flags(executor); break; case LIST_PERMS: list_cmdaccess(executor); break; case LIST_CONF_PERMS: list_cf_access(executor); break; case LIST_POWERS: display_powertab(executor); break; case LIST_ATTRPERMS: list_attraccess(executor); break; case LIST_VATTRS: s_option = mux_strtok_parse(&tts); list_vattrs(executor, s_option); break; case LIST_LOGGING: interp_nametab(executor, logoptions_nametab, mudconf.log_options, T("Events Logged:"), T("enabled"), T("disabled")); interp_nametab(executor, logdata_nametab, mudconf.log_info, T("Information Logged:"), T("yes"), T("no")); break; case LIST_DB_STATS: list_db_stats(executor); break; case LIST_PROCESS: list_process(executor); break; case LIST_BADNAMES: badname_list(executor, T("Disallowed names:")); break; case LIST_RESOURCES: list_system_resources(executor); break; case LIST_GUESTS: Guest.ListAll(executor); break; #ifdef REALITY_LVLS case LIST_RLEVELS: list_rlevels(executor); break; #endif } } void do_assert(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *arg1, UTF8 *command, UTF8 *cargs[], int ncargs) { UNUSED_PARAMETER(key); if (!xlate(arg1)) { break_called = true; if ( NULL != command && '\0' != command[0]) { CLinearTimeAbsolute lta; wait_que(executor, caller, enactor, eval, false, lta, NOTHING, 0, command, ncargs, cargs, mudstate.global_regs); } } } void do_break(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *arg1, UTF8 *command, UTF8 *cargs[], int ncargs) { UNUSED_PARAMETER(key); if (xlate(arg1)) { break_called = true; if ( NULL != command && '\0' != command[0]) { CLinearTimeAbsolute lta; wait_que(executor, caller, enactor, eval, false, lta, NOTHING, 0, command, ncargs, cargs, mudstate.global_regs); } } } // do_icmd: Ignore or disable commands on a per-player or per-room basis. // Used with express permission of RhostMUSH developers. // Bludgeoned into MUX by Jake Nelson 7/2002. // void do_icmd(dbref player, dbref cause, dbref enactor, int eval, int key, UTF8 *name, UTF8 *args[], int nargs) { UNUSED_PARAMETER(eval); UNUSED_PARAMETER(cause); UNUSED_PARAMETER(enactor); CMDENT *cmdp; UTF8 *buff1, *pt1, *pt2, *pt3, *atrpt, *pt5; int x, aflags; size_t y; dbref target = NOTHING, aowner, zone; bool bFound, set; int loc_set = -1; if ( key == ICMD_IROOM || key == ICMD_DROOM || key == ICMD_CROOM || key == ICMD_LROOM || key == ICMD_LALLROOM) { if (key != ICMD_LALLROOM) { target = match_thing_quiet(player, name); } if ( key != ICMD_LALLROOM && ( !Good_obj(target) || !( isRoom(target) || isThing(target)))) { notify(player, T("@icmd: Bad Location.")); return; } if (key == ICMD_CROOM) { atr_clr(target, A_CMDCHECK); notify(player, T("@icmd: Location - All cleared.")); notify(player, T("@icmd: Done.")); return; } else if (key == ICMD_LROOM) { atrpt = atr_get("do_icmd.4060", target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player,T("Location CmdCheck attribute is:")); notify(player, atrpt); } else { notify(player, T("Location CmdCheck attribute is empty.")); } free_lbuf(atrpt); notify(player, T("@icmd: Done.")); return; } else if (key == ICMD_LALLROOM) { target = Location(player); if ( !Good_obj(target) || Going(target) || isPlayer(target)) { notify(player, T("@icmd: Bad Location.")); return; } notify(player, T("Scanning all locations and zones from your current location:")); bFound = false; atrpt = atr_get("do_icmd.4086", target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player, tprintf("%c --- At %s(#%d) :", (Zone(target) == target ? '*' : ' '), Name(target), target)); notify(player, atrpt); bFound = true; } free_lbuf(atrpt); if (Zone(target) != target) { zone = Zone(target); if ( Good_obj(zone) && ( isRoom(zone) || isThing(zone))) { atrpt = atr_get("do_icmd.4102", zone, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player,tprintf("%c z-- At %s(#%d) :", '*', Name(zone), zone)); notify(player, atrpt); bFound = true; } free_lbuf(atrpt); } } if (!bFound) { notify(player, T("@icmd: Location - No icmd's found at current location.")); } notify(player, T("@icmd: Done.")); return; } else if (key == ICMD_IROOM) { loc_set = 1; } else if (key == ICMD_DROOM) { loc_set = 0; } } if (loc_set == -1 ) { target = lookup_player(player, name, false); if (!Good_obj(target) || God(target)) { notify(player, T("@icmd: Bad player.")); return; } if ((key == ICMD_OFF) || (key == ICMD_CLEAR)) { s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK); if (key == ICMD_CLEAR) { atr_clr(target, A_CMDCHECK); } notify(player, T("@icmd: All cleared.")); notify(player, T("@icmd: Done.")); return; } else if (key == ICMD_ON) { s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK); notify(player, T("@icmd: Activated.")); notify(player, T("@icmd: Done.")); return; } else if (key == ICMD_CHECK) { if (CmdCheck(target)) { notify(player, T("CmdCheck is active.")); } else { notify(player, T("CmdCheck is not active.")); } atrpt = atr_get("do_icmd.4166", target, A_CMDCHECK, &aowner, &aflags); if (*atrpt) { notify(player, T("CmdCheck attribute is:")); notify(player, atrpt); } else { notify(player, T("CmdCheck attribute is empty.")); } free_lbuf(atrpt); notify(player, T("@icmd: Done.")); return; } } else { key = loc_set; } const UTF8 *message = T(""); buff1 = alloc_lbuf("do_icmd"); for (x = 0; x < nargs; x++) { pt1 = args[x]; pt2 = buff1; while ( *pt1 && pt2 < buff1 + LBUF_SIZE) { *pt2++ = mux_tolower_ascii(*pt1++); } *pt2 = '\0'; if ( buff1[0] == '!' && buff1[1] != '\0') { pt1 = buff1 + 1; set = false; } else { pt1 = buff1; set = true; } if (*pt1) { bool bHome, bColon = false; if (!string_compare(pt1, T("home"))) { bHome = true; cmdp = NULL; } else { bHome = false; cmdp = (CMDENT *) hashfindLEN(pt1, strlen((char *)pt1), &mudstate.command_htab); } if (cmdp || bHome) { atrpt = atr_get("do_icmd.4223", target, A_CMDCHECK, &aowner, &aflags); if (cmdp) { aflags = (int)strlen((char *)cmdp->cmdname); bColon = ( aflags == 1 && *(cmdp->cmdname) == ':'); } else { aflags = 4; } pt5 = atrpt; while (pt1) { if (cmdp) { if (bColon) { pt1 = (UTF8 *)strstr((char *)pt5, "::"); if (pt1) { pt1++; } } else { pt1 = (UTF8 *)strstr((char *)pt5, (char *)cmdp->cmdname); } } else { pt1 = (UTF8 *)strstr((char *)pt5, "home"); } if ( pt1 && (pt1 > atrpt) && (*(pt1 - 1) == ':') && ( mux_isspace(*(pt1 + aflags)) || !*(pt1 + aflags))) { break; } else if (pt1) { if (*pt1) { pt5 = pt1 + 1; } else { pt1 = NULL; break; } } } if (set) { if (!pt1) { if (cmdp) { pt3 = tprintf(" %d:%s", key + 1, cmdp->cmdname); } else { pt3 = tprintf(" %d:home", key + 1); } size_t natrpt = strlen((char *)atrpt); size_t npt3 = strlen((char *)pt3); if ((natrpt + npt3) < LBUF_SIZE - 1) { mux_strncpy(atrpt + natrpt, pt3, LBUF_SIZE-natrpt-1); atr_add_raw(target, A_CMDCHECK, atrpt); if ( loc_set == -1 ) { s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK); } message = T("Set"); } } else { message = T("Command already present"); } } else { if (pt1) { pt2 = pt1 - 1; while ((pt2 > atrpt) && !mux_isspace(*pt2)) { pt2--; } y = pt2 - atrpt + 1; // Save the char that'll be nulled by mux_strncpy. // (Even though it may be unneeded by this point.) UTF8 cSave = buff1[y]; mux_strncpy(buff1, atrpt, y); buff1[y] = cSave; if (y == 1) { *atrpt = '\0'; } *(atrpt + y) = '\0'; pt2 = pt1 + aflags; if (*pt2) { while (*pt2 && mux_isspace(*pt2)) { pt2++; } if (*pt2) { size_t natrpt = strlen((char *)atrpt); mux_strncpy(atrpt + natrpt, pt2, LBUF_SIZE-natrpt-1); } } if ((y > 1) && !*pt2) { pt2 = atrpt + y; while ((pt2 > atrpt) && mux_isspace(*pt2)) { pt2--; } *(pt2 + 1) = '\0'; } if ((y == 1) && !*pt2) { atr_clr(target, A_CMDCHECK); if (loc_set == -1) { s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK); } message = T("Cleared"); } else { atr_add_raw(target, A_CMDCHECK, atrpt); message = T("Cleared"); } } else { message = T("Command not present"); } } free_lbuf(atrpt); } else { message = T("Bad command"); } notify(player, tprintf("@icmd:%s %s.",(loc_set == -1) ? T("") : T(" Location -"), message)); } } free_lbuf(buff1); notify(player,T("@icmd: Done.")); } // do_train: show someone else in the same room what code you're entering and the result // From RhostMUSH, changed to use notify_all_from_inside. // void do_train(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *string) { UNUSED_PARAMETER(key); if (0 < mudstate.train_nest_lev) { notify(executor, T("Train cannot be used to teach command, train.")); return; } mudstate.train_nest_lev++; dbref loc = Location(executor); if (!Good_obj(loc)) { notify(executor, T("Bad location.")); mudstate.train_nest_lev--; return; } if ( !string || !*string) { notify(executor, T("Train requires an argument.")); mudstate.train_nest_lev--; return; } notify_all_from_inside(loc, executor, tprintf("%s types -=> %s", Moniker(executor), string)); process_command(executor, caller, enactor, eval, true, string, NULL, 0); mudstate.train_nest_lev--; } void do_moniker(dbref executor, dbref caller, dbref enactor, int key, int nfargs, UTF8 *name, UTF8 *instr) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(key); UNUSED_PARAMETER(nfargs); dbref thing = match_thing(executor, name); if (!Good_obj(thing)) { return; } if (!Controls(executor, thing)) { notify(executor, NOPERM_MESSAGE); return; } if ( instr == NULL || instr[0] == '\0') { notify_quiet(executor, T("Moniker cleared.")); s_Moniker(thing, NULL); } else { s_Moniker(thing, instr); if ( !Quiet(executor) && !Quiet(thing)) { notify_quiet(executor, T("Moniker set.")); } } set_modified(thing); } // do_hook: run softcode before or after running a hardcode command, or // softcode access. Original idea from TinyMUSH 3, code from RhostMUSH. // Used with express permission of RhostMUSH developers. // Bludgeoned into MUX by Jake Nelson 7/2002. // static void show_hook(UTF8 *bf, UTF8 *bfptr, int key) { if (key & HOOK_BEFORE) safe_str(T("before "), bf, &bfptr); if (key & HOOK_AFTER) safe_str(T("after "), bf, &bfptr); if (key & HOOK_PERMIT) safe_str(T("permit "), bf, &bfptr); if (key & HOOK_IGNORE) safe_str(T("ignore "), bf, &bfptr); if (key & HOOK_IGSWITCH) safe_str(T("igswitch "), bf, &bfptr); if (key & HOOK_AFAIL) safe_str(T("afail "), bf, &bfptr); *bfptr = '\0'; } static void hook_loop(dbref executor, CMDENT *cmdp, UTF8 *s_ptr, UTF8 *s_ptrbuff) { show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); const char *pFmt = "%-32.32s | %s"; const UTF8 *pCmd = cmdp->cmdname; if ( pCmd[0] != '\0' && pCmd[1] == '\0') { switch (pCmd[0]) { case '"': pFmt = "S %-30.30s | %s"; pCmd = T("('\"' hook on 'say')"); break; case ':': pFmt = "P %-30.30s | %s"; pCmd = T("(':' hook on 'pose')"); break; case ';': pFmt = "P %-30.30s | %s"; pCmd = T("(';' hook on 'pose')"); break; case '\\': pFmt = "E %-30.30s | %s"; pCmd = T("('\\\\' hook on '@emit')"); break; case '#': pFmt = "F %-30.30s | %s"; pCmd = T("('#' hook on '@force')"); break; case '&': pFmt = "V %-30.30s | %s"; pCmd = T("('&' hook on '@set')"); break; case '-': pFmt = "M %-30.30s | %s"; pCmd = T("('-' hook on '@mail')"); break; case '~': pFmt = "M %-30.30s | %s"; pCmd = T("('~' hook on '@mail')"); break; } } notify(executor, tprintf(pFmt, pCmd, s_ptrbuff)); } void do_hook(dbref executor, dbref caller, dbref enactor, int eval, int key, UTF8 *name) { UNUSED_PARAMETER(caller); UNUSED_PARAMETER(enactor); UNUSED_PARAMETER(eval); bool negate, found; UTF8 *s_ptr, *s_ptrbuff, *cbuff, *p; const UTF8 *q; CMDENT *cmdp = (CMDENT *)NULL; if ( ( key && !(key & HOOK_LIST)) || ( ( !key || (key & HOOK_LIST)) && *name)) { cmdp = (CMDENT *)hashfindLEN(name, strlen((char *)name), &mudstate.command_htab); if (!cmdp) { notify(executor, T("@hook: Non-existent command name given.")); return; } } if ( (key & HOOK_CLEAR) && (key & HOOK_LIST)) { notify(executor, T("@hook: Incompatible switches.")); return; } if (key & HOOK_CLEAR) { negate = true; key = key & ~HOOK_CLEAR; key = key & ~SW_MULTIPLE; } else { negate = false; } if (key & (HOOK_BEFORE|HOOK_AFTER|HOOK_PERMIT|HOOK_IGNORE|HOOK_IGSWITCH|HOOK_AFAIL)) { if (negate) { cmdp->hookmask = cmdp->hookmask & ~key; } else { cmdp->hookmask = cmdp->hookmask | key; } if (cmdp->hookmask) { s_ptr = s_ptrbuff = alloc_lbuf("@hook"); show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("@hook: New mask for '%s' -> %s", cmdp->cmdname, s_ptrbuff)); free_lbuf(s_ptrbuff); } else { notify(executor, tprintf("@hook: New mask for '%s' is empty.", cmdp->cmdname)); } } if ( (key & HOOK_LIST) || !key) { if (cmdp) { if (cmdp->hookmask) { s_ptr = s_ptrbuff = alloc_lbuf("@hook"); show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("@hook: Mask for hashed command '%s' -> %s", cmdp->cmdname, s_ptrbuff)); free_lbuf(s_ptrbuff); } else { notify(executor, tprintf("@hook: Mask for hashed command '%s' is empty.", cmdp->cmdname)); } } else { notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("%-32s | %s", "Built-in Command", "Hook Mask Values")); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); found = false; s_ptr = s_ptrbuff = alloc_lbuf("@hook"); { CMDENT_NO_ARG *cmdp2; for (cmdp2 = command_table_no_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_ONE_ARG *cmdp2; for (cmdp2 = command_table_one_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_ONE_ARG_CMDARG *cmdp2; for (cmdp2 = command_table_one_arg_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG *cmdp2; for (cmdp2 = command_table_two_arg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_ARGV *cmdp2; for (cmdp2 = command_table_two_arg_argv; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_CMDARG *cmdp2; for (cmdp2 = command_table_two_arg_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } { CMDENT_TWO_ARG_ARGV_CMDARG *cmdp2; for (cmdp2 = command_table_two_arg_argv_cmdarg; cmdp2->cmdname; cmdp2++) { s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; if (cmdp2->hookmask) { found = true; hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff); } } } if (!found) { notify(executor, tprintf("%26s -- No @hooks defined --", " ")); } found = false; /* We need to search the attribute table as well */ notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("%-32s | %s", "Built-in Attribute", "Hook Mask Values")); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); cbuff = alloc_sbuf("cbuff_hook"); for (ATTR *ap = AttrTable; ap->name; ap++) { if (ap->flags & AF_NOCMD) { continue; } s_ptrbuff[0] = '\0'; s_ptr = s_ptrbuff; p = cbuff; safe_sb_chr('@', cbuff, &p); for (q = ap->name; *q; q++) { safe_sb_chr(mux_tolower_ascii(*q), cbuff, &p); } *p = '\0'; size_t ncbuff = p - cbuff; cmdp = (CMDENT *)hashfindLEN(cbuff, ncbuff, &mudstate.command_htab); if ( cmdp && cmdp->hookmask) { found = true; show_hook(s_ptrbuff, s_ptr, cmdp->hookmask); notify(executor, tprintf("%-32.32s | %s", cmdp->cmdname, s_ptrbuff)); } } free_sbuf(cbuff); if (!found) { notify(executor, tprintf("%26s -- No @hooks defined --", " ")); } free_lbuf(s_ptrbuff); notify(executor, tprintf("%.32s-+-%s", "--------------------------------", "--------------------------------------------")); notify(executor, tprintf("The hook object is currently: #%d (%s)", mudconf.hook_obj, ( ( Good_obj(mudconf.hook_obj) && !Going(mudconf.hook_obj)) ? "VALID" : "INVALID"))); } } }