mux/src/command.cpp

Go to the documentation of this file.
00001 // command.cpp -- command parser and support routines.
00002 //
00003 // $Id: command.cpp,v 1.81 2007/04/14 04:57:05 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include "ansi.h"
00012 #include "attrs.h"
00013 #include "command.h"
00014 #include "comsys.h"
00015 #include "functions.h"
00016 #include "mguests.h"
00017 #include "powers.h"
00018 #include "vattr.h"
00019 #include "help.h"
00020 #include "pcre.h"
00021 
00022 // Switch tables for the various commands.
00023 //
00024 static NAMETAB attrib_sw[] =
00025 {
00026     {"access",          1,  CA_GOD,     ATTRIB_ACCESS},
00027     {"delete",          1,  CA_GOD,     ATTRIB_DELETE},
00028     {"rename",          1,  CA_GOD,     ATTRIB_RENAME},
00029     { NULL,             0,       0,     0}
00030 };
00031 
00032 static NAMETAB boot_sw[] =
00033 {
00034     {"port",            1,  CA_WIZARD,  BOOT_PORT|SW_MULTIPLE},
00035     {"quiet",           1,  CA_WIZARD,  BOOT_QUIET|SW_MULTIPLE},
00036     { NULL,             0,          0,  0}
00037 };
00038 
00039 static NAMETAB cboot_sw[] =
00040 {
00041     {"quiet",           1,  CA_PUBLIC,  CBOOT_QUIET},
00042     { NULL,             0,          0,  0}
00043 };
00044 
00045 static NAMETAB comtitle_sw[] =
00046 {
00047     {"off",             2,  CA_PUBLIC,  COMTITLE_OFF},
00048     {"on",              2,  CA_PUBLIC,  COMTITLE_ON},
00049     { NULL,             0,          0,  0}
00050 };
00051 
00052 static NAMETAB cemit_sw[] =
00053 {
00054     {"noheader",        1,  CA_PUBLIC,  CEMIT_NOHEADER},
00055     { NULL,             0,          0,  0}
00056 };
00057 
00058 static NAMETAB clone_sw[] =
00059 {
00060     {"cost",            1,  CA_PUBLIC,  CLONE_SET_COST},
00061     {"inherit",         3,  CA_PUBLIC,  CLONE_INHERIT|SW_MULTIPLE},
00062     {"inventory",       3,  CA_PUBLIC,  CLONE_INVENTORY},
00063     {"location",        1,  CA_PUBLIC,  CLONE_LOCATION},
00064     {"parent",          2,  CA_PUBLIC,  CLONE_FROM_PARENT|SW_MULTIPLE},
00065     {"preserve",        2,  CA_WIZARD,  CLONE_PRESERVE|SW_MULTIPLE},
00066     { NULL,             0,          0,  0}
00067 };
00068 
00069 static NAMETAB clist_sw[] =
00070 {
00071     {"full",            0,  CA_PUBLIC,  CLIST_FULL},
00072     {"headers",         0,  CA_PUBLIC,  CLIST_HEADERS},
00073     { NULL,             0,          0,  0}
00074 };
00075 
00076 static NAMETAB cset_sw[] =
00077 {
00078     {"anon",            1,  CA_PUBLIC,  CSET_SPOOF},
00079     {"header",          1,  CA_PUBLIC,  CSET_HEADER},
00080     {"list",            2,  CA_PUBLIC,  CSET_LIST},
00081     {"log" ,            3,  CA_PUBLIC,  CSET_LOG},
00082     {"loud",            3,  CA_PUBLIC,  CSET_LOUD},
00083     {"mute",            1,  CA_PUBLIC,  CSET_QUIET},
00084     {"nospoof",         1,  CA_PUBLIC,  CSET_NOSPOOF},
00085     {"object",          1,  CA_PUBLIC,  CSET_OBJECT},
00086     {"private",         2,  CA_PUBLIC,  CSET_PRIVATE},
00087     {"public",          2,  CA_PUBLIC,  CSET_PUBLIC},
00088     {"quiet",           1,  CA_PUBLIC,  CSET_QUIET},
00089     {"spoof",           1,  CA_PUBLIC,  CSET_SPOOF},
00090     { NULL,             0,          0,  0}
00091 };
00092 
00093 static NAMETAB dbck_sw[] =
00094 {
00095     {"full",            1,  CA_WIZARD,  DBCK_FULL},
00096     { NULL,             0,          0,  0}
00097 };
00098 
00099 static NAMETAB decomp_sw[] =
00100 {
00101     {"dbref",           1,  CA_PUBLIC,  DECOMP_DBREF},
00102     { NULL,             0,           0, 0}
00103 };
00104 
00105 static NAMETAB destroy_sw[] =
00106 {
00107     {"instant",         4,  CA_PUBLIC,  DEST_INSTANT|SW_MULTIPLE},
00108     {"override",        8,  CA_PUBLIC,  DEST_OVERRIDE|SW_MULTIPLE},
00109     { NULL,             0,          0,  0}
00110 };
00111 
00112 static NAMETAB dig_sw[] =
00113 {
00114     {"teleport",        1,  CA_PUBLIC,  DIG_TELEPORT},
00115     { NULL,             0,          0,  0}
00116 };
00117 
00118 static NAMETAB doing_sw[] =
00119 {
00120     {"header",          1,  CA_PUBLIC,  DOING_HEADER},
00121     {"message",         1,  CA_PUBLIC,  DOING_MESSAGE},
00122     {"poll",            1,  CA_PUBLIC,  DOING_POLL},
00123     {"quiet",           1,  CA_PUBLIC,  DOING_QUIET|SW_MULTIPLE},
00124     {"unique",          1,  CA_PUBLIC,  DOING_UNIQUE},
00125     { NULL,             0,          0,  0}
00126 };
00127 
00128 static NAMETAB dolist_sw[] =
00129 {
00130     {"delimit",         1,  CA_PUBLIC,  DOLIST_DELIMIT},
00131     {"notify",          1,  CA_PUBLIC,  DOLIST_NOTIFY|SW_MULTIPLE},
00132     {"space",           1,  CA_PUBLIC,  DOLIST_SPACE},
00133     { NULL,             0,          0,  0}
00134 };
00135 
00136 #ifdef QUERY_SLAVE
00137 static NAMETAB query_sw[] =
00138 {
00139     {"sql",             1,  CA_PUBLIC,  QUERY_SQL},
00140     { NULL,             0,          0,  0}
00141 };
00142 #endif // QUERY_SLAVE
00143 
00144 static NAMETAB drop_sw[] =
00145 {
00146     {"quiet",           1,  CA_PUBLIC,  DROP_QUIET},
00147     { NULL,             0,          0,  0}
00148 };
00149 
00150 static NAMETAB dump_sw[] =
00151 {
00152     {"flatfile",        1,  CA_WIZARD,  DUMP_FLATFILE|SW_MULTIPLE},
00153     {"structure",       1,  CA_WIZARD,  DUMP_STRUCT|SW_MULTIPLE},
00154     {"text",            1,  CA_WIZARD,  DUMP_TEXT|SW_MULTIPLE},
00155     { NULL,             0,          0,  0}
00156 };
00157 
00158 static NAMETAB emit_sw[] =
00159 {
00160     {"here",            2,  CA_PUBLIC,  SAY_HERE|SW_MULTIPLE},
00161     {"html",            2,  CA_PUBLIC,  SAY_HTML|SW_MULTIPLE},
00162     {"room",            1,  CA_PUBLIC,  SAY_ROOM|SW_MULTIPLE},
00163     { NULL,             0,          0,  0}
00164 };
00165 
00166 static NAMETAB enter_sw[] =
00167 {
00168     {"quiet",           1,  CA_PUBLIC,  MOVE_QUIET},
00169     { NULL,             0,          0,  0}
00170 };
00171 
00172 static NAMETAB examine_sw[] =
00173 {
00174     {"brief",           1,  CA_PUBLIC,  EXAM_BRIEF},
00175     {"debug",           1,  CA_WIZARD,  EXAM_DEBUG},
00176     {"full",            1,  CA_PUBLIC,  EXAM_LONG},
00177     {"parent",          1,  CA_PUBLIC,  EXAM_PARENT},
00178     { NULL,             0,          0,  0}
00179 };
00180 
00181 static NAMETAB femit_sw[] =
00182 {
00183     {"here",            1,  CA_PUBLIC,  PEMIT_HERE|SW_MULTIPLE},
00184     {"room",            1,  CA_PUBLIC,  PEMIT_ROOM|SW_MULTIPLE},
00185     { NULL,             0,          0,  0}
00186 };
00187 
00188 static NAMETAB fixdb_sw[] =
00189 {
00190     {"contents",        1,     CA_GOD,  FIXDB_CON},
00191     {"exits",           1,     CA_GOD,  FIXDB_EXITS},
00192     {"location",        1,     CA_GOD,  FIXDB_LOC},
00193     {"next",            1,     CA_GOD,  FIXDB_NEXT},
00194     {"owner",           1,     CA_GOD,  FIXDB_OWNER},
00195     {"pennies",         1,     CA_GOD,  FIXDB_PENNIES},
00196     {"rename",          1,     CA_GOD,  FIXDB_NAME},
00197     { NULL,             0,          0,  0}
00198 };
00199 
00200 static NAMETAB flag_sw[] =
00201 {
00202     {"remove",          1,     CA_GOD,  FLAG_REMOVE},
00203     { NULL,             0,          0,  0}
00204 };
00205 
00206 static NAMETAB fpose_sw[] =
00207 {
00208     {"default",         1,  CA_PUBLIC,  0},
00209     {"nospace",         1,  CA_PUBLIC,  SAY_NOSPACE},
00210     { NULL,             0,          0,  0}
00211 };
00212 
00213 static NAMETAB function_sw[] =
00214 {
00215     {"list",            1,  CA_WIZARD,  FN_LIST},
00216     {"preserve",        3,  CA_WIZARD,  FN_PRES|SW_MULTIPLE},
00217     {"privileged",      3,  CA_WIZARD,  FN_PRIV|SW_MULTIPLE},
00218     { NULL,             0,          0,  0}
00219 };
00220 
00221 static NAMETAB get_sw[] =
00222 {
00223     {"quiet",           1,  CA_PUBLIC,  GET_QUIET},
00224     { NULL,             0,          0,  0}
00225 };
00226 
00227 static NAMETAB give_sw[] =
00228 {
00229     {"quiet",           1,  CA_WIZARD,  GIVE_QUIET},
00230     { NULL,             0,          0,  0}
00231 };
00232 
00233 static NAMETAB goto_sw[] =
00234 {
00235     {"quiet",           1,  CA_PUBLIC,  MOVE_QUIET},
00236     { NULL,             0,          0,  0}
00237 };
00238 
00239 static NAMETAB halt_sw[] =
00240 {
00241     {"all",             1,  CA_PUBLIC,  HALT_ALL},
00242     { NULL,             0,          0,  0}
00243 };
00244 
00245 static NAMETAB hook_sw[] =
00246 {
00247     {"after",           3,     CA_GOD,  HOOK_AFTER},
00248     {"before",          3,     CA_GOD,  HOOK_BEFORE},
00249     {"clear",           3,     CA_GOD,  HOOK_CLEAR|SW_MULTIPLE},
00250     {"fail",            1,     CA_GOD,  HOOK_AFAIL},
00251     {"ignore",          3,     CA_GOD,  HOOK_IGNORE},
00252     {"igswitch",        3,     CA_GOD,  HOOK_IGSWITCH},
00253     {"list",            3,     CA_GOD,  HOOK_LIST},
00254     {"permit",          3,     CA_GOD,  HOOK_PERMIT},
00255     {NULL,              0,          0,  0}
00256 };
00257 
00258 static NAMETAB icmd_sw[] =
00259 {
00260     {"check",           2,     CA_GOD,  ICMD_CHECK},
00261     {"clear",           2,     CA_GOD,  ICMD_CLEAR},
00262     {"croom",           2,     CA_GOD,  ICMD_CROOM},
00263     {"disable",         1,     CA_GOD,  ICMD_DISABLE},
00264     {"droom",           2,     CA_GOD,  ICMD_DROOM},
00265     {"ignore",          1,     CA_GOD,  ICMD_IGNORE},
00266     {"iroom",           2,     CA_GOD,  ICMD_IROOM},
00267     {"lroom",           2,     CA_GOD,  ICMD_LROOM},
00268     {"lallroom",        2,     CA_GOD,  ICMD_LALLROOM},
00269     {"off",             2,     CA_GOD,  ICMD_OFF},
00270     {"on",              2,     CA_GOD,  ICMD_ON},
00271     {NULL,              0,          0,  0}
00272 };
00273 
00274 static NAMETAB leave_sw[] =
00275 {
00276     {"quiet",           1,  CA_PUBLIC,  MOVE_QUIET},
00277     { NULL,             0,          0,  0}
00278 };
00279 
00280 static NAMETAB listmotd_sw[] =
00281 {
00282     {"brief",           1,  CA_WIZARD,  MOTD_BRIEF},
00283     { NULL,             0,          0,  0}
00284 };
00285 
00286 NAMETAB lock_sw[] =
00287 {
00288     {"defaultlock",     1,  CA_PUBLIC,  A_LOCK},
00289     {"droplock",        1,  CA_PUBLIC,  A_LDROP},
00290     {"enterlock",       1,  CA_PUBLIC,  A_LENTER},
00291     {"getfromlock",     1,  CA_PUBLIC,  A_LGET},
00292     {"givelock",        1,  CA_PUBLIC,  A_LGIVE},
00293     {"leavelock",       2,  CA_PUBLIC,  A_LLEAVE},
00294     {"linklock",        2,  CA_PUBLIC,  A_LLINK},
00295     {"maillock",        1,  CA_PUBLIC,  A_LMAIL},
00296     {"openlock",        1,  CA_PUBLIC,  A_LOPEN},
00297     {"pagelock",        3,  CA_PUBLIC,  A_LPAGE},
00298     {"parentlock",      3,  CA_PUBLIC,  A_LPARENT},
00299     {"receivelock",     1,  CA_PUBLIC,  A_LRECEIVE},
00300     {"speechlock",      1,  CA_PUBLIC,  A_LSPEECH},
00301     {"teloutlock",      2,  CA_PUBLIC,  A_LTELOUT},
00302     {"tportlock",       2,  CA_PUBLIC,  A_LTPORT},
00303     {"uselock",         1,  CA_PUBLIC,  A_LUSE},
00304     {"userlock",        4,  CA_PUBLIC,  A_LUSER},
00305     { NULL,             0,          0,  0}
00306 };
00307 
00308 static NAMETAB look_sw[] =
00309 {
00310     {"outside",         1,  CA_PUBLIC,  LOOK_OUTSIDE},
00311     { NULL,             0,          0,  0}
00312 };
00313 
00314 static NAMETAB mail_sw[] =
00315 {
00316     {"abort",           2,  CA_PUBLIC,  MAIL_ABORT},
00317     {"alias",           4,  CA_PUBLIC,  MAIL_ALIAS},
00318     {"alist",           4,  CA_PUBLIC,  MAIL_ALIST},
00319     {"bcc",             1,  CA_PUBLIC,  MAIL_BCC},
00320     {"cc",              2,  CA_PUBLIC,  MAIL_CC},
00321     {"clear",           2,  CA_PUBLIC,  MAIL_CLEAR},
00322     {"debug",           2,  CA_PUBLIC,  MAIL_DEBUG},
00323     {"dstats",          2,  CA_PUBLIC,  MAIL_DSTATS},
00324     {"edit",            1,  CA_PUBLIC,  MAIL_EDIT},
00325     {"file",            2,  CA_PUBLIC,  MAIL_FILE},
00326     {"folder",          3,  CA_PUBLIC,  MAIL_FOLDER},
00327     {"forward",         3,  CA_PUBLIC,  MAIL_FORWARD},
00328     {"fstats",          2,  CA_PUBLIC,  MAIL_FSTATS},
00329     {"fwd",             2,  CA_PUBLIC,  MAIL_FORWARD},
00330     {"list",            1,  CA_PUBLIC,  MAIL_LIST},
00331     {"nuke",            1,  CA_PUBLIC,  MAIL_NUKE},
00332     {"proof",           2,  CA_PUBLIC,  MAIL_PROOF},
00333     {"purge",           2,  CA_PUBLIC,  MAIL_PURGE},
00334     {"quick",           3,  CA_PUBLIC,  MAIL_QUICK},
00335     {"quote",           3,  CA_PUBLIC,  MAIL_QUOTE|SW_MULTIPLE},
00336     {"read",            3,  CA_PUBLIC,  MAIL_READ},
00337     {"reply",           3,  CA_PUBLIC,  MAIL_REPLY},
00338     {"replyall",        6,  CA_PUBLIC,  MAIL_REPLYALL},
00339     {"retract",         3,  CA_PUBLIC,  MAIL_RETRACT},
00340     {"review",          3,  CA_PUBLIC,  MAIL_REVIEW},
00341     {"safe",            2,  CA_PUBLIC,  MAIL_SAFE},
00342     {"send",            2,  CA_PUBLIC,  MAIL_SEND},
00343     {"stats",           2,  CA_PUBLIC,  MAIL_STATS},
00344     {"tag",             1,  CA_PUBLIC,  MAIL_TAG},
00345     {"unclear",         3,  CA_PUBLIC,  MAIL_UNCLEAR},
00346     {"untag",           3,  CA_PUBLIC,  MAIL_UNTAG},
00347     {"urgent",          2,  CA_PUBLIC,  MAIL_URGENT},
00348     { NULL,             0,          0,  0}
00349 };
00350 
00351 static NAMETAB malias_sw[] =
00352 {
00353     {"add",             1,  CA_PUBLIC,  MALIAS_ADD},
00354     {"chown",           1,  CA_PUBLIC,  MALIAS_CHOWN},
00355     {"desc",            1,  CA_PUBLIC,  MALIAS_DESC},
00356     {"delete",          1,  CA_PUBLIC,  MALIAS_DELETE},
00357     {"list",            1,  CA_PUBLIC,  MALIAS_LIST},
00358     {"remove",          1,  CA_PUBLIC,  MALIAS_REMOVE},
00359     {"rename",          1,  CA_PUBLIC,  MALIAS_RENAME},
00360     {"status",          1,  CA_PUBLIC,  MALIAS_STATUS},
00361     { NULL,             0,          0,  0}
00362 };
00363 
00364 static NAMETAB mark_sw[] =
00365 {
00366     {"clear",           1,  CA_PUBLIC,  MARK_CLEAR},
00367     {"set",             1,  CA_PUBLIC,  MARK_SET},
00368     { NULL,             0,          0,  0}
00369 };
00370 
00371 static NAMETAB markall_sw[] =
00372 {
00373     {"clear",           1,  CA_PUBLIC,  MARK_CLEAR},
00374     {"set",             1,  CA_PUBLIC,  MARK_SET},
00375     { NULL,             0,          0,  0}
00376 };
00377 
00378 static NAMETAB motd_sw[] =
00379 {
00380     {"brief",           1,  CA_WIZARD,  MOTD_BRIEF|SW_MULTIPLE},
00381     {"connect",         1,  CA_WIZARD,  MOTD_ALL},
00382     {"down",            1,  CA_WIZARD,  MOTD_DOWN},
00383     {"full",            1,  CA_WIZARD,  MOTD_FULL},
00384     {"list",            1,  CA_PUBLIC,  MOTD_LIST},
00385     {"wizard",          1,  CA_WIZARD,  MOTD_WIZ},
00386     { NULL,             0,          0,  0}
00387 };
00388 
00389 static NAMETAB notify_sw[] =
00390 {
00391     {"all",             1,  CA_PUBLIC,  NFY_NFYALL},
00392     {"first",           1,  CA_PUBLIC,  NFY_NFY},
00393     {"quiet",           1,  CA_PUBLIC,  NFY_QUIET},
00394     { NULL,             0,          0,  0}
00395 };
00396 
00397 static NAMETAB open_sw[] =
00398 {
00399     {"inventory",       1,  CA_PUBLIC,  OPEN_INVENTORY},
00400     {"location",        1,  CA_PUBLIC,  OPEN_LOCATION},
00401     { NULL,             0,          0,  0}
00402 };
00403 
00404 static NAMETAB page_sw[] =
00405 {
00406     {"noeval",          1,  CA_PUBLIC,  SW_NOEVAL|SW_MULTIPLE},
00407     { NULL,             0,          0,  0}
00408 };
00409 
00410 static NAMETAB pemit_sw[] =
00411 {
00412     {"contents",        1,  CA_PUBLIC,  PEMIT_CONTENTS|SW_MULTIPLE},
00413     {"html",            1,  CA_PUBLIC,  PEMIT_HTML|SW_MULTIPLE},
00414     {"list",            1,  CA_PUBLIC,  PEMIT_LIST|SW_MULTIPLE},
00415     {"noeval",          1,  CA_PUBLIC,  SW_NOEVAL|SW_MULTIPLE},
00416     {"object",          1,  CA_PUBLIC,  0},
00417     {"silent",          1,  CA_PUBLIC,  0},
00418     { NULL,             0,          0,  0}
00419 };
00420 
00421 static NAMETAB pose_sw[] =
00422 {
00423     {"default",         1,  CA_PUBLIC,  0},
00424     {"noeval",          3,  CA_PUBLIC,  SW_NOEVAL|SW_MULTIPLE},
00425     {"nospace",         3,  CA_PUBLIC,  SAY_NOSPACE},
00426     { NULL,             0,          0,  0}
00427 };
00428 
00429 static NAMETAB ps_sw[] =
00430 {
00431     {"all",             1,  CA_PUBLIC,  PS_ALL|SW_MULTIPLE},
00432     {"brief",           1,  CA_PUBLIC,  PS_BRIEF},
00433     {"long",            1,  CA_PUBLIC,  PS_LONG},
00434     {"summary",         1,  CA_PUBLIC,  PS_SUMM},
00435     { NULL,             0,          0,  0}
00436 };
00437 
00438 static NAMETAB quota_sw[] =
00439 {
00440     {"all",             1,  CA_GOD,     QUOTA_ALL|SW_MULTIPLE},
00441     {"fix",             1,  CA_WIZARD,  QUOTA_FIX},
00442     {"remaining",       1,  CA_WIZARD,  QUOTA_REM|SW_MULTIPLE},
00443     {"set",             1,  CA_WIZARD,  QUOTA_SET},
00444     {"total",           1,  CA_WIZARD,  QUOTA_TOT|SW_MULTIPLE},
00445     { NULL,             0,          0,  0}
00446 };
00447 
00448 static NAMETAB say_sw[] =
00449 {
00450     {"noeval",          1,  CA_PUBLIC,  SAY_NOEVAL|SW_NOEVAL|SW_MULTIPLE},
00451     { NULL,             0,          0,  0}
00452 };
00453 
00454 static NAMETAB set_sw[] =
00455 {
00456     {"quiet",           1,  CA_PUBLIC,  SET_QUIET},
00457     { NULL,             0,          0,  0}
00458 };
00459 
00460 static NAMETAB stats_sw[] =
00461 {
00462     {"all",             1,  CA_PUBLIC,  STAT_ALL},
00463     {"me",              1,  CA_PUBLIC,  STAT_ME},
00464     {"player",          1,  CA_PUBLIC,  STAT_PLAYER},
00465     { NULL,             0,          0,  0}
00466 };
00467 
00468 static NAMETAB sweep_sw[] =
00469 {
00470     {"commands",        3,  CA_PUBLIC,  SWEEP_COMMANDS|SW_MULTIPLE},
00471     {"connected",       3,  CA_PUBLIC,  SWEEP_CONNECT|SW_MULTIPLE},
00472     {"exits",           1,  CA_PUBLIC,  SWEEP_EXITS|SW_MULTIPLE},
00473     {"here",            1,  CA_PUBLIC,  SWEEP_HERE|SW_MULTIPLE},
00474     {"inventory",       1,  CA_PUBLIC,  SWEEP_ME|SW_MULTIPLE},
00475     {"listeners",       1,  CA_PUBLIC,  SWEEP_LISTEN|SW_MULTIPLE},
00476     {"players",         1,  CA_PUBLIC,  SWEEP_PLAYER|SW_MULTIPLE},
00477     { NULL,             0,          0,  0}
00478 };
00479 
00480 static NAMETAB switch_sw[] =
00481 {
00482     {"all",             1,  CA_PUBLIC,  SWITCH_ANY},
00483     {"default",         1,  CA_PUBLIC,  SWITCH_DEFAULT},
00484     {"first",           1,  CA_PUBLIC,  SWITCH_ONE},
00485     { NULL,             0,          0,  0}
00486 };
00487 
00488 static NAMETAB teleport_sw[] =
00489 {
00490     {"list",            1,  CA_PUBLIC,  TELEPORT_LIST|SW_MULTIPLE},
00491     {"loud",            1,  CA_PUBLIC,  TELEPORT_DEFAULT},
00492     {"quiet",           1,  CA_PUBLIC,  TELEPORT_QUIET},
00493     { NULL,             0,          0,  0}
00494 };
00495 
00496 static NAMETAB timecheck_sw[] =
00497 {
00498     {"log",             1,  CA_WIZARD,  TIMECHK_LOG | SW_MULTIPLE},
00499     {"reset",           1,  CA_WIZARD,  TIMECHK_RESET | SW_MULTIPLE},
00500     {"screen",          1,  CA_WIZARD,  TIMECHK_SCREEN | SW_MULTIPLE},
00501     { NULL,             0,          0,  0}
00502 };
00503 
00504 static NAMETAB toad_sw[] =
00505 {
00506     {"no_chown",        1,  CA_WIZARD,  TOAD_NO_CHOWN|SW_MULTIPLE},
00507     { NULL,             0,          0,  0}
00508 };
00509 
00510 static NAMETAB trig_sw[] =
00511 {
00512     {"quiet",           1,  CA_PUBLIC,  TRIG_QUIET},
00513     { NULL,             0,          0,  0}
00514 };
00515 
00516 static NAMETAB wait_sw[] =
00517 {
00518     {"until",           1,  CA_PUBLIC, WAIT_UNTIL},
00519     { NULL,             0,          0,  0}
00520 };
00521 
00522 static NAMETAB wall_sw[] =
00523 {
00524     {"admin",           1,  CA_ADMIN,    SHOUT_ADMINSHOUT},
00525     {"emit",            1,  CA_ANNOUNCE, SHOUT_WALLEMIT},
00526     {"no_prefix",       1,  CA_ANNOUNCE, SAY_NOTAG|SW_MULTIPLE},
00527     {"pose",            1,  CA_ANNOUNCE, SHOUT_WALLPOSE},
00528     {"wizard",          1,  CA_ANNOUNCE, SHOUT_WIZSHOUT|SW_MULTIPLE},
00529     { NULL,             0,          0,  0}
00530 };
00531 
00532 static NAMETAB warp_sw[] =
00533 {
00534     {"check",           1,  CA_WIZARD,  TWARP_CLEAN|SW_MULTIPLE},
00535     {"dump",            1,  CA_WIZARD,  TWARP_DUMP|SW_MULTIPLE},
00536     {"events",          1,  CA_WIZARD,  TWARP_EVENTS|SW_MULTIPLE},
00537     {"idle",            1,  CA_WIZARD,  TWARP_IDLE|SW_MULTIPLE},
00538     {"queue",           1,  CA_WIZARD,  TWARP_QUEUE|SW_MULTIPLE},
00539     { NULL,             0,          0,  0}
00540 };
00541 
00542 
00543 /* ---------------------------------------------------------------------------
00544  * Command table: Definitions for builtin commands, used to build the command
00545  * hash table.
00546  *
00547  * Format:  Name        Switches    Permissions Needed
00548  *  Key (if any)    Calling Seq         Handler
00549  */
00550 static CMDENT_NO_ARG command_table_no_arg[] =
00551 {
00552     {"@@",          NULL,       CA_PUBLIC,   0,          CS_NO_ARGS, 0, do_comment},
00553     {"@backup",     NULL,       CA_WIZARD,   0,          CS_NO_ARGS, 0, do_backup},
00554     {"@dbck",       dbck_sw,    CA_WIZARD,   0,          CS_NO_ARGS, 0, do_dbck},
00555     {"@dbclean",    NULL,       CA_GOD,      0,          CS_NO_ARGS, 0, do_dbclean},
00556     {"@dump",       dump_sw,    CA_WIZARD,   0,          CS_NO_ARGS, 0, do_dump},
00557     {"@mark_all",   markall_sw, CA_WIZARD,   MARK_SET,   CS_NO_ARGS, 0, do_markall},
00558     {"@readcache",  NULL,       CA_WIZARD,   0,          CS_NO_ARGS, 0, do_readcache},
00559     {"@restart",    NULL,       CA_NO_GUEST|CA_NO_SLAVE, 0, CS_NO_ARGS, 0, do_restart},
00560 #ifndef WIN32
00561     {"@startslave", NULL,       CA_WIZARD,   0,          CS_NO_ARGS, 0, boot_slave},
00562 #endif // !WIN32
00563     {"@timecheck",  timecheck_sw, CA_WIZARD, 0,          CS_NO_ARGS, 0, do_timecheck},
00564     {"clearcom",    NULL,       CA_NO_SLAVE, 0,          CS_NO_ARGS, 0, do_clearcom},
00565     {"info",        NULL,       CA_PUBLIC,   CMD_INFO,   CS_NO_ARGS, 0, logged_out0},
00566     {"inventory",   NULL,       CA_PUBLIC,   0,          CS_NO_ARGS, 0, do_inventory},
00567     {"leave",       leave_sw,   CA_LOCATION, 0,          CS_NO_ARGS, 0, do_leave},
00568     {"logout",      NULL,       CA_PUBLIC,   CMD_LOGOUT, CS_NO_ARGS, 0, logged_out0},
00569     {"quit",        NULL,       CA_PUBLIC,   CMD_QUIT,   CS_NO_ARGS, 0, logged_out0},
00570     {"report",      NULL,       CA_PUBLIC,   0,          CS_NO_ARGS, 0, do_report},
00571     {"score",       NULL,       CA_PUBLIC,   0,          CS_NO_ARGS, 0, do_score},
00572     {"version",     NULL,       CA_PUBLIC,   0,          CS_NO_ARGS, 0, do_version},
00573     {NULL,          NULL,       0,           0,          0,          0, NULL}
00574 };
00575 
00576 static CMDENT_ONE_ARG command_table_one_arg[] =
00577 {
00578     {"@boot",         boot_sw,    CA_NO_GUEST|CA_NO_SLAVE,    0,  CS_ONE_ARG|CS_INTERP, 0, do_boot},
00579     {"@break",        NULL,       CA_PUBLIC,                  0,  CS_ONE_ARG,           0, do_break},
00580     {"@ccreate",      NULL,       CA_NO_SLAVE|CA_NO_GUEST,    0,  CS_ONE_ARG,           0, do_createchannel},
00581     {"@cdestroy",     NULL,       CA_NO_SLAVE|CA_NO_GUEST,    0,  CS_ONE_ARG,           0, do_destroychannel},
00582     {"@clist",        clist_sw,   CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_chanlist},
00583     {"@cut",          NULL,       CA_WIZARD|CA_LOCATION,      0,  CS_ONE_ARG|CS_INTERP, 0, do_cut},
00584     {"@cwho",         NULL,       CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_channelwho},
00585     {"@destroy",      destroy_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, DEST_ONE,   CS_ONE_ARG|CS_INTERP,   0, do_destroy},
00586     {"@disable",      NULL,       CA_WIZARD,       GLOB_DISABLE,  CS_ONE_ARG,           0, do_global},
00587     {"@doing",        doing_sw,   CA_PUBLIC,                  0,  CS_ONE_ARG,           0, do_doing},
00588     {"@emit",         emit_sw,    CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,  SAY_EMIT,   CS_ONE_ARG|CS_INTERP,   0, do_say},
00589     {"@enable",       NULL,       CA_WIZARD,        GLOB_ENABLE,  CS_ONE_ARG,           0, do_global},
00590     {"@entrances",    NULL,       CA_NO_GUEST,                0,  CS_ONE_ARG|CS_INTERP, 0, do_entrances},
00591     {"@find",         NULL,       CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_find},
00592     {"@halt",         halt_sw,    CA_NO_SLAVE,                0,  CS_ONE_ARG|CS_INTERP, 0, do_halt},
00593     {"@hook",         hook_sw,    CA_GOD,                     0,  CS_ONE_ARG|CS_INTERP, 0, do_hook},
00594     {"@kick",         NULL,       CA_WIZARD,         QUEUE_KICK,  CS_ONE_ARG|CS_INTERP, 0, do_queue},
00595     {"@last",         NULL,       CA_NO_GUEST,                0,  CS_ONE_ARG|CS_INTERP, 0, do_last},
00596     {"@list",         NULL,       CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_list},
00597     {"@list_file",    NULL,       CA_WIZARD,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_list_file},
00598     {"@listcommands", NULL,       CA_GOD,                     0,  CS_ONE_ARG,           0, do_listcommands},
00599     {"@listmotd",     listmotd_sw,CA_PUBLIC,          MOTD_LIST,  CS_ONE_ARG,           0, do_motd},
00600     {"@mark",         mark_sw,    CA_WIZARD,          SRCH_MARK,  CS_ONE_ARG|CS_NOINTERP,   0, do_search},
00601     {"@motd",         motd_sw,    CA_WIZARD,                  0,  CS_ONE_ARG,           0, do_motd},
00602     {"@nemit",        emit_sw,    CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_say},
00603     {"@poor",         NULL,       CA_GOD,                     0,  CS_ONE_ARG|CS_INTERP, 0, do_poor},
00604     {"@ps",           ps_sw,      CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_ps},
00605     {"@quitprogram",  NULL,       CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_quitprog},
00606     {"@search",       NULL,       CA_PUBLIC,        SRCH_SEARCH,  CS_ONE_ARG|CS_NOINTERP,   0, do_search},
00607     {"@shutdown",     NULL,       CA_NO_GUEST|CA_NO_SLAVE,    0,  CS_ONE_ARG,           0, do_shutdown},
00608     {"@stats",        stats_sw,   CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_stats},
00609     {"@sweep",        sweep_sw,   CA_PUBLIC,                  0,  CS_ONE_ARG,           0, do_sweep},
00610     {"@timewarp",     warp_sw,    CA_WIZARD,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_timewarp},
00611     {"@unlink",       NULL,       CA_NO_SLAVE|CA_GBL_BUILD,   0,  CS_ONE_ARG|CS_INTERP, 0, do_unlink},
00612     {"@unlock",       lock_sw,    CA_NO_SLAVE,                0,  CS_ONE_ARG|CS_INTERP, 0, do_unlock},
00613     {"@wall",         wall_sw,    CA_ANNOUNCE,      SHOUT_SHOUT,  CS_ONE_ARG|CS_INTERP, 0, do_shout},
00614     {"@wipe",         NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0,  CS_ONE_ARG|CS_INTERP,   0, do_wipe},
00615     {"allcom",        NULL,       CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_allcom},
00616     {"comlist",       NULL,       CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_comlist},
00617     {"delcom",        NULL,       CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_delcom},
00618     {"doing",         NULL,       CA_PUBLIC,          CMD_DOING,  CS_ONE_ARG,           0, logged_out1},
00619     {"drop",          drop_sw,    CA_NO_SLAVE|CA_CONTENTS|CA_LOCATION|CA_NO_GUEST,  0,  CS_ONE_ARG|CS_INTERP,   0, do_drop},
00620     {"enter",         enter_sw,   CA_LOCATION,                0,  CS_ONE_ARG|CS_INTERP, 0, do_enter},
00621     {"examine",       examine_sw, CA_PUBLIC,                  0,  CS_ONE_ARG|CS_INTERP, 0, do_examine},
00622     {"get",           get_sw,     CA_LOCATION|CA_NO_GUEST,    0,  CS_ONE_ARG|CS_INTERP, 0, do_get},
00623     {"goto",          goto_sw,    CA_LOCATION,                0,  CS_ONE_ARG|CS_INTERP, 0, do_move},
00624     {"look",          look_sw,    CA_LOCATION,        LOOK_LOOK,  CS_ONE_ARG|CS_INTERP, 0, do_look},
00625     {"outputprefix",  NULL,       CA_PUBLIC,         CMD_PREFIX,  CS_ONE_ARG,           0, logged_out1},
00626     {"outputsuffix",  NULL,       CA_PUBLIC,         CMD_SUFFIX,  CS_ONE_ARG,           0, logged_out1},
00627     {"pose",          pose_sw,    CA_LOCATION|CA_NO_SLAVE,  SAY_POSE,   CS_ONE_ARG|CS_INTERP,   0, do_say},
00628     {"puebloclient",  NULL,       CA_PUBLIC,   CMD_PUEBLOCLIENT,  CS_ONE_ARG,           0, logged_out1},
00629     {"say",           say_sw,     CA_LOCATION|CA_NO_SLAVE,  SAY_SAY,    CS_ONE_ARG|CS_INTERP,   0, do_say},
00630     {"session",       NULL,       CA_PUBLIC,        CMD_SESSION,  CS_ONE_ARG,           0, logged_out1},
00631     {"think",         NULL,       CA_NO_SLAVE,                0,  CS_ONE_ARG,           0, do_think},
00632     {"train",         NULL,       CA_PUBLIC,                  0,  CS_ONE_ARG,           0, do_train},
00633     {"use",           NULL,       CA_NO_SLAVE|CA_GBL_INTERP,  0,  CS_ONE_ARG|CS_INTERP, 0, do_use},
00634     {"who",           NULL,       CA_PUBLIC,            CMD_WHO,  CS_ONE_ARG,           0, logged_out1},
00635     {"\\",            NULL,       CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_SLAVE,  SAY_PREFIX, CS_ONE_ARG|CS_INTERP,   0, do_say},
00636     {":",             NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,  SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say},
00637     {";",             NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,  SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say},
00638     {"\"",            NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,  SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, 0, do_say},
00639     {"-",             NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,  0,  CS_ONE_ARG|CS_LEADIN,   0, do_postpend},
00640     {"~",             NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,  0,  CS_ONE_ARG|CS_LEADIN,   0, do_prepend},
00641     {NULL,            NULL,       0,                          0,    0,                  0, NULL}
00642 };
00643 
00644 static CMDENT_ONE_ARG_CMDARG command_table_one_arg_cmdarg[] =
00645 {
00646     {"@apply_marked", NULL,       CA_WIZARD|CA_GBL_INTERP,    0,      CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,   0, do_apply_marked},
00647     {"#",             NULL,       CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK,    0,      CS_ONE_ARG|CS_INTERP|CS_CMDARG, 0, do_force_prefixed},
00648     {NULL,            NULL,       0,     0,      0,             0,  NULL}
00649 };
00650 
00651 static CMDENT_TWO_ARG command_table_two_arg[] =
00652 {
00653     {"@addcommand",  NULL,       CA_GOD,                                           0,           CS_TWO_ARG,           0, do_addcommand},
00654     {"@admin",       NULL,       CA_WIZARD,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_admin},
00655     {"@alias",       NULL,       CA_NO_GUEST|CA_NO_SLAVE,                          0,           CS_TWO_ARG,           0, do_alias},
00656     {"@attribute",   attrib_sw,  CA_GOD,                                           0,           CS_TWO_ARG|CS_INTERP, 0, do_attribute},
00657     {"@cboot",       cboot_sw,   CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG,           0, do_chboot},
00658     {"@ccharge",     NULL,       CA_NO_SLAVE|CA_NO_GUEST,                          1,           CS_TWO_ARG,           0, do_editchannel},
00659     {"@cchown",      NULL,       CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG,           0, do_editchannel},
00660     {"@cemit",       cemit_sw,   CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG,           0, do_cemit},
00661     {"@chown",       NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,             CHOWN_ONE,   CS_TWO_ARG|CS_INTERP, 0, do_chown},
00662     {"@chownall",    NULL,       CA_WIZARD|CA_GBL_BUILD,                           CHOWN_ALL,   CS_TWO_ARG|CS_INTERP, 0, do_chownall},
00663     {"@chzone",      NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,             0,           CS_TWO_ARG|CS_INTERP, 0, do_chzone},
00664     {"@clone",       clone_sw,   CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0,           CS_TWO_ARG|CS_INTERP, 0, do_clone},
00665     {"@coflags",     NULL,       CA_NO_SLAVE,                                      4,           CS_TWO_ARG,           0, do_editchannel},
00666     {"@cpflags",     NULL,       CA_NO_SLAVE,                                      3,           CS_TWO_ARG,           0, do_editchannel},
00667     {"@create",      NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST, 0,           CS_TWO_ARG|CS_INTERP, 0, do_create},
00668     {"@cset",        cset_sw,    CA_NO_SLAVE,                                      0,           CS_TWO_ARG|CS_INTERP, 0, do_chopen},
00669     {"@decompile",   decomp_sw,  CA_PUBLIC,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_decomp},
00670     {"@delcommand",  NULL,       CA_GOD,                                           0,           CS_TWO_ARG,           0, do_delcommand},
00671     {"@drain",       NULL,       CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,            NFY_DRAIN,   CS_TWO_ARG,           0, do_notify},
00672     {"@femit",       femit_sw,   CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,              PEMIT_FEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00673     {"@fixdb",       fixdb_sw,   CA_GOD,                                           0,           CS_TWO_ARG|CS_INTERP, 0, do_fixdb},
00674     {"@flag",        flag_sw,    CA_GOD,                                           0,           CS_TWO_ARG,           0, do_flag},
00675     {"@forwardlist", NULL,       CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG,           0, do_forwardlist},
00676     {"@fpose",       fpose_sw,   CA_LOCATION|CA_NO_SLAVE,                          PEMIT_FPOSE, CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00677     {"@fsay",        NULL,       CA_LOCATION|CA_NO_SLAVE,                          PEMIT_FSAY,  CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00678     {"@function",    function_sw,CA_GOD,                                           0,           CS_TWO_ARG|CS_INTERP, 0, do_function},
00679     {"@link",        NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,             0,           CS_TWO_ARG|CS_INTERP, 0, do_link},
00680     {"@lock",        lock_sw,    CA_NO_SLAVE,                                      0,           CS_TWO_ARG|CS_INTERP, 0, do_lock},
00681     {"@log",         NULL,       CA_WIZARD,                                        0,           CS_TWO_ARG,           0, do_log},
00682     {"@mail",        mail_sw,    CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG|CS_INTERP, 0, do_mail},
00683     {"@malias",      malias_sw,  CA_NO_SLAVE|CA_NO_GUEST,                          0,           CS_TWO_ARG|CS_INTERP, 0, do_malias},
00684     {"@moniker",     NULL,       CA_NO_GUEST|CA_NO_SLAVE,                          0,           CS_TWO_ARG|CS_INTERP, 0, do_moniker},
00685     {"@name",        NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,             0,           CS_TWO_ARG|CS_INTERP, 0, do_name},
00686     {"@newpassword", NULL,       CA_WIZARD,                                        0,           CS_TWO_ARG,           0, do_newpassword},
00687     {"@notify",      notify_sw,  CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,            0,           CS_TWO_ARG,           0, do_notify},
00688     {"@npemit",      pemit_sw,   CA_NO_GUEST|CA_NO_SLAVE,                          PEMIT_PEMIT, CS_TWO_ARG|CS_UNPARSE|CS_NOSQUISH, 0, do_pemit},
00689     {"@oemit",       NULL,       CA_NO_GUEST|CA_NO_SLAVE,                          PEMIT_OEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00690     {"@parent",      NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,             0,           CS_TWO_ARG,           0, do_parent},
00691     {"@password",    NULL,       CA_NO_GUEST,                                      0,           CS_TWO_ARG,           0, do_password},
00692     {"@pcreate",     NULL,       CA_WIZARD|CA_GBL_BUILD,                           PCRE_PLAYER, CS_TWO_ARG,           0, do_pcreate},
00693     {"@pemit",       pemit_sw,   CA_NO_GUEST|CA_NO_SLAVE,                          PEMIT_PEMIT, CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00694     {"@power",       NULL,       CA_PUBLIC,                                        0,           CS_TWO_ARG,           0, do_power},
00695     {"@program",     NULL,       CA_PUBLIC,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_prog},
00696     {"@quota",       quota_sw,   CA_PUBLIC,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_quota},
00697     {"@robot",       NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER,   PCRE_ROBOT,  CS_TWO_ARG,           0, do_pcreate},
00698 #ifdef REALITY_LVLS
00699     {"@rxlevel",    NULL,       CA_WIZARD,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_rxlevel},
00700 #endif
00701     {"@set",         set_sw,     CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,             0,           CS_TWO_ARG,           0, do_set},
00702     {"@teleport",    teleport_sw,CA_NO_GUEST,                                      TELEPORT_DEFAULT, CS_TWO_ARG|CS_INTERP, 0, do_teleport},
00703 #ifdef REALITY_LVLS
00704     {"@txlevel",    NULL,       CA_WIZARD,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_txlevel},
00705 #endif
00706     {"@toad",        toad_sw,    CA_WIZARD,                                        0,           CS_TWO_ARG|CS_INTERP, 0, do_toad},
00707     {"addcom",       NULL,       CA_NO_SLAVE,                                      0,           CS_TWO_ARG,           0, do_addcom},
00708     {"comtitle",     comtitle_sw,CA_NO_SLAVE,                                      0,           CS_TWO_ARG,           0, do_comtitle},
00709     {"give",         give_sw,    CA_LOCATION|CA_NO_GUEST,                          0,           CS_TWO_ARG|CS_INTERP, 0, do_give},
00710     {"kill",         NULL,       CA_NO_GUEST|CA_NO_SLAVE,                          KILL_KILL,   CS_TWO_ARG|CS_INTERP, 0, do_kill},
00711     {"page",         page_sw,    CA_NO_SLAVE,                                      0,           CS_TWO_ARG|CS_INTERP, 0, do_page},
00712     {"slay",         NULL,       CA_WIZARD,                                        KILL_SLAY,   CS_TWO_ARG|CS_INTERP, 0, do_kill},
00713     {"whisper",      NULL,       CA_LOCATION|CA_NO_SLAVE,                          PEMIT_WHISPER, CS_TWO_ARG|CS_INTERP, 0, do_pemit},
00714     {"&",            NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,                  0,           CS_TWO_ARG|CS_LEADIN, 0, do_setvattr},
00715     {NULL,           NULL,       0,                                                0,           0,                    0, NULL}
00716 };
00717 
00718 static CMDENT_TWO_ARG_ARGV command_table_two_arg_argv[] =
00719 {
00720     {"@cpattr",     NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0,  CS_TWO_ARG|CS_ARGV,             0, do_cpattr},
00721     {"@dig",        dig_sw,     CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0,  CS_TWO_ARG|CS_ARGV|CS_INTERP,   0, do_dig},
00722     {"@edit",       NULL,       CA_NO_SLAVE|CA_NO_GUEST,              0,  CS_TWO_ARG|CS_ARGV|CS_STRIP_AROUND, 0, do_edit},
00723     {"@icmd",       icmd_sw,    CA_GOD,                               0,  CS_TWO_ARG|CS_ARGV|CS_INTERP,   0, do_icmd},
00724     {"@mvattr",     NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD, 0,  CS_TWO_ARG|CS_ARGV,             0, do_mvattr},
00725     {"@open",       open_sw,    CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST, 0,  CS_TWO_ARG|CS_ARGV|CS_INTERP,   0, do_open},
00726     {"@trigger",    trig_sw,    CA_GBL_INTERP,                        0,  CS_TWO_ARG|CS_ARGV,             0, do_trigger},
00727     {"@verb",       NULL,       CA_GBL_INTERP|CA_NO_SLAVE,            0,  CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP_AROUND, 0, do_verb},
00728     {NULL,          NULL,       0,                                    0,  0,              0, NULL}
00729 };
00730 
00731 static CMDENT_TWO_ARG_CMDARG command_table_two_arg_cmdarg[] =
00732 {
00733     {"@dolist", dolist_sw,  CA_GBL_INTERP,  0,      CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_dolist},
00734     {"@force",  NULL,       CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST,    0,    CS_TWO_ARG|CS_INTERP|CS_CMDARG, 0, do_force},
00735 #ifdef QUERY_SLAVE
00736     {"@query",  query_sw,   CA_WIZARD,      0,      CS_TWO_ARG|CS_INTERP|CS_CMDARG,                   0, do_query},
00737 #endif
00738     {"@wait",   wait_sw,    CA_GBL_INTERP,  0,      CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_wait},
00739     {NULL,      NULL,       0,              0,      0,              0, NULL}
00740 };
00741 
00742 static CMDENT_TWO_ARG_ARGV_CMDARG command_table_two_arg_argv_cmdarg[] =
00743 {
00744     {"@if",     NULL,       CA_GBL_INTERP,  0,  CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_if},
00745     {"@switch", switch_sw,  CA_GBL_INTERP,  0,  CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, 0, do_switch},
00746     {NULL,      NULL,       0,              0,  0,                                                        0, NULL}
00747 };
00748 
00749 static CMDENT *prefix_cmds[256];
00750 
00751 static CMDENT *goto_cmdp;
00752 
00753 void commands_no_arg_add(CMDENT_NO_ARG cmdent[])
00754 {
00755     CMDENT_NO_ARG *cp0a;
00756     for (cp0a = cmdent; cp0a->cmdname; cp0a++)
00757     {
00758         if (!hashfindLEN(cp0a->cmdname, strlen(cp0a->cmdname),
00759                          &mudstate.command_htab))
00760         {
00761             hashaddLEN(cp0a->cmdname, strlen(cp0a->cmdname), cp0a,
00762                        &mudstate.command_htab);
00763         }
00764     }
00765 }
00766 
00767 void commands_one_arg_add(CMDENT_ONE_ARG cmdent[])
00768 {
00769     CMDENT_ONE_ARG *cp1a;
00770     for (cp1a = cmdent; cp1a->cmdname; cp1a++)
00771     {
00772         if (!hashfindLEN(cp1a->cmdname, strlen(cp1a->cmdname),
00773                         &mudstate.command_htab))
00774         {
00775             hashaddLEN(cp1a->cmdname, strlen(cp1a->cmdname), cp1a,
00776                        &mudstate.command_htab);
00777         }
00778     }
00779 }
00780 
00781 void commands_one_arg_cmdarg_add(CMDENT_ONE_ARG_CMDARG cmdent[])
00782 {
00783     CMDENT_ONE_ARG_CMDARG *cp1ac;
00784     for (cp1ac = cmdent; cp1ac->cmdname; cp1ac++)
00785     {
00786         if (!hashfindLEN(cp1ac->cmdname, strlen(cp1ac->cmdname),
00787                          &mudstate.command_htab))
00788         {
00789             hashaddLEN(cp1ac->cmdname, strlen(cp1ac->cmdname), cp1ac,
00790                        &mudstate.command_htab);
00791         }
00792     }
00793 }
00794 
00795 void commands_two_arg_add(CMDENT_TWO_ARG cmdent[])
00796 {
00797     CMDENT_TWO_ARG *cp2a;
00798     for (cp2a = cmdent; cp2a->cmdname; cp2a++)
00799     {
00800         if (!hashfindLEN(cp2a->cmdname, strlen(cp2a->cmdname),
00801                          &mudstate.command_htab))
00802         {
00803             hashaddLEN(cp2a->cmdname, strlen(cp2a->cmdname), cp2a,
00804                        &mudstate.command_htab);
00805         }
00806     }
00807 }
00808 
00809 void commands_two_arg_argv_add(CMDENT_TWO_ARG_ARGV cmdent[])
00810 {
00811     CMDENT_TWO_ARG_ARGV *cp2aa;
00812     for (cp2aa = cmdent; cp2aa->cmdname; cp2aa++)
00813     {
00814         if (!hashfindLEN(cp2aa->cmdname, strlen(cp2aa->cmdname),
00815                          &mudstate.command_htab))
00816         {
00817             hashaddLEN(cp2aa->cmdname, strlen(cp2aa->cmdname), cp2aa,
00818                        &mudstate.command_htab);
00819         }
00820     }
00821 }
00822 
00823 void commands_two_arg_cmdarg_add(CMDENT_TWO_ARG_CMDARG cmdent[])
00824 {
00825     CMDENT_TWO_ARG_CMDARG  *cp2ac;
00826     for (cp2ac = cmdent; cp2ac->cmdname; cp2ac++)
00827     {
00828         if (!hashfindLEN(cp2ac->cmdname, strlen(cp2ac->cmdname),
00829                          &mudstate.command_htab))
00830         {
00831             hashaddLEN(cp2ac->cmdname, strlen(cp2ac->cmdname), cp2ac,
00832                        &mudstate.command_htab);
00833         }
00834     }
00835 }
00836 
00837 void commands_two_arg_argv_cmdarg_add(CMDENT_TWO_ARG_ARGV_CMDARG cmdent[])
00838 {
00839     CMDENT_TWO_ARG_ARGV_CMDARG  *cp2aac;
00840     for (cp2aac = cmdent; cp2aac->cmdname; cp2aac++)
00841     {
00842         if (!hashfindLEN(cp2aac->cmdname, strlen(cp2aac->cmdname),
00843                          &mudstate.command_htab))
00844         {
00845             hashaddLEN(cp2aac->cmdname, strlen(cp2aac->cmdname), cp2aac,
00846                        &mudstate.command_htab);
00847         }
00848     }
00849 }
00850 
00851 void init_cmdtab(void)
00852 {
00853     ATTR *ap;
00854 
00855     // Load attribute-setting commands.
00856     //
00857     for (ap = attr; ap->name; ap++)
00858     {
00859         if (ap->flags & AF_NOCMD)
00860         {
00861             continue;
00862         }
00863 
00864         int nBuffer;
00865         bool bValid;
00866         char *cbuff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
00867         if (!bValid)
00868         {
00869             continue;
00870         }
00871 
00872         CMDENT_TWO_ARG *cp2a;
00873         cp2a = (CMDENT_TWO_ARG *)MEMALLOC(sizeof(CMDENT_TWO_ARG));
00874         ISOUTOFMEMORY(cp2a);
00875         cp2a->cmdname = StringClone(cbuff);
00876         cp2a->perms = CA_NO_GUEST | CA_NO_SLAVE;
00877         cp2a->switches = NULL;
00878         if (ap->flags & (AF_WIZARD | AF_MDARK))
00879         {
00880             cp2a->perms |= CA_WIZARD;
00881         }
00882         cp2a->extra = ap->number;
00883         cp2a->callseq = CS_TWO_ARG;
00884         cp2a->hookmask = 0;
00885         cp2a->handler = do_setattr;
00886         hashaddLEN(cp2a->cmdname, nBuffer, cp2a, &mudstate.command_htab);
00887     }
00888 
00889     // Load the builtin commands
00890     //
00891     commands_no_arg_add(command_table_no_arg);
00892     commands_one_arg_add(command_table_one_arg);
00893     commands_one_arg_cmdarg_add(command_table_one_arg_cmdarg);
00894     commands_two_arg_add(command_table_two_arg);
00895     commands_two_arg_argv_add(command_table_two_arg_argv);
00896     commands_two_arg_cmdarg_add(command_table_two_arg_cmdarg);
00897     commands_two_arg_argv_cmdarg_add(command_table_two_arg_argv_cmdarg);
00898 
00899     set_prefix_cmds();
00900 
00901     goto_cmdp = (CMDENT *) hashfindLEN((char *)"goto", strlen("goto"), &mudstate.command_htab);
00902 }
00903 
00912 void set_prefix_cmds()
00913 {
00914     for (int i = 0; i < 256; i++)
00915     {
00916         prefix_cmds[i] = NULL;
00917     }
00918 
00919 #define SET_PREFIX_CMD(s) prefix_cmds[(unsigned char)(s)[0]] = \
00920         (CMDENT *) hashfindLEN((char *)(s), 1, &mudstate.command_htab)
00921     SET_PREFIX_CMD("\"");
00922     SET_PREFIX_CMD(":");
00923     SET_PREFIX_CMD(";");
00924     SET_PREFIX_CMD("\\");
00925     SET_PREFIX_CMD("#");
00926     SET_PREFIX_CMD("&");
00927     SET_PREFIX_CMD("-");
00928     SET_PREFIX_CMD("~");
00929 #undef SET_PREFIX_CMD
00930 }
00931 
00932 // ---------------------------------------------------------------------------
00933 // check_access: Check if player has access to function.
00934 //
00935 bool check_access(dbref player, int mask)
00936 {
00937     if (mask & (CA_DISABLED|CA_STATIC))
00938     {
00939         return false;
00940     }
00941     if (  God(player)
00942        || mudstate.bReadingConfiguration)
00943     {
00944         return true;
00945     }
00946 
00947     if (mask & CA_MUSTBE_MASK)
00948     {
00949         // Since CA_GOD by itself is a frequent case, for the sake of
00950         // performance, we test CA_GOD specifically. If CA_GOD were ever
00951         // combined with anything, it would be passed through to the general
00952         // case.
00953         //
00954         if ((mask & CA_MUSTBE_MASK) == CA_GOD)
00955         {
00956             return false;
00957         }
00958 
00959         // Since God(player) is always false here, CA_GOD is still handled by
00960         // the following code even though it doesn't appear in any of the
00961         // cases explicitly.  CA_WIZARD by itself is also a common case, but
00962         // since we have have a bit (mask & CA_MUSTBE_MASK), and since that
00963         // bit is not a lone CA_GOD bit (handled above), and since CA_WIZARD
00964         // it tested first below, it doesn't make sense to test CA_WIZARD
00965         // as a special case.
00966         //
00967         if (!(  ((mask & CA_WIZARD)   && Wizard(player))
00968              || ((mask & CA_ADMIN)    && WizRoy(player))
00969              || ((mask & CA_BUILDER)  && Builder(player))
00970              || ((mask & CA_STAFF)    && Staff(player))
00971              || ((mask & CA_HEAD)     && Head(player))
00972              || ((mask & CA_ANNOUNCE) && Announce(player))
00973              || ((mask & CA_IMMORTAL) && Immortal(player))
00974              || ((mask & CA_UNINS)    && Uninspected(player))
00975              || ((mask & CA_ROBOT)    && Robot(player))))
00976         {
00977             return false;
00978         }
00979     }
00980 
00981     // Check for forbidden flags.
00982     //
00983     if (  (mask & CA_CANTBE_MASK)
00984        && !Wizard(player))
00985     {
00986         if (  ((mask & CA_NO_HAVEN)   && Player_haven(player))
00987            || ((mask & CA_NO_ROBOT)   && Robot(player))
00988            || ((mask & CA_NO_SLAVE)   && Slave(player))
00989            || ((mask & CA_NO_SUSPECT) && Suspect(player))
00990            || ((mask & CA_NO_GUEST)   && Guest(player))
00991            || ((mask & CA_NO_UNINS)   && Uninspected(player)))
00992         {
00993             return false;
00994         }
00995     }
00996     return true;
00997 }
00998 
00999 /*****************************************************************************
01000  * Process the various hook calls.
01001  * Idea taken from TinyMUSH3, code from RhostMUSH, ported by Jake Nelson.
01002  * Hooks processed:  before, after, ignore, permit, fail
01003  *****************************************************************************/
01004 static bool process_hook(dbref executor, dbref thing, char *s_uselock, ATTR *hk_attr,
01005                   bool save_flg)
01006 {
01007     UNUSED_PARAMETER(s_uselock);
01008 
01009     bool retval = true;
01010     if (hk_attr)
01011     {
01012         dbref aowner;
01013         int aflags;
01014         int anum = hk_attr->number;
01015         char *atext = atr_get(thing, anum, &aowner, &aflags);
01016         if (atext[0] && !(aflags & AF_NOPROG))
01017         {
01018             char **preserve = NULL;
01019             int *preserve_len = NULL;
01020             if (save_flg)
01021             {
01022                 preserve = PushPointers(MAX_GLOBAL_REGS);
01023                 preserve_len = PushIntegers(MAX_GLOBAL_REGS);
01024                 save_global_regs("process_hook.save", preserve, preserve_len);
01025             }
01026             char *buff, *bufc;
01027             bufc = buff = alloc_lbuf("process_hook");
01028             char *str = atext;
01029             mux_exec(buff, &bufc, thing, executor, executor, EV_FCHECK | EV_EVAL, &str,
01030                 (char **)NULL, 0);
01031             *bufc = '\0';
01032             if (save_flg)
01033             {
01034                 restore_global_regs("process_hook.save", preserve, preserve_len);
01035                 PopIntegers(preserve_len, MAX_GLOBAL_REGS);
01036                 PopPointers(preserve, MAX_GLOBAL_REGS);
01037             }
01038             retval = xlate(buff);
01039             free_lbuf(buff);
01040         }
01041         free_lbuf(atext);
01042     }
01043     return retval;
01044 }
01045 
01046 static char *hook_name(char *pCommand, int key)
01047 {
01048     char *keylet;
01049     switch (key)
01050     {
01051     case HOOK_AFAIL:
01052         keylet = "AF";
01053         break;
01054     case HOOK_AFTER:
01055         keylet = "A";
01056         break;
01057     case HOOK_BEFORE:
01058         keylet = "B";
01059         break;
01060     case HOOK_IGNORE:
01061         keylet = "I";
01062         break;
01063     case HOOK_PERMIT:
01064         keylet = "P";
01065         break;
01066     default:
01067         return NULL;
01068     }
01069 
01070     const char *cmdName = pCommand;
01071     if (  pCommand[0]
01072        && !pCommand[1])
01073     {
01074         switch (pCommand[0])
01075         {
01076         case '"' : cmdName = "say";    break;
01077         case ':' :
01078         case ';' : cmdName = "pose";   break;
01079         case '\\': cmdName = "@emit";  break;
01080         case '#' : cmdName = "@force"; break;
01081         case '&' : cmdName = "@set";   break;
01082         case '-' : cmdName = "@mail";  break;
01083         case '~' : cmdName = "@mail";  break;
01084         }
01085     }
01086 
01087     char *s_uselock = alloc_sbuf("command_hook.hookname");
01088     sprintf(s_uselock, "%s_%s", keylet, cmdName);
01089     return s_uselock;
01090 }
01091 
01092 /* ---------------------------------------------------------------------------
01093  * process_cmdent: Perform indicated command with passed args.
01094  */
01095 
01096 static void process_cmdent(CMDENT *cmdp, char *switchp, dbref executor, dbref caller,
01097             dbref enactor, bool interactive, char *arg, char *unp_command,
01098             char *cargs[], int ncargs)
01099 {
01100     // Perform object type checks.
01101     //
01102     if (Invalid_Objtype(executor))
01103     {
01104         notify(executor, "Command incompatible with executor type.");
01105         return;
01106     }
01107 
01108     // Check if we have permission to execute the command.
01109     //
01110     if (!check_access(executor, cmdp->perms))
01111     {
01112         notify(executor, NOPERM_MESSAGE);
01113         return;
01114     }
01115 
01116     // Check global flags
01117     //
01118     if (  !Builder(executor)
01119        && Protect(CA_GBL_BUILD)
01120        && !(mudconf.control_flags & CF_BUILD))
01121     {
01122         notify(executor, "Sorry, building is not allowed now.");
01123         return;
01124     }
01125     if (Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP))
01126     {
01127         notify(executor, "Sorry, queueing and triggering are not allowed now.");
01128         return;
01129     }
01130 
01131     char *buf1, *buf2, tchar, *bp, *str, *buff, *j, *new0, *s_uselock;
01132     char *args[MAX_ARG];
01133     int nargs, i, interp, key, xkey, aflags;
01134     dbref aowner;
01135     char *aargs[NUM_ENV_VARS];
01136     ADDENT *add;
01137     ATTR *hk_ap2;
01138 
01139     key = cmdp->extra & ~SW_MULTIPLE;
01140     if (key & SW_GOT_UNIQUE)
01141     {
01142         i = 1;
01143         key = key & ~SW_GOT_UNIQUE;
01144     }
01145     else
01146     {
01147         i = 0;
01148     }
01149 
01150     // Check command switches.  Note that there may be more than one,
01151     // and that we OR all of them together along with the extra value
01152     // from the command table to produce the key value in the handler
01153     // call.
01154     //
01155     if (switchp && cmdp->switches)
01156     {
01157         do
01158         {
01159             buf1 = strchr(switchp, '/');
01160             if (buf1)
01161             {
01162                 *buf1++ = '\0';
01163             }
01164             if (!search_nametab(executor, cmdp->switches, switchp, &xkey))
01165             {
01166                 if (xkey == -1)
01167                 {
01168                     notify(executor,
01169                        tprintf("Unrecognized switch '%s' for command '%s'.",
01170                        switchp, cmdp->cmdname));
01171                     return;
01172                 }
01173                 else if (xkey == -2)
01174                 {
01175                     notify(executor, NOPERM_MESSAGE);
01176                     return;
01177                 }
01178             }
01179             else if (!(xkey & SW_MULTIPLE))
01180             {
01181                 if (i == 1)
01182                 {
01183                     notify(executor, "Illegal combination of switches.");
01184                     return;
01185                 }
01186                 i = 1;
01187             }
01188             else
01189             {
01190                 xkey &= ~SW_MULTIPLE;
01191             }
01192             key |= xkey;
01193             switchp = buf1;
01194         } while (buf1);
01195     }
01196     else if (switchp && !(cmdp->callseq & CS_ADDED))
01197     {
01198         notify(executor, tprintf("Command %s does not take switches.",
01199             cmdp->cmdname));
01200         return;
01201     }
01202 
01203     // 'Before' hooks.
01204     // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson.
01205     //
01206     if (  (cmdp->hookmask & HOOK_BEFORE)
01207        && Good_obj(mudconf.hook_obj)
01208        && !Going(mudconf.hook_obj))
01209     {
01210         s_uselock = hook_name(cmdp->cmdname, HOOK_BEFORE);
01211         hk_ap2 = atr_str(s_uselock);
01212         process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false);
01213         free_sbuf(s_uselock);
01214     }
01215 
01216     // We are allowed to run the command.  Now, call the handler using
01217     // the appropriate calling sequence and arguments.
01218     //
01219     //if ((cmdp->callseq & CS_INTERP) && (key & SW_NOEVAL))
01220     if (key & SW_NOEVAL)
01221     {
01222         // The user specified /noeval on a @pemit or a @npemit,
01223         // just do EV_STRIP_CURLY and remove the SW_NOEVAL from the
01224         // 'key'.
01225         //
01226         interp = EV_STRIP_CURLY;
01227         key &= ~SW_NOEVAL;
01228     }
01229     else if (  (cmdp->callseq & CS_INTERP)
01230             || !( interactive
01231                || (cmdp->callseq & CS_NOINTERP)))
01232     {
01233         // If the command is interpreted, or we're interactive (and
01234         // the command isn't specified CS_NOINTERP), eval the args.
01235         //
01236         interp = EV_EVAL | EV_STRIP_CURLY;
01237     }
01238     else if (cmdp->callseq & CS_STRIP)
01239     {
01240         interp = EV_STRIP_CURLY;
01241     }
01242     else if (cmdp->callseq & CS_STRIP_AROUND)
01243     {
01244         interp = EV_STRIP_AROUND;
01245     }
01246     else
01247     {
01248         interp = 0;
01249     }
01250 
01251     int nargs2;
01252     switch (cmdp->callseq & CS_NARG_MASK)
01253     {
01254     case CS_NO_ARGS: // <cmd>   (no args)
01255         (*(((CMDENT_NO_ARG *)cmdp)->handler))(executor, caller, enactor, key);
01256         break;
01257 
01258     case CS_ONE_ARG:    // <cmd> <arg>
01259 
01260         // If an unparsed command, just give it to the handler
01261         //
01262 #if 0
01263         // This never happens.
01264         //
01265         if (cmdp->callseq & CS_UNPARSE)
01266         {
01267             (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, unp_command);
01268             break;
01269         }
01270 #endif
01271         // Interpret if necessary, but not twice for CS_ADDED.
01272         //
01273         if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED))
01274         {
01275             buf1 = bp = alloc_lbuf("process_cmdent");
01276             str = arg;
01277             mux_exec(buf1, &bp, executor, caller, enactor,
01278                 interp | EV_FCHECK | EV_TOP, &str, cargs, ncargs);
01279             *bp = '\0';
01280         }
01281         else
01282         {
01283             buf1 = parse_to(&arg, '\0', interp | EV_TOP);
01284         }
01285 
01286 
01287         // Call the correct handler.
01288         //
01289         if (cmdp->callseq & CS_CMDARG)
01290         {
01291             (*(((CMDENT_ONE_ARG_CMDARG *)cmdp)->handler))(executor, caller,
01292                 enactor, key, buf1, cargs, ncargs);
01293         }
01294         else if (cmdp->callseq & CS_ADDED)
01295         {
01296             for (add = cmdp->addent; add != NULL; add = add->next)
01297             {
01298                 buff = atr_get(add->thing, add->atr, &aowner, &aflags);
01299 
01300                 // Attribute should contain at least two characters and first
01301                 // character is '$'.
01302                 //
01303                 if (  AMATCH_CMD != buff[0]
01304                    || '\0' == buff[1])
01305                 {
01306                     free_lbuf(buff);
01307                     break;
01308                 }
01309 
01310                 // Skip the '$' character and the next to allow "$::cmd".
01311                 //
01312                 size_t iBuff;
01313                 for (iBuff = 2;  '\0' != buff[iBuff]
01314                               && ':'  != buff[iBuff]; iBuff++)
01315                 {
01316                     ; // Nothing.
01317                 }
01318 
01319                 if ('\0' == buff[iBuff])
01320                 {
01321                     free_lbuf(buff);
01322                     break;
01323                 }
01324                 buff[iBuff++] = '\0';
01325 
01326                 if (!(cmdp->callseq & CS_LEADIN))
01327                 {
01328                     for (j = unp_command; *j && (*j != ' '); j++) ;
01329                 }
01330                 else
01331                 {
01332                     for (j = unp_command; *j; j++) ;
01333                 }
01334 
01335                 new0 = alloc_lbuf("process_cmdent.soft");
01336                 bp = new0;
01337                 if (!*j)
01338                 {
01339                     // No args.
01340                     //
01341                     if (!(cmdp->callseq & CS_LEADIN))
01342                     {
01343                         safe_str(cmdp->cmdname, new0, &bp);
01344                     }
01345                     else
01346                     {
01347                         safe_str(unp_command, new0, &bp);
01348                     }
01349                     if (switchp)
01350                     {
01351                         safe_chr('/', new0, &bp);
01352                         safe_str(switchp, new0, &bp);
01353                     }
01354                     *bp = '\0';
01355                 }
01356                 else
01357                 {
01358                     j++;
01359                     safe_str(cmdp->cmdname, new0, &bp);
01360                     if (switchp)
01361                     {
01362                         safe_chr('/', new0, &bp);
01363                         safe_str(switchp, new0, &bp);
01364                     }
01365                     safe_chr(' ', new0, &bp);
01366                     safe_str(j, new0, &bp);
01367                     *bp = '\0';
01368                 }
01369 
01370                 if (  (  (aflags & AF_REGEXP)
01371                       && regexp_match(buff + 1, new0,
01372                              ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), aargs,
01373                              NUM_ENV_VARS))
01374                    || (  (aflags & AF_REGEXP) == 0
01375                       && wild(buff + 1, new0, aargs, NUM_ENV_VARS)))
01376                 {
01377                     CLinearTimeAbsolute lta;
01378                     wait_que(add->thing, caller, executor, false, lta,
01379                         NOTHING, 0, buff + iBuff, aargs, NUM_ENV_VARS, mudstate.global_regs);
01380                     for (i = 0; i < NUM_ENV_VARS; i++)
01381                     {
01382                         if (aargs[i])
01383                         {
01384                             free_lbuf(aargs[i]);
01385                         }
01386                     }
01387                 }
01388                 free_lbuf(new0);
01389                 free_lbuf(buff);
01390             }
01391         }
01392         else
01393         {
01394             (*(((CMDENT_ONE_ARG *)cmdp)->handler))(executor, caller,
01395                 enactor, key, buf1);
01396         }
01397 
01398         // Free the buffer if one was allocated.
01399         //
01400         if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED))
01401         {
01402             free_lbuf(buf1);
01403         }
01404         break;
01405 
01406     case CS_TWO_ARG: // <cmd> <arg1> = <arg2>
01407 
01408         // Interpret ARG1
01409         //
01410         buf2 = parse_to(&arg, '=', EV_STRIP_TS);
01411 
01412         nargs2 = 0;
01413         if (buf2)
01414         {
01415             if (arg)
01416             {
01417                 nargs2 = 2;
01418             }
01419             else
01420             {
01421                 nargs2 = 1;
01422             }
01423         }
01424 
01425         // Handle when no '=' was specified.
01426         //
01427         if (!arg || (arg && !*arg))
01428         {
01429             arg = &tchar;
01430             *arg = '\0';
01431         }
01432         buf1 = bp = alloc_lbuf("process_cmdent.2");
01433         str = buf2;
01434         mux_exec(buf1, &bp, executor, caller, enactor,
01435             EV_STRIP_CURLY | EV_FCHECK | EV_EVAL | EV_TOP, &str, cargs, ncargs);
01436         *bp = '\0';
01437 
01438         if (cmdp->callseq & CS_ARGV)
01439         {
01440             // Arg2 is ARGV style.  Go get the args.
01441             //
01442             parse_arglist(executor, caller, enactor, arg, '\0',
01443                 interp | EV_STRIP_LS | EV_STRIP_TS, args, MAX_ARG, cargs,
01444                 ncargs, &nargs);
01445 
01446             // Call the correct command handler.
01447             //
01448             if (cmdp->callseq & CS_CMDARG)
01449             {
01450                 (*(((CMDENT_TWO_ARG_ARGV_CMDARG *)cmdp)->handler))(executor,
01451                     caller, enactor, key, buf1, args, nargs, cargs, ncargs);
01452             }
01453             else
01454             {
01455                 (*(((CMDENT_TWO_ARG_ARGV *)cmdp)->handler))(executor, caller,
01456                     enactor, key, buf1, args, nargs);
01457             }
01458 
01459             // Free the argument buffers.
01460             //
01461             for (i = 0; i < nargs; i++)
01462             {
01463                 free_lbuf(args[i]);
01464             }
01465         }
01466         else
01467         {
01468             // Arg2 is normal style.  Interpret if needed.
01469             //
01470             if (interp & EV_EVAL)
01471             {
01472                 buf2 = bp = alloc_lbuf("process_cmdent.3");
01473                 str = arg;
01474                 mux_exec(buf2, &bp, executor, caller, enactor,
01475                     interp | EV_FCHECK | EV_TOP, &str, cargs, ncargs);
01476                 *bp = '\0';
01477             }
01478             else if (cmdp->callseq & CS_UNPARSE)
01479             {
01480                 buf2 = parse_to(&arg, '\0', interp | EV_TOP | EV_NO_COMPRESS);
01481             }
01482             else
01483             {
01484                 buf2 = parse_to(&arg, '\0', interp | EV_STRIP_LS | EV_STRIP_TS | EV_TOP);
01485             }
01486 
01487             // Call the correct command handler.
01488             //
01489             if (cmdp->callseq & CS_CMDARG)
01490             {
01491                 (*(((CMDENT_TWO_ARG_CMDARG *)cmdp)->handler))(executor,
01492                     caller, enactor, key, buf1, buf2, cargs, ncargs);
01493             }
01494             else
01495             {
01496                 (*(((CMDENT_TWO_ARG *)cmdp)->handler))(executor, caller,
01497                     enactor, key, nargs2, buf1, buf2);
01498             }
01499 
01500             // Free the buffer, if needed.
01501             //
01502             if (interp & EV_EVAL)
01503             {
01504                 free_lbuf(buf2);
01505             }
01506         }
01507 
01508         // Free the buffer obtained by evaluating Arg1.
01509         //
01510         free_lbuf(buf1);
01511         break;
01512     }
01513 
01514     // 'After' hooks.
01515     // @hook idea from TinyMUSH 3, code from RhostMUSH. Ported by Jake Nelson.
01516     //
01517     if (  (cmdp->hookmask & HOOK_AFTER)
01518         && Good_obj(mudconf.hook_obj)
01519         && !Going(mudconf.hook_obj))
01520     {
01521         s_uselock = hook_name(cmdp->cmdname, HOOK_AFTER);
01522         hk_ap2 = atr_str(s_uselock);
01523         (void)process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false);
01524         free_sbuf(s_uselock);
01525     }
01526     return;
01527 }
01528 
01529 static int cmdtest(dbref player, char *cmd)
01530 {
01531     char *buff1, *pt1, *pt2;
01532     dbref aowner;
01533     int aflags, rval;
01534 
01535     rval = 0;
01536     buff1 = atr_get(player, A_CMDCHECK, &aowner, &aflags);
01537     pt1 = buff1;
01538     while (pt1 && *pt1)
01539     {
01540         pt2 = strchr(pt1, ':');
01541         if (!pt2 || (pt2 == pt1))
01542             break;
01543         if (!strncmp(pt2+1, cmd, strlen(cmd)))
01544         {
01545             if (*(pt2-1) == '1')
01546                 rval = 1;
01547             else
01548                 rval = 2;
01549             break;
01550         }
01551         pt1 = strchr(pt2+1,' ');
01552         if (pt1 && *pt1)
01553         {
01554             while (mux_isspace(*pt1))
01555             {
01556                 pt1++;
01557             }
01558         }
01559     }
01560     free_lbuf(buff1);
01561     return rval;
01562 }
01563 
01564 static int zonecmdtest(dbref player, char *cmd)
01565 {
01566     if (!Good_obj(player) || God(player))
01567     {
01568         return 0;
01569     }
01570     dbref loc = Location(player);
01571 
01572     int i_ret = 0;
01573     if (Good_obj(loc))
01574     {
01575         i_ret = cmdtest(loc, cmd);
01576         if (i_ret == 0)
01577         {
01578             dbref zone = Zone(loc);
01579             if (  Good_obj(zone)
01580                && (  isRoom(zone)
01581                   || isThing(zone)))
01582             {
01583                 i_ret = cmdtest(zone, cmd);
01584             }
01585         }
01586     }
01587     return i_ret;
01588 }
01589 
01590 static int higcheck(dbref executor, dbref caller, dbref enactor, CMDENT *cmdp,
01591              char *pCommand)
01592 {
01593     UNUSED_PARAMETER(caller);
01594     UNUSED_PARAMETER(enactor);
01595     UNUSED_PARAMETER(pCommand);
01596 
01597     if (  Good_obj(mudconf.hook_obj)
01598        && !Going(mudconf.hook_obj))
01599     {
01600         char *s_uselock;
01601         ATTR *checkattr;
01602         bool bResult;
01603         if (cmdp->hookmask & HOOK_IGNORE)
01604         {
01605             s_uselock = hook_name(cmdp->cmdname, HOOK_IGNORE);
01606             checkattr = atr_str(s_uselock);
01607             bResult = process_hook(executor, mudconf.hook_obj, s_uselock,
01608                 checkattr, true);
01609             free_sbuf(s_uselock);
01610             if (!bResult)
01611             {
01612                 return 2;
01613             }
01614         }
01615         if (cmdp->hookmask & HOOK_PERMIT)
01616         {
01617             s_uselock = hook_name(cmdp->cmdname, HOOK_PERMIT);
01618             checkattr = atr_str(s_uselock);
01619             bResult = process_hook(executor, mudconf.hook_obj, s_uselock,
01620                 checkattr, true);
01621             free_sbuf(s_uselock);
01622             if (!bResult)
01623             {
01624                 return 1;
01625             }
01626         }
01627     }
01628     return 0;
01629 }
01630 
01631 static void hook_fail(dbref executor, CMDENT *cmdp, char *pCommand)
01632 {
01633     UNUSED_PARAMETER(pCommand);
01634 
01635     if (  Good_obj(mudconf.hook_obj)
01636        && !Going(mudconf.hook_obj))
01637     {
01638         char *s_uselock = hook_name(cmdp->cmdname, HOOK_AFAIL);
01639         ATTR *hk_ap2 = atr_str(s_uselock);
01640         process_hook(executor, mudconf.hook_obj, s_uselock, hk_ap2, false);
01641         free_sbuf(s_uselock);
01642     }
01643 }
01644 
01645 // ---------------------------------------------------------------------------
01646 // process_command: Execute a command.
01647 //
01648 char *process_command
01649 (
01650     dbref executor,
01651     dbref caller,
01652     dbref enactor,
01653     bool  interactive,
01654     char *arg_command,
01655     char *args[],
01656     int   nargs
01657 )
01658 {
01659     static char preserve_cmd[LBUF_SIZE];
01660     char *pOriginalCommand = arg_command;
01661     static char SpaceCompressCommand[LBUF_SIZE];
01662     static char LowerCaseCommand[LBUF_SIZE];
01663     char *pCommand;
01664     char *p, *q, *arg, *pSlash, *cmdsave, *bp, *str, check2[2];
01665     int aflags, i;
01666     dbref exit, aowner;
01667     CMDENT *cmdp;
01668 
01669     // Robustify player.
01670     //
01671     cmdsave = mudstate.debug_cmd;
01672     mudstate.debug_cmd = (char *)"< process_command >";
01673     mudstate.nStackNest = 0;
01674     mudstate.bStackLimitReached = false;
01675     *(check2 + 1) = '\0';
01676 
01677     mux_assert(pOriginalCommand);
01678 
01679     if (!Good_obj(executor))
01680     {
01681         // We are using SpaceCompressCommand temporarily.
01682         //
01683         STARTLOG(LOG_BUGS, "CMD", "PLYR");
01684         sprintf(SpaceCompressCommand, "Bad player in process_command: %d",
01685             executor);
01686         log_text(SpaceCompressCommand);
01687         ENDLOG;
01688         mudstate.debug_cmd = cmdsave;
01689         return pOriginalCommand;
01690     }
01691 
01692     // Make sure player isn't going or halted.
01693     //
01694     if (  Going(executor)
01695        || (  Halted(executor)
01696           && !(  isPlayer(executor)
01697               && interactive)))
01698     {
01699         notify(Owner(executor),
01700             tprintf("Attempt to execute command by halted object #%d", executor));
01701         mudstate.debug_cmd = cmdsave;
01702         return pOriginalCommand;
01703     }
01704     if (  Suspect(executor)
01705        && (mudconf.log_options & LOG_SUSPECTCMDS))
01706     {
01707         STARTLOG(LOG_SUSPECTCMDS, "CMD", "SUSP");
01708         log_name_and_loc(executor);
01709         log_text(" entered: ");
01710         log_text(pOriginalCommand);
01711         ENDLOG;
01712     }
01713     else
01714     {
01715         STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL");
01716         log_name_and_loc(executor);
01717         log_text(" entered: ");
01718         log_text(pOriginalCommand);
01719         ENDLOG;
01720     }
01721 
01722     // Reset recursion limits.
01723     //
01724     mudstate.func_nest_lev = 0;
01725     mudstate.func_invk_ctr = 0;
01726     mudstate.ntfy_nest_lev = 0;
01727     mudstate.lock_nest_lev = 0;
01728 
01729     if (Verbose(executor))
01730     {
01731         notify(Owner(executor), tprintf("%s] %s", Name(executor), pOriginalCommand));
01732     }
01733 
01734     // Eat leading whitespace, and space-compress if configured.
01735     //
01736     while (mux_isspace(*pOriginalCommand))
01737     {
01738         pOriginalCommand++;
01739     }
01740     strcpy(preserve_cmd, pOriginalCommand);
01741     mudstate.debug_cmd = pOriginalCommand;
01742     mudstate.curr_cmd = preserve_cmd;
01743 
01744     if (mudconf.space_compress)
01745     {
01746         // Compress out the spaces and use that as the command
01747         //
01748         pCommand = SpaceCompressCommand;
01749 
01750         p = pOriginalCommand;
01751         q = SpaceCompressCommand;
01752         while (  *p
01753               && q < SpaceCompressCommand + LBUF_SIZE)
01754         {
01755             while (  *p
01756                   && !mux_isspace(*p)
01757                   && q < SpaceCompressCommand + LBUF_SIZE)
01758             {
01759                 *q++ = *p++;
01760             }
01761 
01762             while (mux_isspace(*p))
01763             {
01764                 p++;
01765             }
01766 
01767             if (  *p
01768                && q < SpaceCompressCommand + LBUF_SIZE)
01769             {
01770                 *q++ = ' ';
01771             }
01772         }
01773         *q = '\0';
01774     }
01775     else
01776     {
01777         // Don't compress the spaces. Use the original command
01778         // (without leading spaces) as the command to use.
01779         //
01780         pCommand = pOriginalCommand;
01781     }
01782 
01783     // Now comes the fun stuff.  First check for single-letter leadins.
01784     // We check these before checking HOME because they are among the
01785     // most frequently executed commands, and they can never be the
01786     // HOME command.
01787     //
01788     i = pCommand[0] & 0xff;
01789     int cval = 0;
01790     int hval = 0;
01791     if (i && (prefix_cmds[i] != NULL))
01792     {
01793         // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
01794         // Both from RhostMUSH.
01795         // cval/hval values: 0 normal, 1 disable, 2 ignore
01796         //
01797         *check2 = (char)i;
01798         if (CmdCheck(executor))
01799         {
01800             cval = cmdtest(executor, check2);
01801         }
01802         else if (CmdCheck(Owner(executor)))
01803         {
01804             cval = cmdtest(Owner(executor), check2);
01805         }
01806         else
01807         {
01808             cval = 0;
01809         }
01810 
01811         if (cval == 0)
01812         {
01813             cval = zonecmdtest(executor, check2);
01814         }
01815 
01816         if (prefix_cmds[i]->hookmask & (HOOK_IGNORE|HOOK_PERMIT))
01817         {
01818             hval = higcheck(executor, caller, enactor, prefix_cmds[i], pCommand);
01819         }
01820         else
01821         {
01822             hval = 0;
01823         }
01824 
01825         if (  cval != 2
01826            && hval != 2)
01827         {
01828             if (  cval == 1
01829                || hval == 1)
01830             {
01831                 if (prefix_cmds[i]->hookmask & HOOK_AFAIL)
01832                 {
01833                     hook_fail(executor, prefix_cmds[i], pCommand);
01834                 }
01835                 else
01836                 {
01837                     notify(executor, NOPERM_MESSAGE);
01838                 }
01839                 return preserve_cmd;
01840             }
01841             process_cmdent(prefix_cmds[i], NULL, executor, caller, enactor,
01842                 interactive, pCommand, pCommand, args, nargs);
01843             if (mudstate.bStackLimitReached)
01844             {
01845                 STARTLOG(LOG_ALWAYS, "CMD", "SPAM");
01846                 log_name_and_loc(executor);
01847                 log_text(" entered: ");
01848                 log_text(pOriginalCommand);
01849                 ENDLOG;
01850             }
01851             mudstate.bStackLimitReached = false;
01852 
01853             mudstate.debug_cmd = cmdsave;
01854             return preserve_cmd;
01855         }
01856     }
01857 
01858     if (  mudconf.have_comsys
01859        && !Slave(executor)
01860        && !do_comsystem(executor, pCommand))
01861     {
01862         return preserve_cmd;
01863     }
01864 
01865     // Check for the HOME command.
01866     //
01867     if (  Has_location(executor)
01868        && string_compare(pCommand, "home") == 0)
01869     {
01870         // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
01871         // Both from RhostMUSH.
01872         // cval/hval values: 0 normal, 1 disable, 2 ignore.
01873         //
01874         if (CmdCheck(executor))
01875         {
01876             cval = cmdtest(executor, "home");
01877         }
01878         else if (CmdCheck(Owner(executor)))
01879         {
01880             cval = cmdtest(Owner(executor), "home");
01881         }
01882         else
01883         {
01884             cval = 0;
01885         }
01886 
01887         if (cval == 0)
01888         {
01889             cval = zonecmdtest(executor, "home");
01890         }
01891 
01892         if (cval != 2)
01893         {
01894             if (!check_access(executor, mudconf.restrict_home))
01895             {
01896                 notify(executor, NOPERM_MESSAGE);
01897                 return preserve_cmd;
01898             }
01899             if (cval == 1)
01900             {
01901                 notify(executor, NOPERM_MESSAGE);
01902                 return preserve_cmd;
01903             }
01904             if (  (  Fixed(executor)
01905                   || Fixed(Owner(executor)))
01906                && !WizRoy(executor))
01907             {
01908                 notify(executor, mudconf.fixed_home_msg);
01909                 return preserve_cmd;
01910             }
01911             do_move(executor, caller, enactor, 0, "home");
01912             mudstate.debug_cmd = cmdsave;
01913             return preserve_cmd;
01914         }
01915     }
01916 
01917     // Only check for exits if we may use the goto command.
01918     //
01919     if (check_access(executor, goto_cmdp->perms))
01920     {
01921         // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
01922         // Both from RhostMUSH.
01923         // cval/hval values: 0 normal, 1 disable, 2 ignore
01924         // Master room exits are not affected.
01925         //
01926         if (CmdCheck(executor))
01927         {
01928             cval = cmdtest(executor, "goto");
01929         }
01930         else if (CmdCheck(Owner(executor)))
01931         {
01932             cval = cmdtest(Owner(executor), "goto");
01933         }
01934         else
01935         {
01936             cval = 0;
01937         }
01938 
01939         if (cval == 0)
01940         {
01941             cval = zonecmdtest(executor, "goto");
01942         }
01943 
01944         if (goto_cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT))
01945         {
01946             hval = higcheck(executor, caller, enactor, goto_cmdp, "goto");
01947         }
01948         else
01949         {
01950             hval = 0;
01951         }
01952 
01953         if (  cval != 2
01954            && hval != 2)
01955         {
01956             // Check for an exit name.
01957             //
01958             init_match_check_keys(executor, pCommand, TYPE_EXIT);
01959             match_exit_with_parents();
01960             exit = last_match_result();
01961             if (exit != NOTHING)
01962             {
01963                 if (cval || hval)
01964                 {
01965                     if (goto_cmdp->hookmask & HOOK_AFAIL)
01966                     {
01967                         hook_fail(executor, goto_cmdp, "goto");
01968                     }
01969                     else
01970                     {
01971                         notify(executor, NOPERM_MESSAGE);
01972                     }
01973                     return preserve_cmd;
01974                 }
01975                 move_exit(executor, exit, false, "You can't go that way.", 0);
01976                 mudstate.debug_cmd = cmdsave;
01977                 return preserve_cmd;
01978             }
01979 
01980             // Check for an exit in the master room.
01981             //
01982             init_match_check_keys(executor, pCommand, TYPE_EXIT);
01983             match_master_exit();
01984             exit = last_match_result();
01985             if (exit != NOTHING)
01986             {
01987                 move_exit(executor, exit, true, NULL, 0);
01988                 mudstate.debug_cmd = cmdsave;
01989                 return preserve_cmd;
01990             }
01991         }
01992     }
01993 
01994     // Set up a lowercase command and an arg pointer for the hashed
01995     // command check.  Since some types of argument processing destroy
01996     // the arguments, make a copy so that we keep the original command
01997     // line intact.  Store the edible copy in LowerCaseCommand after
01998     // the lower-cased command.
01999     //
02000 
02001     // Make lowercase command
02002     //
02003     for (p = pCommand, q = LowerCaseCommand;
02004          *p && !mux_isspace(*p);
02005          p++, q++)
02006     {
02007         *q = mux_tolower(*p);
02008     }
02009     *q = '\0';
02010     int nLowerCaseCommand = q - LowerCaseCommand;
02011 
02012     // Skip spaces before arg
02013     //
02014     while (mux_isspace(*p))
02015     {
02016         p++;
02017     }
02018 
02019     // Remember where arg starts
02020     //
02021     arg = p;
02022 
02023     // Strip off any command switches and save them.
02024     //
02025     pSlash = strchr(LowerCaseCommand, '/');
02026     if (pSlash)
02027     {
02028         nLowerCaseCommand = pSlash - LowerCaseCommand;
02029         *pSlash++ = '\0';
02030     }
02031 
02032     // Check for a builtin command (or an alias of a builtin command)
02033     //
02034     cmdp = (CMDENT *)hashfindLEN(LowerCaseCommand, nLowerCaseCommand, &mudstate.command_htab);
02035 
02036     /* If command is checked to ignore NONMATCHING switches, fall through */
02037     if (cmdp)
02038     {
02039         // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
02040         // Both from RhostMUSH.
02041         // cval/hval values: 0 normal, 1 disable, 2 ignore
02042         //
02043         if (CmdCheck(executor))
02044         {
02045             cval = cmdtest(executor, cmdp->cmdname);
02046         }
02047         else if (CmdCheck(Owner(executor)))
02048         {
02049             cval = cmdtest(Owner(executor), cmdp->cmdname);
02050         }
02051         else
02052         {
02053             cval = 0;
02054         }
02055 
02056         if (cval == 0)
02057         {
02058             cval = zonecmdtest(executor, cmdp->cmdname);
02059         }
02060 
02061         if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT))
02062         {
02063             hval = higcheck(executor, caller, enactor, cmdp, LowerCaseCommand);
02064         }
02065         else
02066         {
02067             hval = 0;
02068         }
02069 
02070         // If the command contains a switch, but the command doesn't support
02071         // any switches or the command contains one that isn't supported,
02072         // HOOK_IGSWITCH will allow us to treat the entire command as if it
02073         // weren't a built-in command.
02074         //
02075         int flagvalue;
02076         if (  (cmdp->hookmask & HOOK_IGSWITCH)
02077            && pSlash)
02078         {
02079             if (cmdp->switches)
02080             {
02081                 search_nametab(executor, cmdp->switches, pSlash, &flagvalue);
02082                 if (flagvalue & SW_MULTIPLE)
02083                 {
02084                     MUX_STRTOK_STATE ttswitch;
02085                     // All the switches given a command shouldn't exceed 200 chars together
02086                     char switch_buff[200];
02087                     char *switch_ptr;
02088                     sprintf(switch_buff, "%.199s", pSlash);
02089                     mux_strtok_src(&ttswitch, switch_buff);
02090                     mux_strtok_ctl(&ttswitch, "/");
02091                     switch_ptr = mux_strtok_parse(&ttswitch);
02092                     while (  switch_ptr
02093                           && *switch_ptr)
02094                     {
02095                         search_nametab(executor, cmdp->switches, switch_ptr, &flagvalue);
02096                         if (flagvalue == -1)
02097                         {
02098                             break;
02099                         }
02100                         switch_ptr = mux_strtok_parse(&ttswitch);
02101                     }
02102                 }
02103                 if (flagvalue == -1)
02104                 {
02105                     cval = 2;
02106                 }
02107             }
02108             else
02109             {
02110                 // Switch exists but no switches allowed for command.
02111                 //
02112                 cval = 2;
02113             }
02114         }
02115 
02116         if (  cval != 2
02117            && hval != 2)
02118         {
02119             if (  cval == 1
02120                || hval == 1)
02121             {
02122                 if (cmdp->hookmask & HOOK_AFAIL)
02123                 {
02124                     hook_fail(executor, cmdp, LowerCaseCommand);
02125                 }
02126                 else
02127                 {
02128                     notify(executor, NOPERM_MESSAGE);
02129                 }
02130                 return preserve_cmd;
02131             }
02132             if (  mudconf.space_compress
02133                && (cmdp->callseq & CS_NOSQUISH))
02134             {
02135                 // We handle this specially -- there is no space compression
02136                 // involved, so we must go back to the original command.
02137                 // We skip over the command and a single space to position
02138                 // arg at the arguments.
02139                 //
02140                 arg = pCommand = pOriginalCommand;
02141                 while (*arg && !mux_isspace(*arg))
02142                 {
02143                     arg++;
02144                 }
02145                 if (*arg)
02146                 {
02147                     // We stopped on the space, advance to next.
02148                     //
02149                     arg++;
02150                 }
02151             }
02152             process_cmdent(cmdp, pSlash, executor, caller, enactor, interactive,
02153                 arg, pCommand, args, nargs);
02154             if (mudstate.bStackLimitReached)
02155             {
02156                 STARTLOG(LOG_ALWAYS, "CMD", "SPAM");
02157                 log_name_and_loc(executor);
02158                 log_text(" entered: ");
02159                 log_text(pOriginalCommand);
02160                 ENDLOG;
02161             }
02162             mudstate.bStackLimitReached = false;
02163             mudstate.debug_cmd = cmdsave;
02164             return preserve_cmd;
02165         }
02166     }
02167 
02168     // Check for enter and leave aliases, user-defined commands on the
02169     // player, other objects where the player is, on objects in the
02170     // player's inventory, and on the room that holds the player. We
02171     // evaluate the command line here to allow chains of $-commands
02172     // to work.
02173     //
02174     bp = LowerCaseCommand;
02175     str = pCommand;
02176     mux_exec(LowerCaseCommand, &bp, executor, caller, enactor,
02177         EV_EVAL | EV_FCHECK | EV_STRIP_CURLY | EV_TOP, &str, args, nargs);
02178     *bp = '\0';
02179     bool succ = false;
02180 
02181     // Idea for enter/leave aliases from R'nice@TinyTIM
02182     //
02183     if (Has_location(executor) && Good_obj(Location(executor)))
02184     {
02185         // Check for a leave alias.
02186         //
02187         p = atr_pget(Location(executor), A_LALIAS, &aowner, &aflags);
02188         if (*p)
02189         {
02190             if (matches_exit_from_list(LowerCaseCommand, p))
02191             {
02192                 free_lbuf(p);
02193 
02194                 // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
02195                 // Both from RhostMUSH.
02196                 // cval/hval values: 0 normal, 1 disable, 2 ignore
02197                 //
02198                 if (CmdCheck(executor))
02199                 {
02200                     cval = cmdtest(executor, "leave");
02201                 }
02202                 else if (CmdCheck(Owner(executor)))
02203                 {
02204                     cval = cmdtest(Owner(executor), "leave");
02205                 }
02206                 else
02207                 {
02208                     cval = 0;
02209                 }
02210 
02211                 if (cval == 0)
02212                 {
02213                     cval = zonecmdtest(executor, "leave");
02214                 }
02215 
02216                 cmdp = (CMDENT *)hashfindLEN((char *)"leave", strlen("leave"), &mudstate.command_htab);
02217 
02218                 if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT))
02219                 {
02220                     hval = higcheck(executor, caller, enactor, cmdp, "leave");
02221                 }
02222                 else
02223                 {
02224                     hval = 0;
02225                 }
02226 
02227                 if (  cval != 2
02228                    && hval != 2)
02229                 {
02230                     if (  cval == 1
02231                        || hval == 1)
02232                     {
02233                         if (cmdp->hookmask & HOOK_AFAIL)
02234                         {
02235                             hook_fail(executor, cmdp, "leave");
02236                         }
02237                         else
02238                         {
02239                             notify(executor, NOPERM_MESSAGE);
02240                         }
02241                         return preserve_cmd;
02242                     }
02243                     do_leave(executor, caller, executor, 0);
02244                     return preserve_cmd;
02245                 }
02246             }
02247         }
02248         free_lbuf(p);
02249 
02250         DOLIST(exit, Contents(Location(executor)))
02251         {
02252             p = atr_pget(exit, A_EALIAS, &aowner, &aflags);
02253             if (*p)
02254             {
02255                 if (matches_exit_from_list(LowerCaseCommand, p))
02256                 {
02257                     free_lbuf(p);
02258 
02259                     // Check for enter aliases.
02260                     //
02261                     // CmdCheck tests for @icmd. higcheck tests for i/p hooks.
02262                     // Both from RhostMUSH.
02263                     // cval/hval values: 0 normal, 1 disable, 2 ignore
02264                     //
02265                     if (CmdCheck(executor))
02266                     {
02267                         cval = cmdtest(executor, "enter");
02268                     }
02269                     else if (CmdCheck(Owner(executor)))
02270                     {
02271                         cval = cmdtest(Owner(executor), "enter");
02272                     }
02273                     else
02274                     {
02275                         cval = 0;
02276                     }
02277 
02278                     if (cval == 0)
02279                     {
02280                         cval = zonecmdtest(executor, "enter");
02281                     }
02282 
02283                     cmdp = (CMDENT *)hashfindLEN((char *)"enter", strlen("enter"), &mudstate.command_htab);
02284 
02285                     if (cmdp->hookmask & (HOOK_IGNORE|HOOK_PERMIT))
02286                     {
02287                         hval = higcheck(executor, caller, enactor, cmdp, "enter");
02288                     }
02289                     else
02290                     {
02291                         hval = 0;
02292                     }
02293 
02294                     if (  cval != 2
02295                        && hval != 2)
02296                     {
02297                         if (  cval == 1
02298                            || hval == 1)
02299                         {
02300                             if (cmdp->hookmask & HOOK_AFAIL)
02301                             {
02302                                 hook_fail(executor, cmdp, "enter");
02303                             }
02304                             else
02305                             {
02306                                 notify(executor, NOPERM_MESSAGE);
02307                             }
02308                             return preserve_cmd;
02309                         }
02310                         do_enter_internal(executor, exit, false);
02311                         return preserve_cmd;
02312                     }
02313                     else if (cval == 1)
02314                     {
02315                         notify_quiet(executor, NOPERM_MESSAGE);
02316                         return preserve_cmd;
02317                     }
02318                 }
02319             }
02320             free_lbuf(p);
02321         }
02322     }
02323 
02324     // Check for $-command matches on me.
02325     //
02326     if (mudconf.match_mine && !No_Command(executor))
02327     {
02328         if (  (  !isPlayer(executor)
02329               || mudconf.match_mine_pl)
02330            && atr_match(executor, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true))
02331         {
02332             succ = true;
02333         }
02334     }
02335 
02336     // Check for $-command matches on nearby things and on my room.
02337     //
02338     if (Has_location(executor))
02339     {
02340         succ |= list_check(Contents(Location(executor)), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true);
02341 
02342         if (!No_Command(Location(executor)))
02343         {
02344             succ |= atr_match(Location(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true);
02345         }
02346     }
02347 
02348     // Check for $-command matches in my inventory.
02349     //
02350     if (Has_contents(executor))
02351     {
02352         succ |= list_check(Contents(executor), executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true);
02353     }
02354 
02355     if (  !succ
02356        && mudconf.have_zones)
02357     {
02358         // now do check on zones.
02359         //
02360         dbref zone = Zone(executor);
02361         dbref loc = Location(executor);
02362         dbref zone_loc = NOTHING;
02363         if (  Good_obj(loc)
02364            && Good_obj(zone_loc = Zone(loc)))
02365         {
02366             if (isRoom(zone_loc))
02367             {
02368                 // zone of player's location is a parent room.
02369                 //
02370                 if (loc != zone)
02371                 {
02372                     // check parent room exits.
02373                     //
02374                     init_match_check_keys(executor, pCommand, TYPE_EXIT);
02375                     match_zone_exit();
02376                     exit = last_match_result();
02377                     if (exit != NOTHING)
02378                     {
02379                         move_exit(executor, exit, true, NULL, 0);
02380                         mudstate.debug_cmd = cmdsave;
02381                         return preserve_cmd;
02382                     }
02383                     succ |= list_check(Contents(zone_loc), executor,
02384                                AMATCH_CMD, LowerCaseCommand, preserve_cmd,
02385                                true);
02386 
02387                     // end of parent room checks.
02388                     //
02389                 }
02390             }
02391             else
02392             {
02393                 // try matching commands on area zone object.
02394                 //
02395                 if (!No_Command(zone_loc))
02396                 {
02397                     succ |= atr_match(zone_loc, executor, AMATCH_CMD,
02398                        LowerCaseCommand, preserve_cmd, true);
02399                 }
02400             }
02401         }
02402 
02403         // End of matching on zone of player's location.
02404         //
02405 
02406         // if nothing matched with parent room/zone object, try matching
02407         // zone commands on the player's personal zone.
02408         //
02409         if (  !succ
02410            && Good_obj(zone)
02411            && !No_Command(zone)
02412            && zone_loc != zone)
02413         {
02414             succ |= atr_match(zone, executor, AMATCH_CMD, LowerCaseCommand, preserve_cmd, true);
02415         }
02416     }
02417 
02418     // If we didn't find anything, try in the master room.
02419     //
02420     if (!succ)
02421     {
02422         if (  Good_obj(mudconf.master_room)
02423            && Has_contents(mudconf.master_room))
02424         {
02425             succ |= list_check(Contents(mudconf.master_room), executor,
02426                 AMATCH_CMD, LowerCaseCommand, preserve_cmd, false);
02427 
02428             if (!No_Command(mudconf.master_room))
02429             {
02430                 succ |= atr_match(mudconf.master_room, executor, AMATCH_CMD,
02431                     LowerCaseCommand, preserve_cmd, false);
02432             }
02433         }
02434     }
02435 
02436     // If we still didn't find anything, tell how to get help.
02437     //
02438     if (!succ)
02439     {
02440         if (  Good_obj(mudconf.global_error_obj)
02441            && !Going(mudconf.global_error_obj))
02442         {
02443             char *errtext = atr_get(mudconf.global_error_obj, A_VA, &aowner, &aflags);
02444             char *errbuff = alloc_lbuf("process_command.error_msg");
02445             char *errbufc = errbuff;
02446             str = errtext;
02447             mux_exec(errbuff, &errbufc, mudconf.global_error_obj, caller, enactor,
02448                 EV_EVAL | EV_FCHECK | EV_STRIP_CURLY | EV_TOP, &str,
02449                 &pCommand, 1);
02450             *errbufc = '\0';
02451             notify(executor, errbuff);
02452             free_lbuf(errtext);
02453             free_lbuf(errbuff);
02454         }
02455         else
02456         {
02457             // We use LowerCaseCommand for another purpose.
02458             //
02459             notify(executor, "Huh?  (Type \"help\" for help.)");
02460             STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD");
02461             log_name_and_loc(executor);
02462             log_text(" entered: ");
02463             log_text(pCommand);
02464             ENDLOG;
02465         }
02466     }
02467     mudstate.debug_cmd = cmdsave;
02468     return preserve_cmd;
02469 }
02470 
02471 // ---------------------------------------------------------------------------
02472 // list_cmdtable: List internal commands.
02473 //
02474 static void list_cmdtable(dbref player)
02475 {
02476     char *buf = alloc_lbuf("list_cmdtable");
02477     char *bp = buf;
02478     ITL itl;
02479     ItemToList_Init(&itl, buf, &bp);
02480     ItemToList_AddString(&itl, (char *)"Commands:");
02481 
02482     {
02483         CMDENT_NO_ARG *cmdp;
02484         for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
02485         {
02486             if (  check_access(player, cmdp->perms)
02487                 && !(cmdp->perms & CF_DARK))
02488             {
02489                 ItemToList_AddString(&itl, cmdp->cmdname);
02490             }
02491         }
02492     }
02493     {
02494         CMDENT_ONE_ARG *cmdp;
02495         for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
02496         {
02497             if (  check_access(player, cmdp->perms)
02498                 && !(cmdp->perms & CF_DARK))
02499             {
02500                 ItemToList_AddString(&itl, cmdp->cmdname);
02501             }
02502         }
02503     }
02504     {
02505         CMDENT_ONE_ARG_CMDARG *cmdp;
02506         for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
02507         {
02508             if (  check_access(player, cmdp->perms)
02509                 && !(cmdp->perms & CF_DARK))
02510             {
02511                 ItemToList_AddString(&itl, cmdp->cmdname);
02512             }
02513         }
02514     }
02515     {
02516         CMDENT_TWO_ARG *cmdp;
02517         for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
02518         {
02519             if (  check_access(player, cmdp->perms)
02520                 && !(cmdp->perms & CF_DARK))
02521             {
02522                 ItemToList_AddString(&itl, cmdp->cmdname);
02523             }
02524         }
02525     }
02526     {
02527         CMDENT_TWO_ARG_ARGV *cmdp;
02528         for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
02529         {
02530             if (  check_access(player, cmdp->perms)
02531                 && !(cmdp->perms & CF_DARK))
02532             {
02533                 ItemToList_AddString(&itl, cmdp->cmdname);
02534             }
02535         }
02536     }
02537     {
02538         CMDENT_TWO_ARG_CMDARG *cmdp;
02539         for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
02540         {
02541             if (  check_access(player, cmdp->perms)
02542                 && !(cmdp->perms & CF_DARK))
02543             {
02544                 ItemToList_AddString(&itl, cmdp->cmdname);
02545             }
02546         }
02547     }
02548     {
02549         CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
02550         for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
02551         {
02552             if (  check_access(player, cmdp->perms)
02553                 && !(cmdp->perms & CF_DARK))
02554             {
02555                 ItemToList_AddString(&itl, cmdp->cmdname);
02556             }
02557         }
02558     }
02559     ItemToList_Final(&itl);
02560     *bp = '\0';
02561 
02562     // Players get the list of logged-out cmds too
02563     //
02564     if (isPlayer(player))
02565     {
02566         display_nametab(player, logout_cmdtable, buf, true);
02567     }
02568     else
02569     {
02570         notify(player, buf);
02571     }
02572     free_lbuf(buf);
02573 }
02574 
02575 // ---------------------------------------------------------------------------
02576 // list_attrtable: List available attributes.
02577 //
02578 static void list_attrtable(dbref player)
02579 {
02580     ATTR *ap;
02581 
02582     char *buf = alloc_lbuf("list_attrtable");
02583     char *bp = buf;
02584     ITL itl;
02585     ItemToList_Init(&itl, buf, &bp);
02586     ItemToList_AddString(&itl, (char *)"Attributes:");
02587     for (ap = attr; ap->name; ap++)
02588     {
02589         if (See_attr(player, player, ap))
02590         {
02591             ItemToList_AddString(&itl, (char *)ap->name);
02592         }
02593     }
02594     ItemToList_Final(&itl);
02595     *bp = '\0';
02596     raw_notify(player, buf);
02597     free_lbuf(buf);
02598 }
02599 
02600 // ---------------------------------------------------------------------------
02601 // list_cmdaccess: List access commands.
02602 //
02603 NAMETAB access_nametab[] =
02604 {
02605     {"builder",               6, CA_WIZARD, CA_BUILDER},
02606     {"dark",                  4, CA_GOD,    CF_DARK},
02607     {"disabled",              4, CA_GOD,    CA_DISABLED},
02608     {"global_build",          8, CA_PUBLIC, CA_GBL_BUILD},
02609     {"global_interp",         8, CA_PUBLIC, CA_GBL_INTERP},
02610     {"god",                   2, CA_GOD,    CA_GOD},
02611     {"head",                  2, CA_WIZARD, CA_HEAD},
02612     {"immortal",              3, CA_WIZARD, CA_IMMORTAL},
02613     {"need_location",         6, CA_PUBLIC, CA_LOCATION},
02614     {"need_contents",         6, CA_PUBLIC, CA_CONTENTS},
02615     {"need_player",           6, CA_PUBLIC, CA_PLAYER},
02616     {"no_haven",              4, CA_PUBLIC, CA_NO_HAVEN},
02617     {"no_robot",              4, CA_WIZARD, CA_NO_ROBOT},
02618     {"no_slave",              5, CA_PUBLIC, CA_NO_SLAVE},
02619     {"no_suspect",            5, CA_WIZARD, CA_NO_SUSPECT},
02620     {"no_guest",              5, CA_WIZARD, CA_NO_GUEST},
02621     {"no_uninspected",        5, CA_WIZARD, CA_NO_UNINS},
02622     {"robot",                 2, CA_WIZARD, CA_ROBOT},
02623     {"staff",                 4, CA_WIZARD, CA_STAFF},
02624     {"static",                4, CA_GOD,    CA_STATIC},
02625     {"uninspected",           5, CA_WIZARD, CA_UNINS},
02626     {"wizard",                3, CA_WIZARD, CA_WIZARD},
02627     {NULL,                    0, 0,         0}
02628 };
02629 
02630 static void list_cmdaccess(dbref player)
02631 {
02632     ATTR *ap;
02633 
02634     char *buff = alloc_sbuf("list_cmdaccess");
02635     {
02636         CMDENT_NO_ARG *cmdp;
02637         for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
02638         {
02639             if (  check_access(player, cmdp->perms)
02640                && !(cmdp->perms & CF_DARK))
02641             {
02642                 sprintf(buff, "%.60s:", cmdp->cmdname);
02643                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02644             }
02645         }
02646     }
02647     {
02648         CMDENT_ONE_ARG *cmdp;
02649         for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
02650         {
02651             if (  check_access(player, cmdp->perms)
02652                && !(cmdp->perms & CF_DARK))
02653             {
02654                 sprintf(buff, "%.60s:", cmdp->cmdname);
02655                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02656             }
02657         }
02658     }
02659     {
02660         CMDENT_ONE_ARG_CMDARG *cmdp;
02661         for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
02662         {
02663             if (  check_access(player, cmdp->perms)
02664                && !(cmdp->perms & CF_DARK))
02665             {
02666                 sprintf(buff, "%.60s:", cmdp->cmdname);
02667                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02668             }
02669         }
02670     }
02671     {
02672         CMDENT_TWO_ARG *cmdp;
02673         for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
02674         {
02675             if (  check_access(player, cmdp->perms)
02676                && !(cmdp->perms & CF_DARK))
02677             {
02678                 sprintf(buff, "%.60s:", cmdp->cmdname);
02679                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02680             }
02681         }
02682     }
02683     {
02684         CMDENT_TWO_ARG_ARGV *cmdp;
02685         for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
02686         {
02687             if (  check_access(player, cmdp->perms)
02688                && !(cmdp->perms & CF_DARK))
02689             {
02690                 sprintf(buff, "%.60s:", cmdp->cmdname);
02691                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02692             }
02693         }
02694     }
02695     {
02696         CMDENT_TWO_ARG_CMDARG *cmdp;
02697         for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
02698         {
02699             if (  check_access(player, cmdp->perms)
02700                && !(cmdp->perms & CF_DARK))
02701             {
02702                 sprintf(buff, "%.60s:", cmdp->cmdname);
02703                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02704             }
02705         }
02706     }
02707     {
02708         CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
02709         for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
02710         {
02711             if (  check_access(player, cmdp->perms)
02712                && !(cmdp->perms & CF_DARK))
02713             {
02714                 sprintf(buff, "%.60s:", cmdp->cmdname);
02715                 listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02716             }
02717         }
02718     }
02719     free_sbuf(buff);
02720     for (ap = attr; ap->name; ap++)
02721     {
02722         if (ap->flags & AF_NOCMD)
02723         {
02724             continue;
02725         }
02726 
02727         int nBuffer;
02728         bool bValid;
02729         buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
02730         if (!bValid)
02731         {
02732             continue;
02733         }
02734 
02735         CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab);
02736         if (cmdp == NULL)
02737         {
02738             continue;
02739         }
02740 
02741         if (!check_access(player, cmdp->perms))
02742         {
02743             continue;
02744         }
02745 
02746         if (!(cmdp->perms & CF_DARK))
02747         {
02748             sprintf(buff, "%.60s:", cmdp->cmdname);
02749             listset_nametab(player, access_nametab, cmdp->perms, buff, true);
02750         }
02751     }
02752 }
02753 
02754 // ---------------------------------------------------------------------------
02755 // list_cmdswitches: List switches for commands.
02756 //
02757 static void list_cmdswitches(dbref player)
02758 {
02759     char *buff = alloc_sbuf("list_cmdswitches");
02760     {
02761         CMDENT_NO_ARG *cmdp;
02762         for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
02763         {
02764             if (cmdp->switches)
02765             {
02766                 if (check_access(player, cmdp->perms))
02767                 {
02768                     if (!(cmdp->perms & CF_DARK))
02769                     {
02770                         sprintf(buff, "%.60s:", cmdp->cmdname);
02771                         display_nametab(player, cmdp->switches, buff, false);
02772                     }
02773                 }
02774             }
02775         }
02776     }
02777     {
02778         CMDENT_ONE_ARG *cmdp;
02779         for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
02780         {
02781             if (cmdp->switches)
02782             {
02783                 if (check_access(player, cmdp->perms))
02784                 {
02785                     if (!(cmdp->perms & CF_DARK))
02786                     {
02787                         sprintf(buff, "%.60s:", cmdp->cmdname);
02788                         display_nametab(player, cmdp->switches, buff, false);
02789                     }
02790                 }
02791             }
02792         }
02793     }
02794     {
02795         CMDENT_ONE_ARG_CMDARG *cmdp;
02796         for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
02797         {
02798             if (cmdp->switches)
02799             {
02800                 if (check_access(player, cmdp->perms))
02801                 {
02802                     if (!(cmdp->perms & CF_DARK))
02803                     {
02804                         sprintf(buff, "%.60s:", cmdp->cmdname);
02805                         display_nametab(player, cmdp->switches, buff, false);
02806                     }
02807                 }
02808             }
02809         }
02810     }
02811     {
02812         CMDENT_TWO_ARG *cmdp;
02813         for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
02814         {
02815             if (cmdp->switches)
02816             {
02817                 if (check_access(player, cmdp->perms))
02818                 {
02819                     if (!(cmdp->perms & CF_DARK))
02820                     {
02821                         sprintf(buff, "%.60s:", cmdp->cmdname);
02822                         display_nametab(player, cmdp->switches, buff, false);
02823                     }
02824                 }
02825             }
02826         }
02827     }
02828     {
02829         CMDENT_TWO_ARG_ARGV *cmdp;
02830         for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
02831         {
02832             if (cmdp->switches)
02833             {
02834                 if (check_access(player, cmdp->perms))
02835                 {
02836                     if (!(cmdp->perms & CF_DARK))
02837                     {
02838                         sprintf(buff, "%.60s:", cmdp->cmdname);
02839                         display_nametab(player, cmdp->switches, buff, false);
02840                     }
02841                 }
02842             }
02843         }
02844     }
02845     {
02846         CMDENT_TWO_ARG_CMDARG *cmdp;
02847         for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
02848         {
02849             if (cmdp->switches)
02850             {
02851                 if (check_access(player, cmdp->perms))
02852                 {
02853                     if (!(cmdp->perms & CF_DARK))
02854                     {
02855                         sprintf(buff, "%.60s:", cmdp->cmdname);
02856                         display_nametab(player, cmdp->switches, buff, false);
02857                     }
02858                 }
02859             }
02860         }
02861     }
02862     {
02863         CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
02864         for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
02865         {
02866             if (cmdp->switches)
02867             {
02868                 if (check_access(player, cmdp->perms))
02869                 {
02870                     if (!(cmdp->perms & CF_DARK))
02871                     {
02872                         sprintf(buff, "%.60s:", cmdp->cmdname);
02873                         display_nametab(player, cmdp->switches, buff, false);
02874                     }
02875                 }
02876             }
02877         }
02878     }
02879     free_sbuf(buff);
02880 }
02881 
02882 // ---------------------------------------------------------------------------
02883 // list_attraccess: List access to attributes.
02884 //
02885 NAMETAB attraccess_nametab[] =
02886 {
02887     {"const",       1,  CA_PUBLIC,  AF_CONST},
02888     {"dark",        2,  CA_WIZARD,  AF_DARK},
02889     {"deleted",     2,  CA_WIZARD,  AF_DELETED},
02890     {"god",         1,  CA_PUBLIC,  AF_GOD},
02891     {"hidden",      1,  CA_WIZARD,  AF_MDARK},
02892     {"ignore",      2,  CA_WIZARD,  AF_NOCMD},
02893     {"internal",    2,  CA_WIZARD,  AF_INTERNAL},
02894     {"is_lock",     4,  CA_PUBLIC,  AF_IS_LOCK},
02895     {"locked",      1,  CA_PUBLIC,  AF_LOCK},
02896     {"no_command",  4,  CA_PUBLIC,  AF_NOPROG},
02897     {"no_inherit",  4,  CA_PUBLIC,  AF_PRIVATE},
02898     {"private",     1,  CA_PUBLIC,  AF_ODARK},
02899     {"regexp",      1,  CA_PUBLIC,  AF_REGEXP},
02900     {"visual",      1,  CA_PUBLIC,  AF_VISUAL},
02901     {"wizard",      1,  CA_PUBLIC,  AF_WIZARD},
02902     { NULL,         0,          0,          0}
02903 };
02904 
02905 NAMETAB indiv_attraccess_nametab[] =
02906 {
02907     {"case",                1,  CA_PUBLIC,  AF_CASE},
02908     {"hidden",              1,  CA_WIZARD,  AF_MDARK},
02909     {"html",                2,  CA_PUBLIC,  AF_HTML},
02910     {"no_parse",            4,  CA_PUBLIC,  AF_NOPARSE},
02911     {"no_command",          4,  CA_PUBLIC,  AF_NOPROG},
02912     {"no_inherit",          4,  CA_PUBLIC,  AF_PRIVATE},
02913     {"regexp",              1,  CA_PUBLIC,  AF_REGEXP},
02914     {"visual",              1,  CA_PUBLIC,  AF_VISUAL},
02915     {"wizard",              1,  CA_WIZARD,  AF_WIZARD},
02916     { NULL,                 0,          0,          0}
02917 };
02918 
02919 static void list_attraccess(dbref player)
02920 {
02921     ATTR *ap;
02922 
02923     char *buff = alloc_sbuf("list_attraccess");
02924     for (ap = attr; ap->name; ap++)
02925     {
02926         if (bCanReadAttr(player, player, ap, false))
02927         {
02928             sprintf(buff, "%s:", ap->name);
02929             listset_nametab(player, attraccess_nametab, ap->flags, buff, true);
02930         }
02931     }
02932     free_sbuf(buff);
02933 }
02934 
02935 // ---------------------------------------------------------------------------
02936 // cf_access: Change command or switch permissions.
02937 //
02938 CF_HAND(cf_access)
02939 {
02940     UNUSED_PARAMETER(vp);
02941 
02942     CMDENT *cmdp;
02943     char *ap;
02944     bool set_switch;
02945 
02946     for (ap = str; *ap && !mux_isspace(*ap) && (*ap != '/'); ap++) ;
02947     if (*ap == '/')
02948     {
02949         set_switch = true;
02950         *ap++ = '\0';
02951     }
02952     else
02953     {
02954         set_switch = false;
02955         if (*ap)
02956         {
02957             *ap++ = '\0';
02958         }
02959         while (mux_isspace(*ap))
02960         {
02961             ap++;
02962         }
02963     }
02964 
02965     cmdp = (CMDENT *)hashfindLEN(str, strlen(str), &mudstate.command_htab);
02966     if (cmdp != NULL)
02967     {
02968         if (set_switch)
02969         {
02970             return cf_ntab_access((int *)cmdp->switches, ap, pExtra, nExtra,
02971                                   player, cmd);
02972         }
02973         else
02974         {
02975             return cf_modify_bits(&(cmdp->perms), ap, pExtra, nExtra, player,
02976                                   cmd);
02977         }
02978     }
02979     else
02980     {
02981         if (!mux_stricmp(str, "home"))
02982         {
02983             return cf_modify_bits(&(mudconf.restrict_home), ap, pExtra,
02984                                   nExtra, player, cmd);
02985         }
02986         cf_log_notfound(player, cmd, "Command", str);
02987         return -1;
02988     }
02989 }
02990 
02991 // ---------------------------------------------------------------------------
02992 // cf_acmd_access: Change command permissions for all attr-setting cmds.
02993 //
02994 CF_HAND(cf_acmd_access)
02995 {
02996     UNUSED_PARAMETER(vp);
02997 
02998     ATTR *ap;
02999 
03000     for (ap = attr; ap->name; ap++)
03001     {
03002         int nBuffer;
03003         bool bValid;
03004         char *buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
03005         if (!bValid)
03006         {
03007             continue;
03008         }
03009 
03010         CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab);
03011         if (cmdp != NULL)
03012         {
03013             int save = cmdp->perms;
03014             int failure = cf_modify_bits(&(cmdp->perms), str, pExtra, nExtra,
03015                  player, cmd);
03016             if (failure != 0)
03017             {
03018                 cmdp->perms = save;
03019                 return -1;
03020             }
03021         }
03022     }
03023     return 0;
03024 }
03025 
03026 // ---------------------------------------------------------------------------
03027 // cf_attr_access: Change access on an attribute.
03028 //
03029 CF_HAND(cf_attr_access)
03030 {
03031     UNUSED_PARAMETER(vp);
03032 
03033     ATTR *ap;
03034     char *sp;
03035 
03036     for (sp = str; *sp && !mux_isspace(*sp); sp++)
03037     {
03038         ; // Nothing
03039     }
03040     if (*sp)
03041     {
03042         *sp++ = '\0';
03043     }
03044     while (mux_isspace(*sp))
03045     {
03046         sp++;
03047     }
03048 
03049     ap = atr_str(str);
03050     if (ap)
03051     {
03052         return cf_modify_bits(&(ap->flags), sp, pExtra, nExtra, player, cmd);
03053     }
03054     else
03055     {
03056         cf_log_notfound(player, cmd, "Attribute", str);
03057         return -1;
03058     }
03059 }
03060 
03061 // ---------------------------------------------------------------------------
03062 // cf_cmd_alias: Add a command alias.
03063 //
03064 CF_HAND(cf_cmd_alias)
03065 {
03066     UNUSED_PARAMETER(pExtra);
03067     UNUSED_PARAMETER(nExtra);
03068 
03069     char *ap;
03070     CMDENT *cmdp, *cmd2;
03071     NAMETAB *nt;
03072 
03073     MUX_STRTOK_STATE tts;
03074     mux_strtok_src(&tts, str);
03075     mux_strtok_ctl(&tts, " \t=,");
03076     char *alias = mux_strtok_parse(&tts);
03077     char *orig = mux_strtok_parse(&tts);
03078 
03079     if (!orig)
03080     {
03081         // We only got one argument to @alias. Bad.
03082         //
03083         return -1;
03084     }
03085 
03086     for (ap = orig; *ap && (*ap != '/'); ap++) ;
03087     if (*ap == '/')
03088     {
03089         // Switch form of command aliasing: create an alias for
03090         // a command + a switch
03091         //
03092         *ap++ = '\0';
03093 
03094         // Look up the command
03095         //
03096         cmdp = (CMDENT *) hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
03097         if (cmdp == NULL || cmdp->switches == NULL)
03098         {
03099             cf_log_notfound(player, cmd, "Command", orig);
03100             return -1;
03101         }
03102 
03103         // Look up the switch
03104         //
03105         nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap);
03106         if (!nt)
03107         {
03108             cf_log_notfound(player, cmd, "Switch", ap);
03109             return -1;
03110         }
03111 
03112         if (!hashfindLEN(alias, strlen(alias), (CHashTable *)vp))
03113         {
03114             // Create the new command table entry.
03115             //
03116             cmd2 = (CMDENT *)MEMALLOC(sizeof(CMDENT));
03117             ISOUTOFMEMORY(cmd2);
03118             cmd2->cmdname = StringClone(alias);
03119             cmd2->switches = cmdp->switches;
03120             cmd2->perms = cmdp->perms | nt->perm;
03121             cmd2->extra = (cmdp->extra | nt->flag) & ~SW_MULTIPLE;
03122             if (!(nt->flag & SW_MULTIPLE))
03123             {
03124                 cmd2->extra |= SW_GOT_UNIQUE;
03125             }
03126             cmd2->callseq = cmdp->callseq;
03127             cmd2->handler = cmdp->handler;
03128 
03129             hashaddLEN(cmd2->cmdname, strlen(cmd2->cmdname), cmd2, (CHashTable *) vp);
03130         }
03131     }
03132     else
03133     {
03134         // A normal (non-switch) alias
03135         //
03136         void *hp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
03137         if (hp == NULL)
03138         {
03139             cf_log_notfound(player, cmd, "Entry", orig);
03140             return -1;
03141         }
03142         hashaddLEN(alias, strlen(alias), hp, (CHashTable *) vp);
03143     }
03144     return 0;
03145 }
03146 
03147 // ---------------------------------------------------------------------------
03148 // list_df_flags: List default flags at create time.
03149 //
03150 static void list_df_flags(dbref player)
03151 {
03152     FLAGSET fs;
03153 
03154     fs = mudconf.player_flags;
03155     fs.word[FLAG_WORD1] |= TYPE_PLAYER;
03156     char *playerb = decode_flags(player, &fs);
03157 
03158     fs = mudconf.room_flags;
03159     fs.word[FLAG_WORD1] |= TYPE_ROOM;
03160     char *roomb = decode_flags(player, &fs);
03161 
03162     fs = mudconf.exit_flags;
03163     fs.word[FLAG_WORD1] |= TYPE_EXIT;
03164     char *exitb = decode_flags(player, &fs);
03165 
03166     fs = mudconf.thing_flags;
03167     fs.word[FLAG_WORD1] |= TYPE_THING;
03168     char *thingb = decode_flags(player, &fs);
03169 
03170     fs = mudconf.robot_flags;
03171     fs.word[FLAG_WORD1] |= TYPE_PLAYER;
03172     char *robotb = decode_flags(player, &fs);
03173 
03174     char *buff = alloc_lbuf("list_df_flags");
03175     sprintf(buff,
03176         "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s",
03177         playerb, roomb, exitb, thingb, robotb);
03178 
03179     free_sbuf(playerb);
03180     free_sbuf(roomb);
03181     free_sbuf(exitb);
03182     free_sbuf(thingb);
03183     free_sbuf(robotb);
03184 
03185     raw_notify(player, buff);
03186     free_lbuf(buff);
03187 }
03188 
03189 // ---------------------------------------------------------------------------
03190 // list_costs: List the costs of things.
03191 //
03192 #define coin_name(s)    (((s)==1) ? mudconf.one_coin : mudconf.many_coins)
03193 
03194 static void list_costs(dbref player)
03195 {
03196     char *buff = alloc_mbuf("list_costs");
03197     *buff = '\0';
03198     if (mudconf.quotas)
03199         sprintf(buff, " and %d quota", mudconf.room_quota);
03200     notify(player,
03201            tprintf("Digging a room costs %d %s%s.",
03202                mudconf.digcost, coin_name(mudconf.digcost), buff));
03203     if (mudconf.quotas)
03204         sprintf(buff, " and %d quota", mudconf.exit_quota);
03205     notify(player,
03206            tprintf("Opening a new exit costs %d %s%s.",
03207                mudconf.opencost, coin_name(mudconf.opencost), buff));
03208     notify(player,
03209            tprintf("Linking an exit, home, or dropto costs %d %s.",
03210                mudconf.linkcost, coin_name(mudconf.linkcost)));
03211     if (mudconf.quotas)
03212         sprintf(buff, " and %d quota", mudconf.thing_quota);
03213     if (mudconf.createmin == mudconf.createmax)
03214     {
03215         raw_notify(player,
03216                tprintf("Creating a new thing costs %d %s%s.",
03217                    mudconf.createmin,
03218                    coin_name(mudconf.createmin), buff));
03219     }
03220     else
03221     {
03222         raw_notify(player,
03223         tprintf("Creating a new thing costs between %d and %d %s%s.",
03224             mudconf.createmin, mudconf.createmax,
03225             mudconf.many_coins, buff));
03226     }
03227     if (mudconf.quotas)
03228         sprintf(buff, " and %d quota", mudconf.player_quota);
03229     notify(player,
03230            tprintf("Creating a robot costs %d %s%s.",
03231                mudconf.robotcost, coin_name(mudconf.robotcost), buff));
03232     if (mudconf.killmin == mudconf.killmax)
03233     {
03234         int chance = 100;
03235         if (0 < mudconf.killguarantee)
03236         {
03237             chance = (mudconf.killmin * 100) / mudconf.killguarantee;
03238         }
03239         raw_notify(player, tprintf("Killing costs %d %s, with a %d%% chance of success.",
03240             mudconf.killmin, coin_name(mudconf.digcost), chance));
03241     }
03242     else
03243     {
03244         int cost_surething;
03245         raw_notify(player, tprintf("Killing costs between %d and %d %s.",
03246             mudconf.killmin, mudconf.killmax, mudconf.many_coins));
03247         if (0 < mudconf.killguarantee)
03248         {
03249             cost_surething = mudconf.killguarantee;
03250         }
03251         else
03252         {
03253             cost_surething = mudconf.killmin;
03254         }
03255         raw_notify(player, tprintf("You must spend %d %s to guarantee success.",
03256             cost_surething, coin_name(cost_surething)));
03257     }
03258     raw_notify(player,
03259            tprintf("Computationally expensive commands and functions (ie: @entrances, @find, @search, @stats (with an argument or switch), search(), and stats()) cost %d %s.",
03260             mudconf.searchcost, coin_name(mudconf.searchcost)));
03261     if (mudconf.machinecost > 0)
03262         raw_notify(player,
03263            tprintf("Each command run from the queue costs 1/%d %s.",
03264                mudconf.machinecost, mudconf.one_coin));
03265     if (mudconf.waitcost > 0)
03266     {
03267         raw_notify(player,
03268                tprintf("A %d %s deposit is charged for putting a command on the queue.",
03269                    mudconf.waitcost, mudconf.one_coin));
03270         raw_notify(player, "The deposit is refunded when the command is run or canceled.");
03271     }
03272     if (mudconf.sacfactor == 0)
03273     {
03274         mux_ltoa(mudconf.sacadjust, buff);
03275     }
03276     else if (mudconf.sacfactor == 1)
03277     {
03278         if (mudconf.sacadjust < 0)
03279             sprintf(buff, "<create cost> - %d", -mudconf.sacadjust);
03280         else if (mudconf.sacadjust > 0)
03281             sprintf(buff, "<create cost> + %d", mudconf.sacadjust);
03282         else
03283             sprintf(buff, "<create cost>");
03284     }
03285     else
03286     {
03287         if (mudconf.sacadjust < 0)
03288             sprintf(buff, "(<create cost> / %d) - %d", mudconf.sacfactor, -mudconf.sacadjust);
03289         else if (mudconf.sacadjust > 0)
03290             sprintf(buff, "(<create cost> / %d) + %d", mudconf.sacfactor, mudconf.sacadjust);
03291         else
03292             sprintf(buff, "<create cost> / %d", mudconf.sacfactor);
03293     }
03294     raw_notify(player, tprintf("The value of an object is %s.", buff));
03295     if (mudconf.clone_copy_cost)
03296         raw_notify(player, "The default value of cloned objects is the value of the original object.");
03297     else
03298         raw_notify(player, tprintf("The default value of cloned objects is %d %s.",
03299                 mudconf.createmin, coin_name(mudconf.createmin)));
03300 
03301     free_mbuf(buff);
03302 }
03303 
03304 // ---------------------------------------------------------------------------
03305 // list_options: List more game options from mudconf.
03306 //
03307 static const char *switchd[] =
03308 {"/first", "/all"};
03309 static const char *examd[] =
03310 {"/brief", "/full"};
03311 static const char *ed[] =
03312 {"Disabled", "Enabled"};
03313 
03314 static void list_options(dbref player)
03315 {
03316     char *buff;
03317 
03318     CLinearTimeAbsolute ltaNow;
03319     ltaNow.GetUTC();
03320 
03321     if (mudconf.quotas)
03322         raw_notify(player, "Building quotas are enforced.");
03323     if (mudconf.name_spaces)
03324         raw_notify(player, "Player names may contain spaces.");
03325     else
03326         raw_notify(player, "Player names may not contain spaces.");
03327     if (!mudconf.robot_speak)
03328         raw_notify(player, "Robots are not allowed to speak in public areas.");
03329     if (mudconf.player_listen)
03330         raw_notify(player, "The @Listen/@Ahear attribute set works on player objects.");
03331     if (mudconf.ex_flags)
03332         raw_notify(player, "The 'examine' command lists the flag names for the object's flags.");
03333     if (!mudconf.quiet_look)
03334         raw_notify(player, "The 'look' command shows visible attributes in addition to the description.");
03335     if (mudconf.see_own_dark)
03336         raw_notify(player, "The 'look' command lists DARK objects owned by you.");
03337     if (!mudconf.dark_sleepers)
03338         raw_notify(player, "The 'look' command shows disconnected players.");
03339     if (mudconf.terse_look)
03340         raw_notify(player, "The 'look' command obeys the TERSE flag.");
03341     if (mudconf.trace_topdown)
03342     {
03343         raw_notify(player, "Trace output is presented top-down (whole expression first, then sub-exprs).");
03344         raw_notify(player, tprintf("Only %d lines of trace output are displayed.", mudconf.trace_limit));
03345     }
03346     else
03347     {
03348         raw_notify(player, "Trace output is presented bottom-up (subexpressions first).");
03349     }
03350     if (!mudconf.quiet_whisper)
03351         raw_notify(player, "The 'whisper' command lets others in the room with you know you whispered.");
03352     if (mudconf.pemit_players)
03353         raw_notify(player, "The '@pemit' command may be used to emit to faraway players.");
03354     if (!mudconf.terse_contents)
03355         raw_notify(player, "The TERSE flag suppresses listing the contents of a location.");
03356     if (!mudconf.terse_exits)
03357         raw_notify(player, "The TERSE flag suppresses listing obvious exits in a location.");
03358     if (!mudconf.terse_movemsg)
03359         raw_notify(player, "The TERSE flag suppresses enter/leave/succ/drop messages generated by moving.");
03360     if (mudconf.pub_flags)
03361         raw_notify(player, "The 'flags()' function will return the flags of any object.");
03362     if (mudconf.read_rem_desc)
03363         raw_notify(player, "The 'get()' function will return the description of faraway objects,");
03364     if (mudconf.read_rem_name)
03365         raw_notify(player, "The 'name()' function will return the name of faraway objects.");
03366     raw_notify(player, tprintf("The default switch for the '@switch' command is %s.", switchd[mudconf.switch_df_all]));
03367     raw_notify(player, tprintf("The default switch for the 'examine' command is %s.", examd[mudconf.exam_public]));
03368     if (mudconf.sweep_dark)
03369         raw_notify(player, "Players may @sweep dark locations.");
03370     if (mudconf.fascist_tport)
03371         raw_notify(player, "You may only @teleport out of locations that are JUMP_OK or that you control.");
03372     raw_notify(player,
03373            tprintf("Players may have at most %d commands in the queue at one time.",
03374                mudconf.queuemax));
03375     if (mudconf.match_mine)
03376     {
03377         if (mudconf.match_mine_pl)
03378             raw_notify(player, "All objects search themselves for $-commands.");
03379         else
03380             raw_notify(player, "Objects other than players search themselves for $-commands.");
03381     }
03382     if (!Wizard(player))
03383         return;
03384     buff = alloc_mbuf("list_options");
03385 
03386     raw_notify(player,
03387            tprintf("%d commands are run from the queue when there is no net activity.",
03388                mudconf.queue_chunk));
03389     raw_notify(player,
03390            tprintf("%d commands are run from the queue when there is net activity.",
03391                mudconf.active_q_chunk));
03392     if (mudconf.idle_wiz_dark)
03393         raw_notify(player, "Wizards idle for longer than the default timeout are automatically set DARK.");
03394     if (mudconf.safe_unowned)
03395         raw_notify(player, "Objects not owned by you are automatically considered SAFE.");
03396     if (mudconf.paranoid_alloc)
03397         raw_notify(player, "The buffer pools are checked for consistency on each allocate or free.");
03398     if (mudconf.cache_names)
03399         raw_notify(player, "A separate name cache is used.");
03400 #ifndef WIN32
03401     if (mudconf.fork_dump)
03402     {
03403         raw_notify(player, "Database dumps are performed by a fork()ed process.");
03404     }
03405 #endif
03406     if (mudconf.max_players >= 0)
03407         raw_notify(player,
03408         tprintf("There may be at most %d players logged in at once.",
03409             mudconf.max_players));
03410     if (mudconf.quotas)
03411         sprintf(buff, " and %d quota", mudconf.start_quota);
03412     else
03413         *buff = '\0';
03414     raw_notify(player,
03415            tprintf("New players are given %d %s to start with.",
03416                mudconf.paystart, mudconf.many_coins));
03417     raw_notify(player,
03418            tprintf("Players are given %d %s each day they connect.",
03419                mudconf.paycheck, mudconf.many_coins));
03420     raw_notify(player,
03421       tprintf("Earning money is difficult if you have more than %d %s.",
03422           mudconf.paylimit, mudconf.many_coins));
03423     if (mudconf.payfind > 0)
03424         raw_notify(player,
03425                tprintf("Players have a 1 in %d chance of finding a %s each time they move.",
03426                    mudconf.payfind, mudconf.one_coin));
03427     raw_notify(player,
03428            tprintf("The head of the object freelist is #%d.",
03429                mudstate.freelist));
03430 
03431     sprintf(buff, "Intervals: Dump...%d  Clean...%d  Idlecheck...%d",
03432         mudconf.dump_interval, mudconf.check_interval,
03433         mudconf.idle_interval);
03434     raw_notify(player, buff);
03435 
03436     CLinearTimeDelta ltdDump = mudstate.dump_counter - ltaNow;
03437     CLinearTimeDelta ltdCheck = mudstate.check_counter - ltaNow;
03438     CLinearTimeDelta ltdIdle = mudstate.idle_counter - ltaNow;
03439 
03440     long lDump  = ltdDump.ReturnSeconds();
03441     long lCheck = ltdCheck.ReturnSeconds();
03442     long lIdle  = ltdIdle.ReturnSeconds();
03443     sprintf(buff, "Timers: Dump...%ld  Clean...%ld  Idlecheck...%ld",
03444         lDump, lCheck, lIdle);
03445     raw_notify(player, buff);
03446 
03447     sprintf(buff, "Timeouts: Idle...%d  Connect...%d  Tries...%d",
03448         mudconf.idle_timeout, mudconf.conn_timeout,
03449         mudconf.retry_limit);
03450     raw_notify(player, buff);
03451 
03452     sprintf(buff, "Scheduling: Timeslice...%s  Max_Quota...%d  Increment...%d",
03453         mudconf.timeslice.ReturnSecondsString(3),mudconf.cmd_quota_max,
03454         mudconf.cmd_quota_incr);
03455     raw_notify(player, buff);
03456 
03457     sprintf(buff, "Spaces...%s  Savefiles...%s",
03458         ed[mudconf.space_compress], ed[mudconf.compress_db]);
03459     raw_notify(player, buff);
03460 
03461     sprintf(buff, "New characters: Room...#%d  Home...#%d  DefaultHome...#%d  Quota...%d",
03462         mudconf.start_room, mudconf.start_home, mudconf.default_home,
03463         mudconf.start_quota);
03464     raw_notify(player, buff);
03465 
03466     sprintf(buff, "Misc: GuestChar...#%d  IdleQueueChunk...%d  ActiveQueueChunk...%d  Master_room...#%d",
03467         mudconf.guest_char, mudconf.queue_chunk,
03468         mudconf.active_q_chunk, mudconf.master_room);
03469     raw_notify(player, buff);
03470 
03471     free_mbuf(buff);
03472 }
03473 
03474 // ---------------------------------------------------------------------------
03475 // list_vattrs: List user-defined attributes
03476 //
03477 static void list_vattrs(dbref player, char *s_mask)
03478 {
03479     bool wild_mtch =  s_mask
03480                    && s_mask[0] != '\0';
03481 
03482     char *buff = alloc_lbuf("list_vattrs");
03483 
03484     // If wild_match, then only list attributes that match wildcard(s)
03485     //
03486     char *p = tprintf("--- User-Defined Attributes %s---",
03487         wild_mtch ? "(wildmatched) " : "");
03488     raw_notify(player, p);
03489 
03490     ATTR *va;
03491     int na;
03492     int wna = 0;
03493 
03494     for (va = vattr_first(), na = 0; va; va = vattr_next(va), na++)
03495     {
03496         if (!(va->flags & AF_DELETED))
03497         {
03498             // We need to be extremely careful that s_mask is !null and valid
03499             //
03500             if (wild_mtch)
03501             {
03502                 mudstate.wild_invk_ctr = 0;
03503                 if (!quick_wild(s_mask, va->name))
03504                 {
03505                     continue;
03506                 }
03507                 wna++;
03508             }
03509             sprintf(buff, "%s(%d):", va->name, va->number);
03510             listset_nametab(player, attraccess_nametab, va->flags, buff, true);
03511         }
03512     }
03513 
03514     if (wild_mtch)
03515     {
03516         p = tprintf("%d attributes matched, %d attributes total, next=%d", wna,
03517             na, mudstate.attr_next);
03518     }
03519     else
03520     {
03521         p = tprintf("%d attributes, next=%d", na, mudstate.attr_next);
03522     }
03523     raw_notify(player, p);
03524     free_lbuf(buff);
03525 }
03526 
03527 static int LeftJustifyString(char *field, int nWidth, const char *value)
03528 {
03529     int n = strlen(value);
03530     if (n > nWidth)
03531     {
03532         n = nWidth;
03533     }
03534     memcpy(field, value, n);
03535     memset(field+n, ' ', nWidth-n);
03536     return nWidth;
03537 }
03538 
03539 static size_t RightJustifyNumber(char *field, size_t nWidth, INT64 value)
03540 {
03541     char   buffer[22];
03542     size_t nReturn = 0;
03543     if (nWidth < sizeof(buffer))
03544     {
03545         size_t n = mux_i64toa(value, buffer);
03546         if (n < sizeof(buffer))
03547         {
03548             nReturn = n;
03549             if (n < nWidth)
03550             {
03551                 memset(field, ' ', nWidth-n);
03552                 field += nWidth-n;
03553                 nReturn = nWidth;
03554             }
03555             memcpy(field, buffer, n);
03556         }
03557     }
03558     return nReturn;
03559 }
03560 
03561 // list_hashstats: List information from hash tables
03562 //
03563 static void list_hashstat(dbref player, const char *tab_name, CHashTable *htab)
03564 {
03565     unsigned int hashsize;
03566     int          entries, max_scan;
03567     INT64        deletes, scans, hits, checks;
03568 
03569     htab->GetStats(&hashsize, &entries, &deletes, &scans, &hits, &checks,
03570         &max_scan);
03571 
03572     char buff[MBUF_SIZE];
03573     char *p = buff;
03574 
03575     p += LeftJustifyString(p,  15, tab_name); *p++ = ' ';
03576     p += RightJustifyNumber(p,  4, hashsize); *p++ = ' ';
03577     p += RightJustifyNumber(p,  6, entries);  *p++ = ' ';
03578     p += RightJustifyNumber(p,  9, deletes);  *p++ = ' ';
03579     p += RightJustifyNumber(p, 11, scans);    *p++ = ' ';
03580     p += RightJustifyNumber(p, 11, hits);     *p++ = ' ';
03581     p += RightJustifyNumber(p, 11, checks);   *p++ = ' ';
03582     p += RightJustifyNumber(p,  4, max_scan); *p = '\0';
03583     raw_notify(player, buff);
03584 }
03585 
03586 static void list_hashstats(dbref player)
03587 {
03588     raw_notify(player, "Hash Stats      Size Entries Deleted      Lookups        Hits     Checks Longest");
03589     list_hashstat(player, "Commands", &mudstate.command_htab);
03590     list_hashstat(player, "Logged-out Cmds", &mudstate.logout_cmd_htab);
03591     list_hashstat(player, "Functions", &mudstate.func_htab);
03592     list_hashstat(player, "Flags", &mudstate.flags_htab);
03593     list_hashstat(player, "Powers", &mudstate.powers_htab);
03594     list_hashstat(player, "Attr names", &mudstate.attr_name_htab);
03595     list_hashstat(player, "Vattr names", &mudstate.vattr_name_htab);
03596     list_hashstat(player, "Player Names", &mudstate.player_htab);
03597     list_hashstat(player, "Net Descriptors", &mudstate.desc_htab);
03598     list_hashstat(player, "Forwardlists", &mudstate.fwdlist_htab);
03599     list_hashstat(player, "Overlaid $-cmds", &mudstate.parent_htab);
03600     list_hashstat(player, "Mail messages", &mudstate.mail_htab);
03601     list_hashstat(player, "Channel names", &mudstate.channel_htab);
03602     list_hashstat(player, "Attribute Cache", &mudstate.acache_htab);
03603     for (int i = 0; i < mudstate.nHelpDesc; i++)
03604     {
03605         list_hashstat(player, mudstate.aHelpDesc[i].pBaseFilename,
03606             mudstate.aHelpDesc[i].ht);
03607     }
03608 }
03609 
03610 
03611 // ---------------------------------------------------------------------------
03612 // list_db_stats: Get useful info from the DB layer about hash stats, etc.
03613 //
03614 static void list_db_stats(dbref player)
03615 {
03616 #ifdef MEMORY_BASED
03617     raw_notify(player, "Database is memory based.");
03618 #else // MEMORY_BASED
03619     CLinearTimeAbsolute lsaNow;
03620     lsaNow.GetUTC();
03621     CLinearTimeDelta ltd = lsaNow - cs_ltime;
03622     raw_notify(player, tprintf("DB Cache Stats   Writes       Reads  (over %d seconds)", ltd.ReturnSeconds()));
03623     raw_notify(player, tprintf("Calls      %12d%12d", cs_writes, cs_reads));
03624     raw_notify(player, tprintf("\nDeletes    %12d", cs_dels));
03625     raw_notify(player, tprintf("Syncs      %12d", cs_syncs));
03626     raw_notify(player, tprintf("I/O        %12d%12d", cs_dbwrites, cs_dbreads));
03627     raw_notify(player, tprintf("Cache Hits %12d%12d", cs_whits, cs_rhits));
03628 #endif // MEMORY_BASED
03629 }
03630 
03631 // ---------------------------------------------------------------------------
03632 // list_process: List local resource usage stats of the mux process.
03633 // Adapted from code by Claudius@PythonMUCK,
03634 //     posted to the net by Howard/Dark_Lord.
03635 //
03636 static void list_process(dbref player)
03637 {
03638 #ifdef HAVE_GETRUSAGE
03639     struct rusage usage;
03640     int ixrss, idrss, isrss, curr, last, dur;
03641 
03642     getrusage(RUSAGE_SELF, &usage);
03643 
03644     // Calculate memory use from the aggregate totals.
03645     //
03646     curr = mudstate.mstat_curr;
03647     last = 1 - curr;
03648     dur = mudstate.mstat_secs[curr] - mudstate.mstat_secs[last];
03649     if (dur > 0)
03650     {
03651         ixrss = (mudstate.mstat_ixrss[curr] -
03652              mudstate.mstat_ixrss[last]) / dur;
03653         idrss = (mudstate.mstat_idrss[curr] -
03654              mudstate.mstat_idrss[last]) / dur;
03655         isrss = (mudstate.mstat_isrss[curr] -
03656              mudstate.mstat_isrss[last]) / dur;
03657     }
03658     else
03659     {
03660         ixrss = 0;
03661         idrss = 0;
03662         isrss = 0;
03663     }
03664 #endif // HAVE_GETRUSAGE
03665 
03666 #ifdef WIN32
03667 #ifdef HAVE_GETRUSAGE
03668     int maxfds = FD_SETSIZE;
03669 #endif // HAVE_GETRUSAGE
03670 #else // WIN32
03671 #ifdef HAVE_GETDTABLESIZE
03672     int maxfds = getdtablesize();
03673 #else // HAVE_GETDTABLESIZE
03674     int maxfds = sysconf(_SC_OPEN_MAX);
03675 #endif // HAVE_GETDTABLESIZE
03676     int psize = getpagesize();
03677 #endif // WIN32
03678 
03679     // Go display everything
03680     //
03681 #ifdef WIN32
03682     raw_notify(player, tprintf("Process ID:  %10d", game_pid));
03683 #else // WIN32
03684     raw_notify(player, tprintf("Process ID:  %10d        %10d bytes per page", game_pid, psize));
03685 #endif // WIN32
03686 
03687 #ifdef HAVE_GETRUSAGE
03688     raw_notify(player, tprintf("Time used:   %10d user   %10d sys",
03689                usage.ru_utime.tv_sec, usage.ru_stime.tv_sec));
03690     raw_notify(player, tprintf("Resident mem:%10d shared %10d private%10d stack",
03691            ixrss, idrss, isrss));
03692     raw_notify(player,
03693            tprintf("Integral mem:%10d shared %10d private%10d stack",
03694                usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss));
03695     raw_notify(player,
03696            tprintf("Max res mem: %10d pages  %10d bytes",
03697                usage.ru_maxrss, (usage.ru_maxrss * psize)));
03698     raw_notify(player,
03699            tprintf("Page faults: %10d hard   %10d soft   %10d swapouts",
03700                usage.ru_majflt, usage.ru_minflt, usage.ru_nswap));
03701     raw_notify(player,
03702            tprintf("Disk I/O:    %10d reads  %10d writes",
03703                usage.ru_inblock, usage.ru_oublock));
03704     raw_notify(player,
03705            tprintf("Network I/O: %10d in     %10d out",
03706                usage.ru_msgrcv, usage.ru_msgsnd));
03707     raw_notify(player,
03708            tprintf("Context swi: %10d vol    %10d forced %10d sigs",
03709                usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals));
03710     raw_notify(player,
03711            tprintf("Descs avail: %10d", maxfds));
03712 #endif // HAVE_GETRUSAGE
03713 }
03714 
03715 //----------------------------------------------------------------------------
03716 // list_rlevels
03717 //
03718 
03719 
03720 #ifdef REALITY_LVLS
03721 static void list_rlevels(dbref player)
03722 {
03723     int i;
03724     raw_notify(player, "Reality levels:");
03725     for(i = 0; i < mudconf.no_levels; ++i)
03726         raw_notify(player, tprintf("    Level: %-20.20s    Value: 0x%08x     Desc: %s",
03727             mudconf.reality_level[i].name, mudconf.reality_level[i].value,
03728                 mudconf.reality_level[i].attr));
03729     raw_notify(player, "--Completed.");
03730 }
03731 #endif /* REALITY_LVLS */
03732 
03733 // ---------------------------------------------------------------------------
03734 // do_list: List information stored in internal structures.
03735 //
03736 #define LIST_ATTRIBUTES 1
03737 #define LIST_COMMANDS   2
03738 #define LIST_COSTS      3
03739 #define LIST_FLAGS      4
03740 #define LIST_FUNCTIONS  5
03741 #define LIST_GLOBALS    6
03742 #define LIST_ALLOCATOR  7
03743 #define LIST_LOGGING    8
03744 #define LIST_DF_FLAGS   9
03745 #define LIST_PERMS      10
03746 #define LIST_ATTRPERMS  11
03747 #define LIST_OPTIONS    12
03748 #define LIST_HASHSTATS  13
03749 #define LIST_BUFTRACE   14
03750 #define LIST_CONF_PERMS 15
03751 #define LIST_SITEINFO   16
03752 #define LIST_POWERS     17
03753 #define LIST_SWITCHES   18
03754 #define LIST_VATTRS     19
03755 #define LIST_DB_STATS   20
03756 #define LIST_PROCESS    21
03757 #define LIST_BADNAMES   22
03758 #define LIST_RESOURCES  23
03759 #define LIST_GUESTS     24
03760 #ifdef REALITY_LVLS
03761 #define LIST_RLEVELS    25
03762 #endif
03763 
03764 NAMETAB list_names[] =
03765 {
03766     {"allocations",        2,  CA_WIZARD,  LIST_ALLOCATOR},
03767     {"attr_permissions",   5,  CA_WIZARD,  LIST_ATTRPERMS},
03768     {"attributes",         2,  CA_PUBLIC,  LIST_ATTRIBUTES},
03769     {"bad_names",          2,  CA_WIZARD,  LIST_BADNAMES},
03770     {"buffers",            2,  CA_WIZARD,  LIST_BUFTRACE},
03771     {"commands",           3,  CA_PUBLIC,  LIST_COMMANDS},
03772     {"config_permissions", 3,  CA_GOD,     LIST_CONF_PERMS},
03773     {"costs",              3,  CA_PUBLIC,  LIST_COSTS},
03774     {"db_stats",           2,  CA_WIZARD,  LIST_DB_STATS},
03775     {"default_flags",      1,  CA_PUBLIC,  LIST_DF_FLAGS},
03776     {"flags",              2,  CA_PUBLIC,  LIST_FLAGS},
03777     {"functions",          2,  CA_PUBLIC,  LIST_FUNCTIONS},
03778     {"globals",            2,  CA_WIZARD,  LIST_GLOBALS},
03779     {"hashstats",          1,  CA_WIZARD,  LIST_HASHSTATS},
03780     {"logging",            1,  CA_GOD,     LIST_LOGGING},
03781     {"options",            1,  CA_PUBLIC,  LIST_OPTIONS},
03782     {"permissions",        2,  CA_WIZARD,  LIST_PERMS},
03783     {"powers",             2,  CA_WIZARD,  LIST_POWERS},
03784     {"process",            2,  CA_WIZARD,  LIST_PROCESS},
03785     {"resources",          1,  CA_WIZARD,  LIST_RESOURCES},
03786     {"site_information",   2,  CA_WIZARD,  LIST_SITEINFO},
03787     {"switches",           2,  CA_PUBLIC,  LIST_SWITCHES},
03788     {"user_attributes",    1,  CA_WIZARD,  LIST_VATTRS},
03789     {"guests",             2,  CA_WIZARD,  LIST_GUESTS},
03790 #ifdef REALITY_LVLS
03791     {"rlevels",            3,  CA_PUBLIC,  LIST_RLEVELS},
03792 #endif
03793     { NULL,                0,  0,          0}
03794 };
03795 
03796 void do_list(dbref executor, dbref caller, dbref enactor, int extra,
03797              char *arg)
03798 {
03799     UNUSED_PARAMETER(caller);
03800     UNUSED_PARAMETER(enactor);
03801     UNUSED_PARAMETER(extra);
03802 
03803     MUX_STRTOK_STATE tts;
03804     mux_strtok_src(&tts, arg);
03805     mux_strtok_ctl(&tts, " \t=,");
03806     char *s_option = mux_strtok_parse(&tts);
03807 
03808     int flagvalue;
03809     if (!search_nametab(executor, list_names, arg, &flagvalue))
03810     {
03811         if (flagvalue == -1)
03812         {
03813             display_nametab(executor, list_names, "Unknown option.  Use one of:", true);
03814         }
03815         else
03816         {
03817             notify(executor, "Permission denied");
03818         }
03819         return;
03820     }
03821 
03822     switch (flagvalue)
03823     {
03824     case LIST_ALLOCATOR:
03825         list_bufstats(executor);
03826         break;
03827     case LIST_BUFTRACE:
03828         list_buftrace(executor);
03829         break;
03830     case LIST_ATTRIBUTES:
03831         list_attrtable(executor);
03832         break;
03833     case LIST_COMMANDS:
03834         list_cmdtable(executor);
03835         break;
03836     case LIST_SWITCHES:
03837         list_cmdswitches(executor);
03838         break;
03839     case LIST_COSTS:
03840         list_costs(executor);
03841         break;
03842     case LIST_OPTIONS:
03843         list_options(executor);
03844         break;
03845     case LIST_HASHSTATS:
03846         list_hashstats(executor);
03847         break;
03848     case LIST_SITEINFO:
03849         list_siteinfo(executor);
03850         break;
03851     case LIST_FLAGS:
03852         display_flagtab(executor);
03853         break;
03854     case LIST_FUNCTIONS:
03855         list_functable(executor);
03856         break;
03857     case LIST_GLOBALS:
03858         interp_nametab(executor, enable_names, mudconf.control_flags,
03859                 "Global parameters:", "enabled", "disabled");
03860         break;
03861     case LIST_DF_FLAGS:
03862         list_df_flags(executor);
03863         break;
03864     case LIST_PERMS:
03865         list_cmdaccess(executor);
03866         break;
03867     case LIST_CONF_PERMS:
03868         list_cf_access(executor);
03869         break;
03870     case LIST_POWERS:
03871         display_powertab(executor);
03872         break;
03873     case LIST_ATTRPERMS:
03874         list_attraccess(executor);
03875         break;
03876     case LIST_VATTRS:
03877         s_option = mux_strtok_parse(&tts);
03878         list_vattrs(executor, s_option);
03879         break;
03880     case LIST_LOGGING:
03881         interp_nametab(executor, logoptions_nametab, mudconf.log_options,
03882                    "Events Logged:", "enabled", "disabled");
03883         interp_nametab(executor, logdata_nametab, mudconf.log_info,
03884                    "Information Logged:", "yes", "no");
03885         break;
03886     case LIST_DB_STATS:
03887         list_db_stats(executor);
03888         break;
03889     case LIST_PROCESS:
03890         list_process(executor);
03891         break;
03892     case LIST_BADNAMES:
03893         badname_list(executor, "Disallowed names:");
03894         break;
03895     case LIST_RESOURCES:
03896         list_system_resources(executor);
03897         break;
03898     case LIST_GUESTS:
03899         Guest.ListAll(executor);
03900         break;
03901 #ifdef REALITY_LVLS
03902     case LIST_RLEVELS:
03903         list_rlevels(executor);
03904         break;
03905 #endif
03906     }
03907 }
03908 
03909 void do_break(dbref executor, dbref caller, dbref enactor, int key, char *arg1)
03910 {
03911     UNUSED_PARAMETER(executor);
03912     UNUSED_PARAMETER(caller);
03913     UNUSED_PARAMETER(enactor);
03914     UNUSED_PARAMETER(key);
03915 
03916     break_called = xlate(arg1);
03917 }
03918 
03919 // do_icmd: Ignore or disable commands on a per-player or per-room basis.
03920 // Used with express permission of RhostMUSH developers.
03921 // Bludgeoned into MUX by Jake Nelson 7/2002.
03922 //
03923 void do_icmd(dbref player, dbref cause, dbref enactor, int key, char *name,
03924              char *args[], int nargs)
03925 {
03926     UNUSED_PARAMETER(cause);
03927     UNUSED_PARAMETER(enactor);
03928 
03929     CMDENT *cmdp;
03930     char *buff1, *pt1, *pt2, *pt3, *atrpt, *pt5;
03931     int x, aflags, y;
03932     dbref target = NOTHING, aowner, zone;
03933     bool bFound, set;
03934 
03935     int loc_set = -1;
03936     if (  key == ICMD_IROOM
03937        || key == ICMD_DROOM
03938        || key == ICMD_CROOM
03939        || key == ICMD_LROOM
03940        || key == ICMD_LALLROOM)
03941     {
03942         if (key != ICMD_LALLROOM)
03943         {
03944             target = match_thing_quiet(player, name);
03945         }
03946         if (  key != ICMD_LALLROOM
03947            && (  !Good_obj(target)
03948               || !( isRoom(target)
03949                  || isThing(target))))
03950         {
03951             notify(player, "@icmd: Bad Location.");
03952             return;
03953         }
03954         if (key == ICMD_CROOM)
03955         {
03956             atr_clr(target, A_CMDCHECK);
03957             notify(player, "@icmd: Location - All cleared.");
03958             notify(player, "@icmd: Done.");
03959             return;
03960         }
03961         else if (key == ICMD_LROOM)
03962         {
03963             atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags);
03964             if (*atrpt)
03965             {
03966                 notify(player,"Location CmdCheck attribute is:");
03967                 notify(player, atrpt);
03968             }
03969             else
03970             {
03971                 notify(player, "Location CmdCheck attribute is empty.");
03972             }
03973             free_lbuf(atrpt);
03974             notify(player, "@icmd: Done.");
03975             return;
03976         }
03977         else if (key == ICMD_LALLROOM)
03978         {
03979             target = Location(player);
03980             if (  !Good_obj(target)
03981                || Going(target)
03982                || isPlayer(target))
03983             {
03984                 notify(player, "@icmd: Bad Location.");
03985                 return;
03986             }
03987             notify(player, "Scanning all locations and zones from your current location:");
03988             bFound = false;
03989             atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags);
03990             if (*atrpt)
03991             {
03992                 notify(player, tprintf("%c     --- At %s(#%d) :",
03993                     (Zone(target) == target ? '*' : ' '), Name(target), target));
03994                 notify(player, atrpt);
03995                 bFound = true;
03996             }
03997             free_lbuf(atrpt);
03998             if (Zone(target) != target)
03999             {
04000                 zone = Zone(target);
04001                 if (  Good_obj(zone)
04002                    && (  isRoom(zone)
04003                       || isThing(zone)))
04004                 {
04005                     atrpt = atr_get(zone, A_CMDCHECK, &aowner, &aflags);
04006                     if (*atrpt)
04007                     {
04008                         notify(player,tprintf("%c     z-- At %s(#%d) :",
04009                             '*', Name(zone), zone));
04010                         notify(player, atrpt);
04011                         bFound = true;
04012                     }
04013                     free_lbuf(atrpt);
04014                 }
04015             }
04016             if (!bFound)
04017             {
04018                 notify(player, "@icmd: Location - No icmd's found at current location.");
04019             }
04020             notify(player, "@icmd: Done.");
04021             return;
04022         }
04023         else if (key == ICMD_IROOM)
04024         {
04025             loc_set = 1;
04026         }
04027         else if (key == ICMD_DROOM)
04028         {
04029             loc_set = 0;
04030         }
04031     }
04032 
04033     if (loc_set == -1 )
04034     {
04035         target = lookup_player(player, name, false);
04036         if (!Good_obj(target) || God(target))
04037         {
04038             notify(player, "@icmd: Bad player.");
04039             return;
04040         }
04041         if ((key == ICMD_OFF) || (key == ICMD_CLEAR))
04042         {
04043             s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK);
04044             if (key == ICMD_CLEAR)
04045             {
04046                 atr_clr(target, A_CMDCHECK);
04047             }
04048             notify(player, "@icmd: All cleared.");
04049             notify(player, "@icmd: Done.");
04050             return;
04051         }
04052         else if (key == ICMD_ON)
04053         {
04054             s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK);
04055             notify(player, "@icmd: Activated.");
04056             notify(player, "@icmd: Done.");
04057             return;
04058         }
04059         else if (key == ICMD_CHECK)
04060         {
04061             if (CmdCheck(target))
04062             {
04063                 notify(player, "CmdCheck is active.");
04064             }
04065             else
04066             {
04067                 notify(player, "CmdCheck is not active.");
04068             }
04069             atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags);
04070             if (*atrpt)
04071             {
04072                 notify(player, "CmdCheck attribute is:");
04073                 notify(player, atrpt);
04074             }
04075             else
04076             {
04077                 notify(player, "CmdCheck attribute is empty.");
04078             }
04079             free_lbuf(atrpt);
04080             notify(player, "@icmd: Done.");
04081             return;
04082         }
04083     }
04084     else
04085     {
04086         key = loc_set;
04087     }
04088     char *message = "";
04089     buff1 = alloc_lbuf("do_icmd");
04090     for (x = 0; x < nargs; x++)
04091     {
04092         pt1 = args[x];
04093         pt2 = buff1;
04094         while (  *pt1
04095               && pt2 < buff1 + LBUF_SIZE)
04096         {
04097             *pt2++ = mux_tolower(*pt1++);
04098         }
04099         *pt2 = '\0';
04100         if (  buff1[0] == '!'
04101            && buff1[1] != '\0')
04102         {
04103             pt1 = buff1 + 1;
04104             set = false;
04105         }
04106         else
04107         {
04108             pt1 = buff1;
04109             set = true;
04110         }
04111         if (*pt1)
04112         {
04113             bool bHome, bColon = false;
04114             if (!string_compare(pt1, "home"))
04115             {
04116                 bHome = true;
04117                 cmdp = NULL;
04118             }
04119             else
04120             {
04121                 bHome = false;
04122                 cmdp = (CMDENT *) hashfindLEN(pt1, strlen(pt1), &mudstate.command_htab);
04123             }
04124             if (cmdp || bHome)
04125             {
04126                 atrpt = atr_get(target, A_CMDCHECK, &aowner, &aflags);
04127                 if (cmdp)
04128                 {
04129                     aflags = strlen(cmdp->cmdname);
04130                     bColon = (  aflags == 1
04131                              && *(cmdp->cmdname) == ':');
04132                 }
04133                 else
04134                 {
04135                     aflags = 4;
04136                 }
04137                 pt5 = atrpt;
04138                 while (pt1)
04139                 {
04140                     if (cmdp)
04141                     {
04142                         if (bColon)
04143                         {
04144                             pt1 = strstr(pt5, "::");
04145                             if (pt1)
04146                             {
04147                                 pt1++;
04148                             }
04149                         }
04150                         else
04151                         {
04152                             pt1 = strstr(pt5, cmdp->cmdname);
04153                         }
04154                     }
04155                     else
04156                     {
04157                         pt1 = strstr(pt5, "home");
04158                     }
04159                     if (  pt1
04160                        && (pt1 > atrpt)
04161                        && (*(pt1 - 1) == ':')
04162                        && (  mux_isspace(*(pt1 + aflags))
04163                           || !*(pt1 + aflags)))
04164                     {
04165                         break;
04166                     }
04167                     else if (pt1)
04168                     {
04169                         if (*pt1)
04170                         {
04171                             pt5 = pt1 + 1;
04172                         }
04173                         else
04174                         {
04175                             pt1 = NULL;
04176                             break;
04177                         }
04178                     }
04179                 }
04180                 if (set)
04181                 {
04182                     if (!pt1)
04183                     {
04184                         if (*atrpt && (strlen(atrpt) < LBUF_SIZE - 2))
04185                         {
04186                             strcat(atrpt, " ");
04187                         }
04188 
04189                         if (cmdp)
04190                         {
04191                             pt3 = tprintf("%d:%s", key + 1, cmdp->cmdname);
04192                         }
04193                         else
04194                         {
04195                             pt3 = tprintf("%d:home", key + 1);
04196                         }
04197 
04198                         size_t natrpt = strlen(atrpt);
04199                         size_t npt3 = strlen(pt3);
04200                         if ((natrpt + npt3) < LBUF_SIZE - 1)
04201                         {
04202                             strcat(atrpt, pt3);
04203                             atr_add_raw(target, A_CMDCHECK, atrpt);
04204                             if ( loc_set == -1 )
04205                             {
04206                                 s_Flags(target, FLAG_WORD3, Flags3(target) | CMDCHECK);
04207                             }
04208                             message = "Set";
04209                         }
04210                     }
04211                     else
04212                     {
04213                         message = "Command already present";
04214                     }
04215                 }
04216                 else
04217                 {
04218                     if (pt1)
04219                     {
04220                         pt2 = pt1 - 1;
04221                         while ((pt2 > atrpt) && !mux_isspace(*pt2))
04222                         {
04223                             pt2--;
04224                         }
04225                         y = pt2 - atrpt + 1;
04226                         strncpy(buff1, atrpt, y);
04227                         if (y == 1)
04228                         {
04229                             *atrpt = '\0';
04230                         }
04231                         *(atrpt + y) = '\0';
04232                         pt2 = pt1 + aflags;
04233                         if (*pt2)
04234                         {
04235                             while (*pt2 && mux_isspace(*pt2))
04236                             {
04237                                 pt2++;
04238                             }
04239                             if (*pt2)
04240                             {
04241                                 strcat(atrpt,pt2);
04242                             }
04243                         }
04244                         if ((y > 1) && !*pt2)
04245                         {
04246                             pt2 = atrpt + y;
04247                             while ((pt2 > atrpt) && mux_isspace(*pt2))
04248                             {
04249                                 pt2--;
04250                             }
04251                             *(pt2 + 1) = '\0';
04252                         }
04253                         if ((y == 1) && !*pt2)
04254                         {
04255                             atr_clr(target, A_CMDCHECK);
04256                             if (loc_set == -1)
04257                             {
04258                                 s_Flags(target, FLAG_WORD3, Flags3(target) & ~CMDCHECK);
04259                             }
04260                             message = "Cleared";
04261                         }
04262                         else
04263                         {
04264                             atr_add_raw(target, A_CMDCHECK, atrpt);
04265                             message = "Cleared";
04266                         }
04267                     }
04268                     else
04269                     {
04270                         message = "Command not present";
04271                     }
04272                 }
04273                 free_lbuf(atrpt);
04274             }
04275             else
04276             {
04277                 message = "Bad command";
04278             }
04279             notify(player, tprintf("@icmd:%s %s.",(loc_set == -1) ? "" : " Location -", message));
04280         }
04281     }
04282     free_lbuf(buff1);
04283     notify(player,"@icmd: Done.");
04284 }
04285 
04286 // do_train: show someone else in the same room what code you're entering and the result
04287 // From RhostMUSH, changed to use notify_all_from_inside.
04288 //
04289 void do_train(dbref executor, dbref caller, dbref enactor, int key, char *string)
04290 {
04291     UNUSED_PARAMETER(key);
04292 
04293     if (0 < mudstate.train_nest_lev)
04294     {
04295         notify(executor, "Train cannot be used to teach command, train.");
04296         return;
04297     }
04298     mudstate.train_nest_lev++;
04299     dbref loc = Location(executor);
04300     if (!Good_obj(loc))
04301     {
04302         notify(executor, "Bad location.");
04303         mudstate.train_nest_lev--;
04304         return;
04305     }
04306     if (  !string
04307        || !*string)
04308     {
04309         notify(executor, "Train requires an argument.");
04310         mudstate.train_nest_lev--;
04311         return;
04312     }
04313 
04314     notify_all_from_inside(loc, executor, tprintf("%s types -=> %s",
04315         Moniker(executor), string));
04316     process_command(executor, caller, enactor, true, string, (char **)NULL, 0);
04317     mudstate.train_nest_lev--;
04318 }
04319 
04320 void do_moniker(dbref executor, dbref caller, dbref enactor, int key,
04321                  int nfargs, char *name, char *instr)
04322 {
04323     UNUSED_PARAMETER(caller);
04324     UNUSED_PARAMETER(enactor);
04325     UNUSED_PARAMETER(key);
04326     UNUSED_PARAMETER(nfargs);
04327 
04328     dbref thing = match_thing(executor, name);
04329     if ( !(  Good_obj(thing)
04330           && Controls(executor, thing)))
04331     {
04332         notify(executor, "Permission denied.");
04333         return;
04334     }
04335 
04336     if (  instr == NULL
04337        || instr[0] == '\0')
04338     {
04339         notify_quiet(executor, "Moniker cleared.");
04340         s_Moniker(thing, NULL);
04341     }
04342     else
04343     {
04344         s_Moniker(thing, instr);
04345         if (  !Quiet(executor)
04346            && !Quiet(thing))
04347         {
04348             notify_quiet(executor, "Moniker set.");
04349         }
04350     }
04351     set_modified(thing);
04352 }
04353 
04354 // do_hook: run softcode before or after running a hardcode command, or
04355 // softcode access. Original idea from TinyMUSH 3, code from RhostMUSH.
04356 // Used with express permission of RhostMUSH developers.
04357 // Bludgeoned into MUX by Jake Nelson 7/2002.
04358 //
04359 static void show_hook(char *bf, char *bfptr, int key)
04360 {
04361     if (key & HOOK_BEFORE)
04362         safe_str("before ", bf, &bfptr);
04363     if (key & HOOK_AFTER)
04364         safe_str("after ", bf, &bfptr);
04365     if (key & HOOK_PERMIT)
04366         safe_str("permit ", bf, &bfptr);
04367     if (key & HOOK_IGNORE)
04368         safe_str("ignore ", bf, &bfptr);
04369     if (key & HOOK_IGSWITCH)
04370         safe_str("igswitch ", bf, &bfptr);
04371     if (key & HOOK_AFAIL)
04372         safe_str("afail ", bf, &bfptr);
04373     *bfptr = '\0';
04374 }
04375 
04376 static void hook_loop(dbref executor, CMDENT *cmdp, char *s_ptr, char *s_ptrbuff)
04377 {
04378     show_hook(s_ptrbuff, s_ptr, cmdp->hookmask);
04379     const char *pFmt = "%-32.32s | %s";
04380     const char *pCmd = cmdp->cmdname;
04381     if (  pCmd[0] != '\0'
04382        && pCmd[1] == '\0')
04383     {
04384         switch (pCmd[0])
04385         {
04386         case '"':
04387             pFmt = "S %-30.30s | %s";
04388             pCmd = "('\"' hook on 'say')";
04389             break;
04390         case ':':
04391             pFmt = "P %-30.30s | %s";
04392             pCmd = "(':' hook on 'pose')";
04393             break;
04394         case ';':
04395             pFmt = "P %-30.30s | %s";
04396             pCmd = "(';' hook on 'pose')";
04397             break;
04398         case '\\':
04399             pFmt = "E %-30.30s | %s";
04400             pCmd = "('\\\\' hook on '@emit')";
04401             break;
04402         case '#':
04403             pFmt = "F %-30.30s | %s";
04404             pCmd = "('#' hook on '@force')";
04405             break;
04406         case '&':
04407             pFmt = "V %-30.30s | %s";
04408             pCmd = "('&' hook on '@set')";
04409             break;
04410         case '-':
04411             pFmt = "M %-30.30s | %s";
04412             pCmd = "('-' hook on '@mail')";
04413             break;
04414         case '~':
04415             pFmt = "M %-30.30s | %s";
04416             pCmd = "('~' hook on '@mail')";
04417             break;
04418         }
04419     }
04420     notify(executor, tprintf(pFmt, pCmd, s_ptrbuff));
04421 }
04422 
04423 void do_hook(dbref executor, dbref caller, dbref enactor, int key, char *name)
04424 {
04425     UNUSED_PARAMETER(caller);
04426     UNUSED_PARAMETER(enactor);
04427 
04428     bool negate, found;
04429     char *s_ptr, *s_ptrbuff, *cbuff, *p, *q;
04430     CMDENT *cmdp = (CMDENT *)NULL;
04431 
04432     if (  (  key
04433           && !(key & HOOK_LIST))
04434        || (  (  !key
04435              || (key & HOOK_LIST))
04436           && *name))
04437     {
04438         cmdp = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab);
04439         if (!cmdp)
04440         {
04441             notify(executor, "@hook: Non-existent command name given.");
04442             return;
04443         }
04444     }
04445     if (  (key & HOOK_CLEAR)
04446        && (key & HOOK_LIST))
04447     {
04448         notify(executor, "@hook: Incompatible switches.");
04449         return;
04450     }
04451 
04452     if (key & HOOK_CLEAR)
04453     {
04454         negate = true;
04455         key = key & ~HOOK_CLEAR;
04456         key = key & ~SW_MULTIPLE;
04457     }
04458     else
04459     {
04460         negate = false;
04461     }
04462 
04463     if (key & (HOOK_BEFORE|HOOK_AFTER|HOOK_PERMIT|HOOK_IGNORE|HOOK_IGSWITCH|HOOK_AFAIL))
04464     {
04465         if (negate)
04466         {
04467             cmdp->hookmask = cmdp->hookmask & ~key;
04468         }
04469         else
04470         {
04471             cmdp->hookmask = cmdp->hookmask | key;
04472         }
04473         if (cmdp->hookmask)
04474         {
04475             s_ptr = s_ptrbuff = alloc_lbuf("@hook");
04476             show_hook(s_ptrbuff, s_ptr, cmdp->hookmask);
04477             notify(executor, tprintf("@hook: New mask for '%s' -> %s", cmdp->cmdname, s_ptrbuff));
04478             free_lbuf(s_ptrbuff);
04479         }
04480         else
04481         {
04482             notify(executor, tprintf("@hook: New mask for '%s' is empty.", cmdp->cmdname));
04483         }
04484     }
04485     if (  (key & HOOK_LIST)
04486        || !key)
04487     {
04488         if (cmdp)
04489         {
04490             if (cmdp->hookmask)
04491             {
04492                 s_ptr = s_ptrbuff = alloc_lbuf("@hook");
04493                 show_hook(s_ptrbuff, s_ptr, cmdp->hookmask);
04494                 notify(executor, tprintf("@hook: Mask for hashed command '%s' -> %s", cmdp->cmdname, s_ptrbuff));
04495                 free_lbuf(s_ptrbuff);
04496             }
04497             else
04498             {
04499                 notify(executor, tprintf("@hook: Mask for hashed command '%s' is empty.", cmdp->cmdname));
04500             }
04501         }
04502         else
04503         {
04504             notify(executor, tprintf("%.32s-+-%s",
04505                 "--------------------------------",
04506                 "--------------------------------------------"));
04507             notify(executor, tprintf("%-32s | %s", "Built-in Command", "Hook Mask Values"));
04508             notify(executor, tprintf("%.32s-+-%s",
04509                 "--------------------------------",
04510                 "--------------------------------------------"));
04511             found = false;
04512             s_ptr = s_ptrbuff = alloc_lbuf("@hook");
04513             {
04514                 CMDENT_NO_ARG *cmdp2;
04515                 for (cmdp2 = command_table_no_arg; cmdp2->cmdname; cmdp2++)
04516                 {
04517                     s_ptrbuff[0] = '\0';
04518                     s_ptr = s_ptrbuff;
04519                     if (cmdp2->hookmask)
04520                     {
04521                         found = true;
04522                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04523                     }
04524                 }
04525             }
04526             {
04527                 CMDENT_ONE_ARG *cmdp2;
04528                 for (cmdp2 = command_table_one_arg; cmdp2->cmdname; cmdp2++)
04529                 {
04530                     s_ptrbuff[0] = '\0';
04531                     s_ptr = s_ptrbuff;
04532                     if (cmdp2->hookmask)
04533                     {
04534                         found = true;
04535                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04536                     }
04537                 }
04538             }
04539             {
04540                 CMDENT_ONE_ARG_CMDARG *cmdp2;
04541                 for (cmdp2 = command_table_one_arg_cmdarg; cmdp2->cmdname; cmdp2++)
04542                 {
04543                     s_ptrbuff[0] = '\0';
04544                     s_ptr = s_ptrbuff;
04545                     if (cmdp2->hookmask)
04546                     {
04547                         found = true;
04548                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04549                     }
04550                 }
04551             }
04552             {
04553                 CMDENT_TWO_ARG *cmdp2;
04554                 for (cmdp2 = command_table_two_arg; cmdp2->cmdname; cmdp2++)
04555                 {
04556                     s_ptrbuff[0] = '\0';
04557                     s_ptr = s_ptrbuff;
04558                     if (cmdp2->hookmask)
04559                     {
04560                         found = true;
04561                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04562                     }
04563                 }
04564             }
04565             {
04566                 CMDENT_TWO_ARG_ARGV *cmdp2;
04567                 for (cmdp2 = command_table_two_arg_argv; cmdp2->cmdname; cmdp2++)
04568                 {
04569                     s_ptrbuff[0] = '\0';
04570                     s_ptr = s_ptrbuff;
04571                     if (cmdp2->hookmask)
04572                     {
04573                         found = true;
04574                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04575                     }
04576                 }
04577             }
04578             {
04579                 CMDENT_TWO_ARG_CMDARG *cmdp2;
04580                 for (cmdp2 = command_table_two_arg_cmdarg; cmdp2->cmdname; cmdp2++)
04581                 {
04582                     s_ptrbuff[0] = '\0';
04583                     s_ptr = s_ptrbuff;
04584                     if (cmdp2->hookmask)
04585                     {
04586                         found = true;
04587                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04588                     }
04589                 }
04590             }
04591             {
04592                 CMDENT_TWO_ARG_ARGV_CMDARG *cmdp2;
04593                 for (cmdp2 = command_table_two_arg_argv_cmdarg; cmdp2->cmdname; cmdp2++)
04594                 {
04595                     s_ptrbuff[0] = '\0';
04596                     s_ptr = s_ptrbuff;
04597                     if (cmdp2->hookmask)
04598                     {
04599                         found = true;
04600                         hook_loop(executor, (CMDENT *)cmdp2, s_ptr, s_ptrbuff);
04601                     }
04602                 }
04603             }
04604             if (!found)
04605             {
04606                 notify(executor, tprintf("%26s -- No @hooks defined --", " "));
04607             }
04608             found = false;
04609             /* We need to search the attribute table as well */
04610             notify(executor, tprintf("%.32s-+-%s",
04611                 "--------------------------------",
04612                 "--------------------------------------------"));
04613             notify(executor, tprintf("%-32s | %s", "Built-in Attribute", "Hook Mask Values"));
04614             notify(executor, tprintf("%.32s-+-%s",
04615                 "--------------------------------",
04616                 "--------------------------------------------"));
04617             cbuff = alloc_sbuf("cbuff_hook");
04618             for (ATTR *ap = attr; ap->name; ap++)
04619             {
04620                 if (ap->flags & AF_NOCMD)
04621                 {
04622                     continue;
04623                 }
04624                 s_ptrbuff[0] = '\0';
04625                 s_ptr = s_ptrbuff;
04626 
04627                 p = cbuff;
04628                 *p++ = '@';
04629                 for (q = (char *) ap->name; *q && p < cbuff + SBUF_SIZE; p++, q++)
04630                 {
04631                     *p = mux_tolower(*q);
04632                 }
04633                 *p = '\0';
04634                 cmdp = (CMDENT *)hashfindLEN(cbuff, strlen(cbuff), &mudstate.command_htab);
04635                 if (  cmdp
04636                    && cmdp->hookmask)
04637                 {
04638                     found = true;
04639                     show_hook(s_ptrbuff, s_ptr, cmdp->hookmask);
04640                     notify(executor, tprintf("%-32.32s | %s", cmdp->cmdname, s_ptrbuff));
04641                 }
04642             }
04643             free_sbuf(cbuff);
04644             if (!found)
04645             {
04646                 notify(executor, tprintf("%26s -- No @hooks defined --", " "));
04647             }
04648             free_lbuf(s_ptrbuff);
04649             notify(executor, tprintf("%.32s-+-%s",
04650                 "--------------------------------",
04651                 "--------------------------------------------"));
04652             notify(executor, tprintf("The hook object is currently: #%d (%s)",
04653                 mudconf.hook_obj,
04654                 (  (  Good_obj(mudconf.hook_obj)
04655                    && !Going(mudconf.hook_obj))
04656                 ? "VALID" : "INVALID")));
04657         }
04658     }
04659 }

Generated on Mon May 28 04:40:08 2007 for MUX by  doxygen 1.4.7