src/command.c

Go to the documentation of this file.
00001 /* 
00002  * command.c - command parser and support routines 
00003  */
00004 
00005 #include "copyright.h"
00006 #include "config.h"
00007 
00008 #include "config.h"
00009 #include "db.h"
00010 #include "interface.h"
00011 #include "mudconf.h"
00012 #include "command.h"
00013 #include "functions.h"
00014 #include "externs.h"
00015 #include "match.h"
00016 #include "attrs.h"
00017 #include "flags.h"
00018 #include "powers.h"
00019 #include "alloc.h"
00020 #include "vattr.h"
00021 #include "mail.h"
00022 #include "comsys.h"
00023 #include "create.h"
00024 #include "macro.h"
00025 #include "p.comsys.h"
00026 
00027 extern void list_cf_access(dbref);
00028 extern void list_siteinfo(dbref);
00029 #ifdef ARBITRARY_LOGFILES
00030 extern void logcache_init(void);
00031 void logcache_list(dbref player);
00032 #endif
00033 
00034 #define CACHING "object"
00035 
00036 /*
00037  * ---------------------------------------------------------------------------
00038  * * Switch tables for the various commands.
00039  */
00040 
00041 #define SW_MULTIPLE     0x80000000      /*
00042                                                                  * This sw may be spec'd w/others  
00043                                                                  */
00044 #define SW_GOT_UNIQUE   0x40000000      /*
00045                                                                          * Already have a unique option  
00046                                                                          */
00047 /*
00048  * (typically via a switch alias) 
00049  */
00050 
00051 #ifdef SQL_SUPPORT
00052 NAMETAB query_sw[] = {
00053         {(char *) "sql", 1, CA_WIZARD, QUERY_SQL},
00054         {(char *) "list", 1, CA_WIZARD, LIST_SQL},
00055         {(char *) "kill", 1, CA_WIZARD, KILL_SQL},
00056         {NULL, 0, 0, 0}
00057 };
00058 #endif
00059 
00060 NAMETAB attrib_sw[] = {
00061         {(char *) "access", 1, CA_GOD, ATTRIB_ACCESS},
00062         {(char *) "delete", 1, CA_GOD, ATTRIB_DELETE},
00063         {(char *) "rename", 1, CA_GOD, ATTRIB_RENAME},
00064         {NULL, 0, 0, 0}
00065 };
00066 
00067 NAMETAB boot_sw[] = {
00068         {(char *) "port", 1, CA_WIZARD, BOOT_PORT | SW_MULTIPLE},
00069         {(char *) "quiet", 1, CA_WIZARD, BOOT_QUIET | SW_MULTIPLE},
00070         {NULL, 0, 0, 0}
00071 };
00072 
00073 NAMETAB cemit_sw[] = {
00074         {(char *) "noheader", 1, CA_PUBLIC, CEMIT_NOHEADER},
00075         {NULL, 0, 0, 0}
00076 };
00077 
00078 NAMETAB clone_sw[] = {
00079         {(char *) "cost", 1, CA_PUBLIC, CLONE_SET_COST},
00080         {(char *) "inherit", 3, CA_PUBLIC, CLONE_INHERIT | SW_MULTIPLE},
00081         {(char *) "inventory", 3, CA_PUBLIC, CLONE_INVENTORY},
00082         {(char *) "location", 1, CA_PUBLIC, CLONE_LOCATION},
00083         {(char *) "parent", 2, CA_PUBLIC, CLONE_PARENT | SW_MULTIPLE},
00084         {(char *) "preserve", 2, CA_WIZARD, CLONE_PRESERVE | SW_MULTIPLE},
00085         {NULL, 0, 0, 0}
00086 };
00087 
00088 NAMETAB clist_sw[] = {
00089         {(char *) "full", 0, CA_PUBLIC, CLIST_FULL},
00090         {NULL, 0, 0, 0}
00091 };
00092 
00093 NAMETAB cstatus_sw[] = {
00094         {(char *) "full", 0, CA_PUBLIC, CSTATUS_FULL},
00095         {NULL, 0, 0, 0}
00096 };
00097 
00098 NAMETAB cset_sw[] = {
00099         {(char *) "public", 2, CA_PUBLIC, CSET_PUBLIC},
00100         {(char *) "private", 2, CA_PUBLIC, CSET_PRIVATE},
00101         {(char *) "loud", 2, CA_PUBLIC, CSET_LOUD},
00102         {(char *) "quiet", 1, CA_PUBLIC, CSET_QUIET},
00103         {(char *) "mute", 1, CA_PUBLIC, CSET_QUIET},
00104         {(char *) "list", 2, CA_PUBLIC, CSET_LIST},
00105         {(char *) "object", 2, CA_PUBLIC, CSET_OBJECT},
00106         {(char *) "transparent", 1, CA_PUBLIC, CSET_TRANSPARENT},
00107         {(char *) "opaque", 1, CA_PUBLIC, CSET_OPAQUE},
00108         {NULL, 0, 0, 0}
00109 };
00110 
00111 NAMETAB decomp_sw[] = {
00112         {(char *) "dbref", 1, CA_PUBLIC, DECOMP_DBREF},
00113         {NULL, 0, 0, 0}
00114 };
00115 
00116 NAMETAB destroy_sw[] = {
00117         {(char *) "override", 8, CA_PUBLIC, DEST_OVERRIDE},
00118         {(char *) "recursive", 9, CA_WIZARD, DEST_RECURSIVE},
00119         {NULL, 0, 0, 0}
00120 };
00121 
00122 NAMETAB dig_sw[] = {
00123         {(char *) "teleport", 1, CA_PUBLIC, DIG_TELEPORT},
00124         {NULL, 0, 0, 0}
00125 };
00126 
00127 NAMETAB doing_sw[] = {
00128         {(char *) "header", 1, CA_PUBLIC, DOING_HEADER},
00129         {(char *) "message", 1, CA_PUBLIC, DOING_MESSAGE},
00130         {(char *) "poll", 1, CA_PUBLIC, DOING_POLL},
00131         {NULL, 0, 0, 0}
00132 };
00133 
00134 NAMETAB dolist_sw[] = {
00135         {(char *) "delimit", 1, CA_PUBLIC, DOLIST_DELIMIT},
00136         {(char *) "space", 1, CA_PUBLIC, DOLIST_SPACE},
00137         {NULL, 0, 0, 0,}
00138 };
00139 
00140 NAMETAB drop_sw[] = {
00141         {(char *) "quiet", 1, CA_PUBLIC, DROP_QUIET},
00142         {NULL, 0, 0, 0}
00143 };
00144 
00145 NAMETAB dump_sw[] = {
00146         {(char *) "structure", 1, CA_WIZARD, DUMP_STRUCT | SW_MULTIPLE},
00147         {(char *) "text", 1, CA_WIZARD, DUMP_TEXT | SW_MULTIPLE},
00148         {(char *) "optimize", 1, CA_WIZARD, DUMP_OPTIMIZE | SW_MULTIPLE},
00149         {NULL, 0, 0, 0}
00150 };
00151 
00152 NAMETAB emit_sw[] = {
00153         {(char *) "here", 1, CA_PUBLIC, SAY_HERE | SW_MULTIPLE},
00154         {(char *) "room", 1, CA_PUBLIC, SAY_ROOM | SW_MULTIPLE},
00155         {NULL, 0, 0, 0}
00156 };
00157 
00158 NAMETAB enter_sw[] = {
00159         {(char *) "quiet", 1, CA_PUBLIC, MOVE_QUIET},
00160         {NULL, 0, 0, 0}
00161 };
00162 
00163 NAMETAB examine_sw[] = {
00164         {(char *) "brief", 1, CA_PUBLIC, EXAM_BRIEF},
00165         {(char *) "debug", 1, CA_WIZARD, EXAM_DEBUG},
00166         {(char *) "full", 1, CA_PUBLIC, EXAM_LONG},
00167         {(char *) "parent", 1, CA_PUBLIC, EXAM_PARENT},
00168         {NULL, 0, 0, 0}
00169 };
00170 
00171 NAMETAB femit_sw[] = {
00172         {(char *) "here", 1, CA_PUBLIC, PEMIT_HERE | SW_MULTIPLE},
00173         {(char *) "room", 1, CA_PUBLIC, PEMIT_ROOM | SW_MULTIPLE},
00174         {NULL, 0, 0, 0}
00175 };
00176 
00177 NAMETAB fixdb_sw[] = {
00178         /* {(char *)"add_pname",1,  CA_GOD,     FIXDB_ADD_PN}, */
00179         {(char *) "contents", 1, CA_GOD, FIXDB_CON},
00180         {(char *) "exits", 1, CA_GOD, FIXDB_EXITS},
00181         {(char *) "location", 1, CA_GOD, FIXDB_LOC},
00182         {(char *) "next", 1, CA_GOD, FIXDB_NEXT},
00183         {(char *) "owner", 1, CA_GOD, FIXDB_OWNER},
00184         {(char *) "pennies", 1, CA_GOD, FIXDB_PENNIES},
00185         {(char *) "rename", 1, CA_GOD, FIXDB_NAME},
00186         /* {(char *)"rm_pname", 1,  CA_GOD,     FIXDB_DEL_PN}, */
00187         {NULL, 0, 0, 0}
00188 };
00189 
00190 NAMETAB fpose_sw[] = {
00191         {(char *) "default", 1, CA_PUBLIC, 0},
00192         {(char *) "nospace", 1, CA_PUBLIC, SAY_NOSPACE},
00193         {NULL, 0, 0, 0}
00194 };
00195 
00196 NAMETAB function_sw[] = {
00197         {(char *) "privileged", 3, CA_WIZARD, FN_PRIV},
00198         {(char *) "preserve", 3, CA_WIZARD, FN_PRES},
00199         {NULL, 0, 0, 0}
00200 };
00201 
00202 NAMETAB get_sw[] = {
00203         {(char *) "quiet", 1, CA_PUBLIC, GET_QUIET},
00204         {NULL, 0, 0, 0}
00205 };
00206 
00207 NAMETAB give_sw[] = {
00208         {(char *) "quiet", 1, CA_WIZARD, GIVE_QUIET},
00209         {NULL, 0, 0, 0}
00210 };
00211 
00212 NAMETAB goto_sw[] = {
00213         {(char *) "quiet", 1, CA_PUBLIC, MOVE_QUIET},
00214         {NULL, 0, 0, 0}
00215 };
00216 
00217 NAMETAB halt_sw[] = {
00218         {(char *) "all", 1, CA_PUBLIC, HALT_ALL},
00219         {NULL, 0, 0, 0}
00220 };
00221 
00222 NAMETAB leave_sw[] = {
00223         {(char *) "quiet", 1, CA_PUBLIC, MOVE_QUIET},
00224         {NULL, 0, 0, 0}
00225 };
00226 
00227 NAMETAB listmotd_sw[] = {
00228         {(char *) "brief", 1, CA_WIZARD, MOTD_BRIEF},
00229         {NULL, 0, 0, 0}
00230 };
00231 
00232 NAMETAB lock_sw[] = {
00233         {(char *) "defaultlock", 1, CA_PUBLIC, A_LOCK},
00234         {(char *) "droplock", 1, CA_PUBLIC, A_LDROP},
00235         {(char *) "enterlock", 1, CA_PUBLIC, A_LENTER},
00236         {(char *) "givelock", 1, CA_PUBLIC, A_LGIVE},
00237         {(char *) "leavelock", 2, CA_PUBLIC, A_LLEAVE},
00238         {(char *) "linklock", 2, CA_PUBLIC, A_LLINK},
00239         {(char *) "pagelock", 3, CA_PUBLIC, A_LPAGE},
00240         {(char *) "parentlock", 3, CA_PUBLIC, A_LPARENT},
00241         {(char *) "receivelock", 1, CA_PUBLIC, A_LRECEIVE},
00242         {(char *) "teloutlock", 2, CA_PUBLIC, A_LTELOUT},
00243         {(char *) "tportlock", 2, CA_PUBLIC, A_LTPORT},
00244         {(char *) "uselock", 1, CA_PUBLIC, A_LUSE},
00245         {(char *) "userlock", 4, CA_PUBLIC, A_LUSER},
00246         {(char *) "speechlock", 1, CA_PUBLIC, A_LSPEECH},
00247         {NULL, 0, 0, 0}
00248 };
00249 
00250 NAMETAB look_sw[] = {
00251         {(char *) "outside", 1, CA_PUBLIC, LOOK_OUTSIDE},
00252         {NULL, 0, 0, 0}
00253 };
00254 
00255 NAMETAB mail_sw[] = {
00256         {(char *) "stats", 1, CA_PUBLIC, MAIL_STATS},
00257         {(char *) "dstats", 1, CA_PUBLIC, MAIL_DSTATS},
00258         {(char *) "fstats", 1, CA_PUBLIC, MAIL_FSTATS},
00259         {(char *) "debug", 1, CA_PUBLIC, MAIL_DEBUG},
00260         {(char *) "nuke", 1, CA_PUBLIC, MAIL_NUKE},
00261         {(char *) "folder", 1, CA_PUBLIC, MAIL_FOLDER},
00262         {(char *) "list", 1, CA_PUBLIC, MAIL_LIST},
00263         {(char *) "read", 1, CA_PUBLIC, MAIL_READ},
00264         {(char *) "clear", 1, CA_PUBLIC, MAIL_CLEAR},
00265         {(char *) "unclear", 1, CA_PUBLIC, MAIL_UNCLEAR},
00266         {(char *) "purge", 1, CA_PUBLIC, MAIL_PURGE},
00267         {(char *) "file", 1, CA_PUBLIC, MAIL_FILE},
00268         {(char *) "tag", 1, CA_PUBLIC, MAIL_TAG},
00269         {(char *) "untag", 1, CA_PUBLIC, MAIL_UNTAG},
00270         {(char *) "fwd", 2, CA_PUBLIC, MAIL_FORWARD},
00271         {(char *) "forward", 2, CA_PUBLIC, MAIL_FORWARD},
00272         {(char *) "send", 0, CA_PUBLIC, MAIL_SEND},
00273         {(char *) "edit", 2, CA_PUBLIC, MAIL_EDIT},
00274         {(char *) "urgent", 1, CA_PUBLIC, MAIL_URGENT},
00275         {(char *) "alias", 1, CA_PUBLIC, MAIL_ALIAS},
00276         {(char *) "alist", 1, CA_PUBLIC, MAIL_ALIST},
00277         {(char *) "proof", 1, CA_PUBLIC, MAIL_PROOF},
00278         {(char *) "abort", 0, CA_PUBLIC, MAIL_ABORT},
00279         {(char *) "quick", 0, CA_PUBLIC, MAIL_QUICK},
00280         {(char *) "review", 2, CA_PUBLIC, MAIL_REVIEW},
00281         {(char *) "retract", 2, CA_PUBLIC, MAIL_RETRACT},
00282         {(char *) "cc", 2, CA_PUBLIC, MAIL_CC},
00283         {(char *) "safe", 2, CA_PUBLIC, MAIL_SAFE}
00284 };
00285 
00286 NAMETAB malias_sw[] = {
00287         {(char *) "desc", 1, CA_PUBLIC, MALIAS_DESC},
00288         {(char *) "chown", 1, CA_PUBLIC, MALIAS_CHOWN},
00289         {(char *) "add", 1, CA_PUBLIC, MALIAS_ADD},
00290         {(char *) "remove", 1, CA_PUBLIC, MALIAS_REMOVE},
00291         {(char *) "delete", 1, CA_PUBLIC, MALIAS_DELETE},
00292         {(char *) "rename", 1, CA_PUBLIC, MALIAS_RENAME},
00293         {(char *) "list", 1, CA_PUBLIC, MALIAS_LIST},
00294         {(char *) "status", 1, CA_PUBLIC, MALIAS_STATUS}
00295 };
00296 
00297 NAMETAB motd_sw[] = {
00298         {(char *) "brief", 1, CA_WIZARD, MOTD_BRIEF | SW_MULTIPLE},
00299         {(char *) "connect", 1, CA_WIZARD, MOTD_ALL},
00300         {(char *) "down", 1, CA_WIZARD, MOTD_DOWN},
00301         {(char *) "full", 1, CA_WIZARD, MOTD_FULL},
00302         {(char *) "list", 1, CA_PUBLIC, MOTD_LIST},
00303         {(char *) "wizard", 1, CA_WIZARD, MOTD_WIZ},
00304         {NULL, 0, 0, 0}
00305 };
00306 
00307 NAMETAB notify_sw[] = {
00308         {(char *) "all", 1, CA_PUBLIC, NFY_NFYALL},
00309         {(char *) "first", 1, CA_PUBLIC, NFY_NFY},
00310         {NULL, 0, 0, 0}
00311 };
00312 
00313 NAMETAB open_sw[] = {
00314         {(char *) "inventory", 1, CA_PUBLIC, OPEN_INVENTORY},
00315         {(char *) "location", 1, CA_PUBLIC, OPEN_LOCATION},
00316         {NULL, 0, 0, 0}
00317 };
00318 
00319 NAMETAB pemit_sw[] = {
00320         {(char *) "contents", 1, CA_PUBLIC, PEMIT_CONTENTS | SW_MULTIPLE},
00321         {(char *) "object", 1, CA_PUBLIC, 0},
00322         {(char *) "silent", 1, CA_PUBLIC, 0},
00323         {(char *) "list", 1, CA_PUBLIC, PEMIT_LIST | SW_MULTIPLE},
00324         {NULL, 0, 0, 0}
00325 };
00326 
00327 NAMETAB pose_sw[] = {
00328         {(char *) "default", 1, CA_PUBLIC, 0},
00329         {(char *) "nospace", 1, CA_PUBLIC, SAY_NOSPACE},
00330         {NULL, 0, 0, 0}
00331 };
00332 
00333 NAMETAB ps_sw[] = {
00334         {(char *) "all", 1, CA_PUBLIC, PS_ALL | SW_MULTIPLE},
00335         {(char *) "brief", 1, CA_PUBLIC, PS_BRIEF},
00336         {(char *) "long", 1, CA_PUBLIC, PS_LONG},
00337         {(char *) "summary", 1, CA_PUBLIC, PS_SUMM},
00338         {NULL, 0, 0, 0}
00339 };
00340 
00341 NAMETAB quota_sw[] = {
00342         {(char *) "all", 1, CA_GOD, QUOTA_ALL | SW_MULTIPLE},
00343         {(char *) "fix", 1, CA_WIZARD, QUOTA_FIX},
00344         {(char *) "remaining", 1, CA_WIZARD, QUOTA_REM | SW_MULTIPLE},
00345         {(char *) "set", 1, CA_WIZARD, QUOTA_SET},
00346         {(char *) "total", 1, CA_WIZARD, QUOTA_TOT | SW_MULTIPLE},
00347         {NULL, 0, 0, 0}
00348 };
00349 
00350 NAMETAB set_sw[] = {
00351         {(char *) "quiet", 1, CA_PUBLIC, SET_QUIET},
00352         {NULL, 0, 0, 0}
00353 };
00354 
00355 NAMETAB stats_sw[] = {
00356         {(char *) "all", 1, CA_PUBLIC, STAT_ALL},
00357         {(char *) "me", 1, CA_PUBLIC, STAT_ME},
00358         {(char *) "player", 1, CA_PUBLIC, STAT_PLAYER},
00359         {NULL, 0, 0, 0}
00360 };
00361 
00362 NAMETAB sweep_sw[] = {
00363         {(char *) "commands", 3, CA_PUBLIC, SWEEP_COMMANDS | SW_MULTIPLE},
00364         {(char *) "connected", 3, CA_PUBLIC, SWEEP_CONNECT | SW_MULTIPLE},
00365         {(char *) "exits", 1, CA_PUBLIC, SWEEP_EXITS | SW_MULTIPLE},
00366         {(char *) "here", 1, CA_PUBLIC, SWEEP_HERE | SW_MULTIPLE},
00367         {(char *) "inventory", 1, CA_PUBLIC, SWEEP_ME | SW_MULTIPLE},
00368         {(char *) "listeners", 1, CA_PUBLIC, SWEEP_LISTEN | SW_MULTIPLE},
00369         {(char *) "players", 1, CA_PUBLIC, SWEEP_PLAYER | SW_MULTIPLE},
00370         {NULL, 0, 0, 0}
00371 };
00372 
00373 NAMETAB switch_sw[] = {
00374         {(char *) "all", 1, CA_PUBLIC, SWITCH_ANY},
00375         {(char *) "default", 1, CA_PUBLIC, SWITCH_DEFAULT},
00376         {(char *) "first", 1, CA_PUBLIC, SWITCH_ONE},
00377         {NULL, 0, 0, 0}
00378 };
00379 
00380 NAMETAB teleport_sw[] = {
00381         {(char *) "loud", 1, CA_PUBLIC, TELEPORT_DEFAULT},
00382         {(char *) "quiet", 1, CA_PUBLIC, TELEPORT_QUIET},
00383         {NULL, 0, 0, 0}
00384 };
00385 
00386 NAMETAB toad_sw[] = {
00387         {(char *) "no_chown", 1, CA_WIZARD, TOAD_NO_CHOWN | SW_MULTIPLE},
00388         {NULL, 0, 0, 0}
00389 };
00390 
00391 NAMETAB trig_sw[] = {
00392         {(char *) "quiet", 1, CA_PUBLIC, TRIG_QUIET},
00393         {NULL, 0, 0, 0}
00394 };
00395 
00396 NAMETAB wall_sw[] = {
00397         {(char *) "emit", 1, CA_ANNOUNCE, SAY_WALLEMIT},
00398         {(char *) "no_prefix", 1, CA_ANNOUNCE, SAY_NOTAG | SW_MULTIPLE},
00399         {(char *) "pose", 1, CA_ANNOUNCE, SAY_WALLPOSE},
00400         {(char *) "wizard", 1, CA_ANNOUNCE, SAY_WIZSHOUT | SW_MULTIPLE},
00401         {(char *) "admin", 1, CA_ADMIN, SAY_ADMINSHOUT},
00402         {NULL, 0, 0, 0}
00403 };
00404 
00405 NAMETAB warp_sw[] = {
00406         {(char *) "check", 1, CA_WIZARD, TWARP_CLEAN | SW_MULTIPLE},
00407         {(char *) "dump", 1, CA_WIZARD, TWARP_DUMP | SW_MULTIPLE},
00408         {(char *) "idle", 1, CA_WIZARD, TWARP_IDLE | SW_MULTIPLE},
00409         {(char *) "queue", 1, CA_WIZARD, TWARP_QUEUE | SW_MULTIPLE},
00410         {(char *) "events", 1, CA_WIZARD, TWARP_EVENTS | SW_MULTIPLE},
00411         {NULL, 0, 0, 0}
00412 };
00413 
00414 /* ---------------------------------------------------------------------------
00415  * Command table: Definitions for builtin commands, used to build the command
00416  * hash table.
00417  *
00418  * Format:  Name                Switches        Permissions Needed
00419  *      Key (if any)    Calling Seq                     Handler
00420  */
00421 
00422 CMDENT command_table[] = {
00423         {(char *) "@@", NULL, 0, 0, CS_NO_ARGS, do_comment},
00424         {(char *) "@addcommand", NULL, CA_GOD, 0, CS_TWO_ARG, do_addcommand},
00425         {(char *) "@admin", NULL, CA_WIZARD, 0, CS_TWO_ARG | CS_INTERP, do_admin},
00426         {(char *) "@alias", NULL, CA_NO_GUEST | CA_NO_SLAVE, 0, CS_TWO_ARG,
00427          do_alias},
00428         {(char *) "@attribute", attrib_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP,
00429          do_attribute},
00430         {(char *) "@boot", boot_sw, CA_NO_GUEST | CA_NO_SLAVE, 0,
00431          CS_ONE_ARG | CS_INTERP, do_boot},
00432         {(char *) "@cboot", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_TWO_ARG,
00433          do_chboot},
00434         {(char *) "@ccharge", NULL, CA_NO_SLAVE | CA_NO_GUEST, 1, CS_TWO_ARG,
00435          do_editchannel},
00436         {(char *) "@cchown", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_TWO_ARG,
00437          do_editchannel},
00438         {(char *) "@ccreate", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_ONE_ARG,
00439          do_createchannel},
00440         {(char *) "@cdestroy", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_ONE_ARG,
00441          do_destroychannel},
00442         {(char *) "@cemit", cemit_sw, CA_NO_SLAVE | CA_NO_GUEST, 0, CS_TWO_ARG,
00443          do_cemit},
00444         {(char *) "@chown", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD,
00445          CHOWN_ONE, CS_TWO_ARG | CS_INTERP, do_chown},
00446         {(char *) "@chownall", NULL, CA_WIZARD | CA_GBL_BUILD, CHOWN_ALL,
00447          CS_TWO_ARG | CS_INTERP, do_chownall},
00448         {(char *) "@chzone", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0,
00449          CS_TWO_ARG | CS_INTERP, do_chzone},
00450         {(char *) "@clone", clone_sw,
00451          CA_NO_SLAVE | CA_GBL_BUILD | CA_CONTENTS | CA_NO_GUEST,
00452          0, CS_TWO_ARG | CS_INTERP, do_clone},
00453         {(char *) "@clist", clist_sw, CA_NO_SLAVE, 0, CS_NO_ARGS, do_chanlist},
00454         {(char *) "@cstatus", cstatus_sw, CA_NO_SLAVE, 0, CS_ONE_ARG,
00455          do_chanstatus},
00456         {(char *) "@coflags", NULL, CA_NO_SLAVE, 4, CS_TWO_ARG, do_editchannel},
00457         {(char *) "@cpattr", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0,
00458          CS_TWO_ARG | CS_ARGV, do_cpattr},
00459         {(char *) "@cpflags", NULL, CA_NO_SLAVE, 3, CS_TWO_ARG, do_editchannel},
00460         {(char *) "@create", NULL,
00461          CA_NO_SLAVE | CA_GBL_BUILD | CA_CONTENTS | CA_NO_GUEST,
00462          0, CS_TWO_ARG | CS_INTERP, do_create},
00463         {(char *) "@cset", cset_sw, CA_NO_SLAVE, 0, CS_TWO_ARG | CS_INTERP,
00464          do_chopen},
00465         {(char *) "@cut", NULL, CA_WIZARD | CA_LOCATION, 0,
00466          CS_ONE_ARG | CS_INTERP, do_cut},
00467         {(char *) "@cwho", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, do_channelwho},
00468         {(char *) "@dbck", NULL, CA_WIZARD, 0, CS_NO_ARGS, do_dbck},
00469         {(char *) "@dbclean", NULL, CA_GOD, 0, CS_NO_ARGS, do_dbclean},
00470         {(char *) "@decompile", decomp_sw, 0, 0, CS_TWO_ARG | CS_INTERP,
00471          do_decomp},
00472         {(char *) "@delcommand", NULL, CA_GOD, 0, CS_TWO_ARG, do_delcommand},
00473         {(char *) "@destroy", destroy_sw,
00474          CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD,
00475          DEST_ONE, CS_ONE_ARG | CS_INTERP, do_destroy},
00476         /*{(char *)"@destroyall", NULL, CA_WIZARD|CA_GBL_BUILD,
00477            DEST_ALL, CS_ONE_ARG, do_destroy}, */
00478         {(char *) "@dig", dig_sw, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD,
00479          0, CS_TWO_ARG | CS_ARGV | CS_INTERP, do_dig},
00480         {(char *) "@disable", NULL, CA_WIZARD, GLOB_DISABLE, CS_ONE_ARG,
00481          do_global},
00482         {(char *) "@doing", doing_sw, CA_PUBLIC, 0, CS_ONE_ARG, do_doing},
00483         {(char *) "@dolist", dolist_sw, CA_GBL_INTERP,
00484          0, CS_TWO_ARG | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND | CS_NO_MACRO,
00485          do_dolist},
00486         {(char *) "@drain", NULL, CA_GBL_INTERP | CA_NO_SLAVE | CA_NO_GUEST,
00487          NFY_DRAIN, CS_TWO_ARG, do_notify},
00488         {(char *) "@dump", dump_sw, CA_WIZARD, 0, CS_NO_ARGS, do_dump},
00489         {(char *) "@edit", NULL, CA_NO_SLAVE | CA_NO_GUEST, 0,
00490          CS_TWO_ARG | CS_ARGV | CS_STRIP_AROUND, do_edit},
00491         {(char *) "@emit", emit_sw, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE,
00492          SAY_EMIT, CS_ONE_ARG | CS_INTERP, do_say},
00493         {(char *) "@enable", NULL, CA_WIZARD, GLOB_ENABLE, CS_ONE_ARG, do_global},
00494         {(char *) "@entrances", NULL, CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP,
00495          do_entrances},
00496         {(char *) "@femit", femit_sw, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE,
00497          PEMIT_FEMIT, CS_TWO_ARG | CS_INTERP, do_pemit},
00498         {(char *) "@find", NULL, 0, 0, CS_ONE_ARG | CS_INTERP, do_find},
00499         {(char *) "@fixdb", fixdb_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP,
00500          do_fixdb},
00501         /*{(char *)"@fnd", NULL, 0, 0, CS_ONE_ARG|CS_UNPARSE, do_fnd}, */
00502         {(char *) "@force", NULL, CA_NO_SLAVE | CA_GBL_INTERP | CA_NO_GUEST,
00503          FRC_COMMAND, CS_TWO_ARG | CS_INTERP | CS_CMDARG | CS_NO_MACRO, do_force},
00504         {(char *) "@fpose", fpose_sw, CA_LOCATION | CA_NO_SLAVE, PEMIT_FPOSE,
00505          CS_TWO_ARG | CS_INTERP, do_pemit},
00506         {(char *) "@fsay", NULL, CA_LOCATION | CA_NO_SLAVE, PEMIT_FSAY,
00507          CS_TWO_ARG | CS_INTERP, do_pemit},
00508         {(char *) "@function", function_sw, CA_GOD, 0, CS_TWO_ARG | CS_INTERP,
00509          do_function},
00510         {(char *) "@halt", halt_sw, CA_NO_SLAVE, 0, CS_ONE_ARG | CS_INTERP,
00511          do_halt},
00512         {(char *) "@kick", NULL, CA_WIZARD, QUEUE_KICK, CS_ONE_ARG | CS_INTERP,
00513          do_queue},
00514         {(char *) "@last", NULL, CA_NO_GUEST, 0, CS_ONE_ARG | CS_INTERP, do_last},
00515         {(char *) "@link", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST,
00516          0, CS_TWO_ARG | CS_INTERP, do_link},
00517         {(char *) "@list", NULL, 0, 0, CS_ONE_ARG | CS_INTERP, do_list},
00518         {(char *) "@listcommands", NULL, CA_GOD, 0, CS_ONE_ARG, do_listcommands},
00519         {(char *) "@list_file", NULL, CA_WIZARD, 0, CS_ONE_ARG | CS_INTERP,
00520          do_list_file},
00521         {(char *) "@listmotd", listmotd_sw, 0, MOTD_LIST, CS_ONE_ARG, do_motd},
00522         {(char *) "@lock", lock_sw, CA_NO_SLAVE, 0, CS_TWO_ARG | CS_INTERP,
00523          do_lock},
00524 #ifdef ARBITRARY_LOGFILES
00525         {(char *) "@log", NULL, CA_WIZARD, 0, CS_TWO_ARG, do_log},
00526 #endif
00527         {(char *) "@mail", mail_sw, CA_NO_SLAVE | CA_NO_GUEST | CA_NO_IC, 0,
00528          CS_TWO_ARG | CS_INTERP, do_mail},
00529         {(char *) "@malias", malias_sw, CA_NO_SLAVE | CA_NO_GUEST, 0,
00530          CS_TWO_ARG | CS_INTERP, do_malias},
00531         {(char *) "@motd", motd_sw, CA_WIZARD, 0, CS_ONE_ARG, do_motd},
00532         {(char *) "@mvattr", NULL, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD,
00533          0, CS_TWO_ARG | CS_ARGV, do_mvattr},
00534         {(char *) "@name", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0,
00535          CS_TWO_ARG | CS_INTERP, do_name},
00536         {(char *) "@newpassword", NULL, CA_WIZARD, PASS_ANY, CS_TWO_ARG,
00537          do_newpassword},
00538         {(char *) "@notify", notify_sw, CA_GBL_INTERP | CA_NO_SLAVE | CA_NO_GUEST,
00539          0, CS_TWO_ARG, do_notify},
00540         {(char *) "@oemit", NULL, CA_LOCATION | CA_NO_GUEST | CA_NO_SLAVE,
00541          PEMIT_OEMIT, CS_TWO_ARG | CS_INTERP, do_pemit},
00542         {(char *) "@open", open_sw, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0,
00543          CS_TWO_ARG | CS_ARGV | CS_INTERP, do_open},
00544         {(char *) "@parent", NULL, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0,
00545          CS_TWO_ARG, do_parent},
00546         {(char *) "@password", NULL, CA_NO_GUEST, PASS_MINE, CS_TWO_ARG,
00547          do_password},
00548         {(char *) "@pcreate", NULL, CA_WIZARD | CA_GBL_BUILD, PCRE_PLAYER,
00549          CS_TWO_ARG, do_pcreate},
00550         {(char *) "@pemit", pemit_sw, CA_NO_GUEST | CA_NO_SLAVE, PEMIT_PEMIT,
00551          CS_TWO_ARG | CS_INTERP, do_pemit},
00552         {(char *) "@npemit", pemit_sw, CA_NO_GUEST | CA_NO_SLAVE, PEMIT_PEMIT,
00553          CS_TWO_ARG | CS_UNPARSE, do_pemit},
00554         {(char *) "@poor", NULL, CA_GOD, 0, CS_ONE_ARG | CS_INTERP, do_poor},
00555         {(char *) "@power", NULL, 0, 0, CS_TWO_ARG, do_power},
00556         {(char *) "@program", NULL, CA_PUBLIC, 0, CS_TWO_ARG | CS_INTERP,
00557          do_prog},
00558 #ifdef USE_PYTHON
00559         {(char *) "@python", NULL, CA_WIZARD, 0, CS_INTERP | CS_ONE_ARG,
00560          do_python},
00561 #endif
00562         {(char *) "@ps", ps_sw, 0, 0, CS_ONE_ARG | CS_INTERP, do_ps},
00563         {(char *) "@quota", quota_sw, 0, 0, CS_TWO_ARG | CS_INTERP, do_quota},
00564         {(char *) "@quitprogram", NULL, CA_PUBLIC, 0, CS_ONE_ARG | CS_INTERP,
00565          do_quitprog},
00566         {(char *) "@readcache", NULL, CA_WIZARD, 0, CS_NO_ARGS, do_readcache},
00567         {(char *) "@restart", NULL, CA_WIZARD, 0, CS_NO_ARGS, do_restart},
00568         {(char *) "@robot", NULL,
00569          CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST | CA_PLAYER, PCRE_ROBOT,
00570          CS_TWO_ARG, do_pcreate},
00571         {(char *) "@search", NULL, 0, SRCH_SEARCH, CS_ONE_ARG | CS_NOINTERP,
00572          do_search},
00573         {(char *) "@set", set_sw, CA_NO_SLAVE | CA_GBL_BUILD | CA_NO_GUEST, 0,
00574          CS_TWO_ARG, do_set},
00575         {(char *) "@shutdown", NULL, CA_WIZARD, 0, CS_ONE_ARG, do_shutdown},
00576         {(char *) "@stats", stats_sw, 0, 0, CS_ONE_ARG | CS_INTERP, do_stats},
00577         {(char *) "@sweep", sweep_sw, 0, 0, CS_ONE_ARG, do_sweep},
00578         {(char *) "@switch", switch_sw, CA_GBL_INTERP, 0,
00579          CS_TWO_ARG | CS_ARGV | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND,
00580          do_switch},
00581         {(char *) "@teleport", teleport_sw, CA_NO_GUEST, TELEPORT_DEFAULT,
00582          CS_TWO_ARG | CS_INTERP, do_teleport},
00583         {(char *) "@timewarp", warp_sw, CA_WIZARD, 0, CS_ONE_ARG | CS_INTERP,
00584          do_timewarp},
00585         {(char *) "@toad", toad_sw, CA_WIZARD, 0, CS_TWO_ARG | CS_INTERP,
00586          do_toad},
00587         {(char *) "@trigger", trig_sw, CA_GBL_INTERP, 0, CS_TWO_ARG | CS_ARGV,
00588          do_trigger},
00589         {(char *) "@unlink", NULL, CA_NO_SLAVE | CA_GBL_BUILD, 0,
00590          CS_ONE_ARG | CS_INTERP, do_unlink},
00591         {(char *) "@unlock", lock_sw, CA_NO_SLAVE, 0, CS_ONE_ARG | CS_INTERP,
00592          do_unlock},
00593         {(char *) "@verb", NULL, CA_GBL_INTERP | CA_NO_SLAVE, 0,
00594          CS_TWO_ARG | CS_ARGV | CS_INTERP | CS_STRIP_AROUND,
00595          do_verb},
00596         {(char *) "@wait", NULL, CA_GBL_INTERP, 0,
00597          CS_TWO_ARG | CS_CMDARG | CS_NOINTERP | CS_STRIP_AROUND | CS_NO_MACRO,
00598          do_wait},
00599         {(char *) "@wall", wall_sw, CA_ANNOUNCE, SAY_SHOUT,
00600          CS_ONE_ARG | CS_INTERP, do_say},
00601         {(char *) "@wipe", wall_sw, CA_NO_SLAVE | CA_NO_GUEST | CA_GBL_BUILD, 0,
00602          CS_ONE_ARG | CS_INTERP, do_wipe},
00603         {(char *) "addcom", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_TWO_ARG,
00604          do_addcom},
00605         {(char *) "allcom", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_ONE_ARG,
00606          do_allcom},
00607         {(char *) "comlist", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_NO_ARGS,
00608          do_comlist},
00609         {(char *) "comtitle", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_TWO_ARG,
00610          do_comtitle},
00611         {(char *) "clearcom", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_NO_ARGS,
00612          do_clearcom},
00613         {(char *) "delcom", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_ONE_ARG,
00614          do_delcom},
00615         {(char *) "drop", drop_sw,
00616          CA_NO_SLAVE | CA_CONTENTS | CA_LOCATION | CA_NO_GUEST, 0,
00617          CS_ONE_ARG | CS_INTERP, do_drop},
00618         {(char *) "enter", enter_sw, CA_LOCATION, 0, CS_ONE_ARG | CS_INTERP,
00619          do_enter},
00620         {(char *) "examine", examine_sw, 0, 0, CS_ONE_ARG | CS_INTERP,
00621          do_examine},
00622         {(char *) "get", get_sw, CA_LOCATION | CA_NO_GUEST, 0,
00623          CS_ONE_ARG | CS_INTERP, do_get},
00624         {(char *) "give", give_sw, CA_LOCATION | CA_NO_GUEST, 0,
00625          CS_TWO_ARG | CS_INTERP, do_give},
00626         {(char *) "goto", goto_sw, CA_LOCATION | CA_NO_SLAVE, 0,
00627          CS_ONE_ARG | CS_INTERP, do_move},
00628 #ifdef MOVE_HELP
00629         {(char *) "muxhelp", NULL, 0, HELP_HELP, CS_ONE_ARG, do_help},
00630 #else
00631         {(char *) "help", NULL, 0, HELP_HELP, CS_ONE_ARG, do_help},
00632 #endif
00633         {(char *) "inventory", NULL, 0, LOOK_INVENTORY, CS_NO_ARGS, do_inventory},
00634         {(char *) "kill", NULL, CA_WIZARD /*CA_NO_GUEST|CA_NO_SLAVE */ ,
00635          KILL_KILL, CS_TWO_ARG | CS_INTERP, do_kill},
00636         {(char *) "leave", leave_sw, CA_LOCATION, 0, CS_NO_ARGS | CS_INTERP,
00637          do_leave},
00638         {(char *) "look", look_sw, CA_LOCATION, LOOK_LOOK, CS_ONE_ARG | CS_INTERP, do_look},
00639         {(char *) "news", NULL, 0, HELP_NEWS, CS_ONE_ARG, do_help},
00640         {(char *) "page", NULL, CA_NO_SLAVE, 0, CS_TWO_ARG | CS_INTERP, do_page},
00641         {(char *) "pose", pose_sw, CA_LOCATION | CA_NO_SLAVE, SAY_POSE,
00642          CS_ONE_ARG | CS_INTERP, do_say},
00643         {(char *) "say", NULL, CA_LOCATION | CA_NO_SLAVE, SAY_SAY,
00644          CS_ONE_ARG | CS_INTERP, do_say},
00645         {(char *) "score", NULL, 0, LOOK_SCORE, CS_NO_ARGS, do_score},
00646         {(char *) "slay", NULL, CA_WIZARD, KILL_SLAY, CS_TWO_ARG | CS_INTERP,
00647          do_kill},
00648         {(char *) "think", NULL, CA_NO_SLAVE, 0, CS_ONE_ARG, do_think},
00649         {(char *) "use", NULL, CA_NO_SLAVE | CA_GBL_INTERP, 0,
00650          CS_ONE_ARG | CS_INTERP, do_use},
00651         {(char *) "version", NULL, 0, 0, CS_NO_ARGS, do_version},
00652         {(char *) "whisper", NULL, CA_LOCATION | CA_NO_SLAVE, PEMIT_WHISPER,
00653          CS_TWO_ARG | CS_INTERP, do_pemit},
00654         {(char *) "wizhelp", NULL, CA_WIZARD, HELP_WIZHELP, CS_ONE_ARG, do_help},
00655         {(char *) "+show", NULL, CA_NO_SLAVE | CA_NO_IC, 0, CS_TWO_ARG, do_show},
00656         {(char *) "+rolls", NULL, CA_NO_SLAVE, 0, CS_NO_ARGS, do_show_stat},
00657         {(char *) "+charclear", NULL, CA_WIZARD, 0, CS_ONE_ARG, do_charclear},
00658 #ifdef HUDINFO_SUPPORT
00659         {(char *) "hudinfo", NULL, CA_PUBLIC, 0, CS_ONE_ARG, fake_hudinfo},
00660 #endif
00661         {(char *) PLUSHELP_COMMAND, NULL, 0, HELP_PLUSHELP, CS_ONE_ARG, do_help},
00662         {(char *) "wiznews", NULL, CA_WIZARD, HELP_WIZNEWS, CS_ONE_ARG, do_help},
00663     {(char *) "\\", NULL, CA_NO_GUEST | CA_LOCATION | CF_DARK | CA_NO_SLAVE,
00664          SAY_PREFIX, CS_ONE_ARG | CS_INTERP, do_say},
00665         {(char *) "#", NULL, CA_NO_SLAVE | CA_GBL_INTERP | CF_DARK, 0,
00666          CS_ONE_ARG | CS_INTERP | CS_CMDARG, do_force_prefixed},
00667         {(char *) ":", NULL, CA_LOCATION | CF_DARK, SAY_PREFIX,
00668          CS_ONE_ARG | CS_INTERP | CS_LEADIN, do_say},
00669         {(char *) ";", NULL, CA_LOCATION | CF_DARK, SAY_PREFIX,
00670          CS_ONE_ARG | CS_INTERP | CS_LEADIN, do_say},
00671 #ifdef USE_PYTHON
00672         {(char *) ",", NULL, CA_WIZARD, 0, CS_ONE_ARG | CS_LEADIN | CS_INTERP,
00673          do_python},
00674 #endif
00675         {(char *) "\"", NULL, CA_LOCATION | CF_DARK, SAY_PREFIX,
00676          CS_ONE_ARG | CS_INTERP | CS_LEADIN, do_say},
00677         {(char *) "&", NULL, CA_NO_GUEST | CA_NO_SLAVE | CF_DARK, 0,
00678          CS_TWO_ARG | CS_LEADIN, do_setvattr},
00679         {(char *) "-", NULL, CA_NO_GUEST | CA_NO_SLAVE | CF_DARK, 0,
00680          CS_ONE_ARG | CS_LEADIN, do_postpend},
00681         {(char *) "~", NULL, CA_NO_GUEST | CA_NO_SLAVE | CF_DARK, 0,
00682          CS_ONE_ARG | CS_LEADIN, do_prepend},
00683 #ifdef SQL_SUPPORT
00684         {(char *) "@query", query_sw, CA_WIZARD, 0, CS_TWO_ARG, do_query},
00685 #endif
00686         {(char *) NULL, NULL, 0, 0, 0, NULL}
00687 };
00688 
00689 CMDENT *prefix_cmds[256];
00690 
00691 CMDENT *goto_cmdp;
00692 
00693 void init_cmdtab(void)
00694 {
00695         CMDENT *cp;
00696         ATTR *ap;
00697         char *p, *q;
00698         char *cbuff;
00699 
00700         hashinit(&mudstate.command_htab, 250 * HASH_FACTOR);
00701 
00702         /*
00703          * Load attribute-setting commands 
00704          */
00705 
00706         cbuff = alloc_sbuf("init_cmdtab");
00707         for(ap = attr; ap->name; ap++) {
00708                 if((ap->flags & AF_NOCMD) == 0) {
00709                         p = cbuff;
00710                         *p++ = '@';
00711                         for(q = (char *) ap->name; *q; p++, q++)
00712                                 *p = ToLower(*q);
00713                         *p = '\0';
00714                         cp = (CMDENT *) malloc(sizeof(CMDENT));
00715                         cp->cmdname = (char *) strsave(cbuff);
00716                         cp->perms = CA_NO_GUEST | CA_NO_SLAVE;
00717                         cp->switches = NULL;
00718                         if(ap->flags & (AF_WIZARD | AF_MDARK)) {
00719                                 cp->perms |= CA_WIZARD;
00720                         }
00721                         cp->extra = ap->number;
00722                         cp->callseq = CS_TWO_ARG;
00723                         cp->handler = do_setattr;
00724                         hashadd(cp->cmdname, (int *) cp, &mudstate.command_htab);
00725                 }
00726         }
00727         free_sbuf(cbuff);
00728 
00729         /*
00730          * Load the builtin commands 
00731          */
00732 
00733         for(cp = command_table; cp->cmdname; cp++)
00734                 hashadd(cp->cmdname, (int *) cp, &mudstate.command_htab);
00735 
00736         set_prefix_cmds();
00737 
00738         goto_cmdp = (CMDENT *) hashfind("goto", &mudstate.command_htab);
00739 }
00740 
00741 void set_prefix_cmds()
00742 {
00743         int i;
00744 
00745         /*
00746          * Load the command prefix table.  Note - these commands can never *
00747          * * * * * * be typed in by a user because commands are lowercased *
00748          * before  * * * * the  * hash table is checked. The names are *
00749          * abbreviated to * * * minimise * * name checking time. 
00750          */
00751 
00752         for(i = 0; i < A_USER_START; i++)
00753                 prefix_cmds[i] = NULL;
00754         prefix_cmds['"'] =
00755                 (CMDENT *) hashfind((char *) "\"", &mudstate.command_htab);
00756         prefix_cmds[':'] =
00757                 (CMDENT *) hashfind((char *) ":", &mudstate.command_htab);
00758         prefix_cmds[';'] =
00759                 (CMDENT *) hashfind((char *) ";", &mudstate.command_htab);
00760         prefix_cmds['\\'] =
00761                 (CMDENT *) hashfind((char *) "\\", &mudstate.command_htab);
00762         prefix_cmds['#'] =
00763                 (CMDENT *) hashfind((char *) "#", &mudstate.command_htab);
00764         prefix_cmds['&'] =
00765                 (CMDENT *) hashfind((char *) "&", &mudstate.command_htab);
00766         prefix_cmds['-'] =
00767                 (CMDENT *) hashfind((char *) "-", &mudstate.command_htab);
00768         prefix_cmds['~'] =
00769                 (CMDENT *) hashfind((char *) "~", &mudstate.command_htab);
00770 #ifdef USE_PYTHON
00771         prefix_cmds[','] =
00772                 (CMDENT *) hashfind((char *) ",", &mudstate.command_htab);
00773 #endif
00774 }
00775 
00776 /* 
00777  * Returns 1 if player is in an IC location, 0 if not. Take into account
00778  * the ooc_comsys directive.
00779  */
00780 int In_IC_Loc(dbref player)
00781 {
00782         dbref d = Location(player);
00783         int z = 0;
00784 
00785         while (isPlayer(d)) {
00786                 int od = d;
00787 
00788                 if((d = Location(d)) == od)
00789                         break;
00790                 if(z++ >= 100)
00791                         break;
00792         }
00793         if(mudconf.btech_ooc_comsys && !Gagged(player))
00794                 return 0;
00795         else if(In_Character(d) || Gagged(player))
00796                 return 1;
00797         return 0;
00798 }                                                               /* end In_IC_Loc() */
00799 
00800 /*
00801  * ---------------------------------------------------------------------------
00802  * * check_access: Check if player has access to function.  
00803  */
00804 
00805 int check_access(player, mask)
00806          dbref player;
00807          int mask;
00808 {
00809         int succ, fail;
00810 
00811         if(mask & CA_DISABLED)
00812                 return 0;
00813         if(God(player) || mudstate.initializing)
00814                 return 1;
00815 
00816         succ = fail = 0;
00817         if(mask & CA_GOD)
00818                 fail++;
00819         if(mask & CA_WIZARD) {
00820                 if(Wizard(player))
00821                         succ++;
00822                 else
00823                         fail++;
00824         }
00825         if((succ == 0) && (mask & CA_ADMIN)) {
00826                 if(WizRoy(player))
00827                         succ++;
00828                 else
00829                         fail++;
00830         }
00831         if((succ == 0) && (mask & CA_ANNOUNCE)) {
00832                 if(Announce(player))
00833                         succ++;
00834                 else
00835                         fail++;
00836         }
00837         if((succ == 0) && (mask & CA_IMMORTAL)) {
00838                 if(Immortal(player))
00839                         succ++;
00840                 else
00841                         fail++;
00842         }
00843         if((succ == 0) && (mask & CA_BUILDER)) {
00844                 if(Builder(player))
00845                         succ++;
00846                 else
00847                         fail++;
00848         }
00849         if((succ == 0) && (mask & CA_ROBOT)) {
00850                 if(Robot(player))
00851                         succ++;
00852                 else
00853                         fail++;
00854         }
00855         if(succ > 0)
00856                 fail = 0;
00857         if(fail > 0)
00858                 return 0;
00859 
00860         /*
00861          * Check for forbidden flags. 
00862          */
00863 
00864         if(!Wizard(player) && (((mask & CA_NO_HAVEN) && Player_haven(player))
00865                                                    || ((mask & CA_NO_ROBOT) && Robot(player)) ||
00866                                                    ((mask & CA_NO_SLAVE) && Slave(player)) ||
00867                                                    ((mask & CA_NO_SUSPECT) && Suspect(player)) ||
00868                                                    ((mask & CA_NO_GUEST) && Guest(player)) ||
00869                                                    (!mudconf.btech_ooc_comsys && (mask & CA_NO_IC)
00870                                                         && In_IC_Loc(player)) || ((mask & CA_NO_IC)
00871                                                                                                           && Gagged(player))
00872            ))
00873                 return 0;
00874         return 1;
00875 }
00876 
00877 /*
00878  * ---------------------------------------------------------------------------
00879  * * process_cmdent: Perform indicated command with passed args.
00880  */
00881 void process_cmdent(CMDENT * cmdp, char *switchp, dbref player, dbref cause,
00882                                         int interactive, char *arg, char *unp_command,
00883                                         char *cargs[], int ncargs)
00884 {
00885         char *buf1, *buf2, tchar, *bp, *str, *buff, *s, *j, *new;
00886         char *args[MAX_ARG];
00887         int nargs, i, fail, interp, key, xkey, aflags;
00888         int length;
00889         int hasswitch = 0;
00890         dbref aowner;
00891         char *aargs[10];
00892         ADDENT *add;
00893 
00894 #define Protect(x) (cmdp->perms & x)
00895 
00896         /*
00897          * Perform object type checks. 
00898          */
00899 
00900         fail = 0;
00901         if(Protect(CA_LOCATION) && !Has_location(player))
00902                 fail++;
00903         if(Protect(CA_CONTENTS) && !Has_contents(player))
00904                 fail++;
00905         if(Protect(CA_PLAYER) && (Typeof(player) != TYPE_PLAYER))
00906                 fail++;
00907         if(fail > 0) {
00908                 notify(player, "Command incompatible with invoker type.");
00909                 return;
00910         }
00911         /*
00912          * Check global flags 
00913          */
00914 
00915         if((!Builder(player)) && Protect(CA_GBL_BUILD) &&
00916            !(mudconf.control_flags & CF_BUILD)) {
00917                 notify(player, "Sorry, building is not allowed now.");
00918                 return;
00919         }
00920         if(Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP)) {
00921                 notify(player, "Sorry, queueing and triggering are not allowed now.");
00922                 return;
00923         }
00924         key = cmdp->extra & ~SW_MULTIPLE;
00925         if(key & SW_GOT_UNIQUE) {
00926                 i = 1;
00927                 key = key & ~SW_GOT_UNIQUE;
00928         } else {
00929                 i = 0;
00930         }
00931 
00932         /*
00933          * Check if we have permission to execute the command 
00934          */
00935 
00936         /* Asumption: base command permission required for all sub-commands */
00937         if(!check_access(player, cmdp->perms)) {
00938                 notify(player, "Permission denied.");
00939                 return;
00940         }
00941 
00942         /*
00943          * Check command switches.  Note that there may be more than one, * * 
00944          * 
00945          * *  * *  * *  * * and that we OR all of them together along with
00946          * the * extra * value * * * from * the command table to produce the
00947          * key * value in * the handler * *  * call. 
00948          */
00949 
00950         if(switchp && cmdp->switches) {
00951                 do {
00952                         buf1 = (char *) index(switchp, '/');
00953                         if(buf1)
00954                                 *buf1++ = '\0';
00955                         xkey = search_nametab(player, cmdp->switches, switchp);
00956                         if(xkey == -1) {
00957                                 notify_printf(player,
00958                                                           "Unrecognized switch '%s' for command '%s'.",
00959                                                           switchp, cmdp->cmdname);
00960                                 return;
00961                         } else if(xkey == -2) {
00962                                 notify(player, "Permission denied.");
00963                                 return;
00964                         } else if(!(xkey & SW_MULTIPLE)) {
00965                                 if(i == 1) {
00966                                         notify(player, "Illegal combination of switches.");
00967                                         return;
00968                                 }
00969                                 i = 1;
00970                         } else {
00971                                 xkey &= ~SW_MULTIPLE;
00972                         }
00973                         key |= xkey;
00974                         switchp = buf1;
00975                         hasswitch = 1;
00976                 } while (buf1);
00977         } else if(switchp && !(cmdp->callseq & CS_ADDED)) {
00978                 notify_printf(player, "Command %s does not take switches.",
00979                                           cmdp->cmdname);
00980                 return;
00981         }
00982         /*
00983          * We are allowed to run the command.  Now, call the handler using
00984          * the appropriate calling sequence and arguments. 
00985          */
00986 
00987         if((cmdp->callseq & CS_INTERP) || !(interactive ||
00988                                                                                 (cmdp->callseq & CS_NOINTERP)))
00989                 interp = EV_EVAL | EV_STRIP;
00990         else if(cmdp->callseq & CS_STRIP)
00991                 interp = EV_STRIP;
00992         else if(cmdp->callseq & CS_STRIP_AROUND)
00993                 interp = EV_STRIP_AROUND;
00994         else
00995                 interp = 0;
00996 
00997         switch (cmdp->callseq & CS_NARG_MASK) {
00998         case CS_NO_ARGS:                        /*
00999                                                                  * <cmd>   (no args) 
01000                                                                  */
01001                 (*(cmdp->handler)) (player, cause, key);
01002                 break;
01003         case CS_ONE_ARG:                        /*
01004                                                                  * <cmd> <arg> 
01005                                                                  */
01006 
01007                 /*
01008                  * If an unparsed command, just give it to the handler 
01009                  */
01010 
01011                 if(cmdp->callseq & CS_UNPARSE) {
01012                         (*(cmdp->handler)) (player, unp_command);
01013                         break;
01014                 }
01015                 /* Interpret if necessary, but not twice for CS_ADDED */
01016 
01017                 if((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED)) {
01018                         buf1 = bp = alloc_lbuf("process_cmdent");
01019                         str = arg;
01020                         exec(buf1, &bp, 0, player, cause, interp | EV_FCHECK | EV_TOP,
01021                                  &str, cargs, ncargs);
01022                         length = strnlen(buf1, LBUF_SIZE-1);
01023                         buf1[length] = '\0';
01024                 } else
01025                         buf1 = parse_to(&arg, '\0', interp | EV_TOP);
01026 
01027                 /*
01028                  * Call the correct handler 
01029                  */
01030 
01031                 if(cmdp->callseq & CS_CMDARG) {
01032                         (*(cmdp->handler)) (player, cause, key, buf1, cargs, ncargs);
01033                 } else {
01034                         if(cmdp->callseq & CS_ADDED) {
01035                                 for(add = (ADDENT *) cmdp->handler; add != NULL;
01036                                         add = add->next) {
01037                                         buff = atr_get(add->thing, add->atr, &aowner, &aflags);
01038                                         /* Skip the '$' character, and the next */
01039                                         for(s = buff + 2; *s && (*s != ':'); s++);
01040                                         if(!*s)
01041                                                 break;
01042                                         *s++ = '\0';
01043                                         if(!(cmdp->callseq & CS_LEADIN))
01044                                                 for(j = unp_command; *j && (*j != ' '); j++);
01045                                         else
01046                                                 for(j = unp_command; *j; j++);
01047 
01048                                         new = alloc_lbuf("process_cmdent.soft");
01049                                         bp = new;
01050                                         if(!*j) {
01051                                                 /* No args */
01052                                                 if(!(cmdp->callseq & CS_LEADIN)) {
01053                                                         safe_str(cmdp->cmdname, new, &bp);
01054                                                 } else {
01055                                                         safe_str(unp_command, new, &bp);
01056                                                 }
01057                                                 if(switchp) {
01058                                                         safe_chr('/', new, &bp);
01059                                                         safe_str(switchp, new, &bp);
01060                                                 }
01061                                                 *bp = '\0';
01062                                         } else {
01063                                                 j++;
01064                                                 safe_str(cmdp->cmdname, new, &bp);
01065                                                 if(switchp) {
01066                                                         safe_chr('/', new, &bp);
01067                                                         safe_str(switchp, new, &bp);
01068                                                 }
01069                                                 safe_chr(' ', new, &bp);
01070                                                 safe_str(j, new, &bp);
01071                                                 *bp = '\0';
01072                                         }
01073 
01074                                         if(wild(buff + 1, new, aargs, 10)) {
01075                                                 wait_que(add->thing, player, 0, NOTHING, 0, s,
01076                                                                  aargs, 10, mudstate.global_regs);
01077                                                 for(i = 0; i < 10; i++) {
01078                                                         if(aargs[i])
01079                                                                 free_lbuf(aargs[i]);
01080                                                 }
01081                                         }
01082                                         free_lbuf(new);
01083                                         free_lbuf(buff);
01084                                 }
01085                         } else
01086                                 (*(cmdp->handler)) (player, cause, key, buf1);
01087                 }
01088 
01089                 /*
01090                  * Free the buffer if one was allocated 
01091                  */
01092 
01093                 if(interp & EV_EVAL)
01094                         free_lbuf(buf1);
01095 
01096                 break;
01097         case CS_TWO_ARG:                        /*
01098                                                                  * <cmd> <arg1> = <arg2> 
01099                                                                  */
01100 
01101                 /*
01102                  * Interpret ARG1 
01103                  */
01104 
01105                 buf2 = parse_to(&arg, '=', EV_STRIP_TS);
01106 
01107                 /*
01108                  * Handle when no '=' was specified 
01109                  */
01110 
01111                 if(!arg || (arg && !*arg)) {
01112                         arg = &tchar;
01113                         *arg = '\0';
01114                 }
01115                 buf1 = bp = alloc_lbuf("process_cmdent.2");
01116                 str = buf2;
01117                 exec(buf1, &bp, 0, player, cause,
01118                          EV_STRIP | EV_FCHECK | EV_EVAL | EV_TOP, &str, cargs, ncargs);
01119                 length = strnlen(buf1, LBUF_SIZE-1);
01120                 buf1[length] ='\0';
01121 
01122                 if(cmdp->callseq & CS_ARGV) {
01123 
01124                         /*
01125                          * Arg2 is ARGV style.  Go get the args 
01126                          */
01127 
01128                         parse_arglist(player, cause, arg, '\0',
01129                                                   interp | EV_STRIP_LS | EV_STRIP_TS, args, MAX_ARG,
01130                                                   cargs, ncargs);
01131                         for(nargs = 0; (nargs < MAX_ARG) && args[nargs]; nargs++);
01132 
01133                         /*
01134                          * Call the correct command handler 
01135                          */
01136 
01137                         if(cmdp->callseq & CS_CMDARG) {
01138                                 (*(cmdp->handler)) (player, cause, key, buf1, args, nargs,
01139                                                                         cargs, ncargs);
01140                         } else {
01141                                 (*(cmdp->handler)) (player, cause, key, buf1, args, nargs);
01142                         }
01143 
01144                         /*
01145                          * Free the argument buffers 
01146                          */
01147 
01148                         for(i = 0; i <= nargs; i++)
01149                                 if(args[i])
01150                                         free_lbuf(args[i]);
01151 
01152                 } else {
01153 
01154                         /*
01155                          * Arg2 is normal style.  Interpret if needed 
01156                          */
01157 
01158                         if(interp & EV_EVAL) {
01159                                 buf2 = bp = alloc_lbuf("process_cmdent.3");
01160                                 str = arg;
01161                                 exec(buf2, &bp, 0, player, cause,
01162                                          interp | EV_FCHECK | EV_TOP, &str, cargs, ncargs);
01163                                 length = strnlen(buf2, LBUF_SIZE-1);
01164                                 buf2[length] = '\0';
01165                         } else if(cmdp->callseq & CS_UNPARSE) {
01166                                 buf2 = parse_to(&arg, '\0', interp | EV_TOP | EV_NO_COMPRESS);
01167                         } else {
01168                                 buf2 =
01169                                         parse_to(&arg, '\0',
01170                                                          interp | EV_STRIP_LS | EV_STRIP_TS | EV_TOP);
01171                         }
01172 
01173                         /*
01174                          * Call the correct command handler 
01175                          */
01176 
01177                         if(cmdp->callseq & CS_CMDARG) {
01178                                 (*(cmdp->handler)) (player, cause, key, buf1, buf2, cargs,
01179                                                                         ncargs);
01180                         } else {
01181                                 (*(cmdp->handler)) (player, cause, key, buf1, buf2);
01182                         }
01183 
01184                         /*
01185                          * Free the buffer, if needed 
01186                          */
01187 
01188                         if(interp & EV_EVAL)
01189                                 free_lbuf(buf2);
01190                 }
01191 
01192                 /*
01193                  * Free the buffer obtained by evaluating Arg1 
01194                  */
01195 
01196                 free_lbuf(buf1);
01197                 break;
01198         }
01199         return;
01200 }
01201 
01202 /*
01203  * ---------------------------------------------------------------------------
01204  * * process_command: Execute a command.
01205  */
01206 
01207 void process_command(dbref player, dbref cause, int interactive,
01208                                          char *command, char *args[], int nargs)
01209 {
01210         char *p, *q, *arg, *lcbuf, *slashp, *cmdsave, *bp, *str;
01211         int succ, aflags, i;
01212         dbref exit, aowner;
01213         CMDENT *cmdp;
01214         char *macroout;
01215         int macerr;
01216         int eins = 1, null = 0;
01217         int length;
01218 
01219         /*
01220          * Robustify player 
01221          */
01222 
01223         cmdsave = mudstate.debug_cmd;
01224         mudstate.debug_cmd = (char *) "< process_command >";
01225 
01226         if(!command) {
01227                 abort();
01228         }
01229 
01230         if(!Good_obj(player)) {
01231         log_error(LOG_BUGS, "CMD", "PLYR", "Bad player in process_command: %d", player);
01232                 mudstate.debug_cmd = cmdsave;
01233                 goto exit;
01234         }
01235 
01236         //    if(isPlayer(player)) choke_player(player);
01237 
01238         /*
01239          * Make sure player isn't going or halted 
01240          */
01241 
01242         if(Going(player) || (Halted(player) &&
01243                                                  !((Typeof(player) == TYPE_PLAYER) && interactive))) {
01244                 notify_printf(Owner(player),
01245                                           "Attempt to execute command by halted object #%d",
01246                                           player);
01247                 mudstate.debug_cmd = cmdsave;
01248                 goto exit;
01249         }
01250 
01251         if(Suspect(player)) {
01252                 STARTLOG(LOG_SUSPECTCMDS | LOG_ALLCOMMANDS, "CMD", "SUS") {
01253                         log_name_and_loc(player);
01254                         lcbuf = alloc_lbuf("process_command.LOG.allcmds");
01255                         sprintf(lcbuf, " entered: '%s'", command);
01256                         log_text(lcbuf);
01257                         free_lbuf(lcbuf);
01258                         ENDLOG;
01259                 }
01260                 send_channel("SuspectsLog", "%s (#%d) (in #%d) entered: %s", Name(player),
01261                                                          player, Location(player), command);
01262         } else {
01263                 STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL") {
01264                         log_name_and_loc(player);
01265                         lcbuf = alloc_lbuf("process_command.LOG.allcmds");
01266                         sprintf(lcbuf, " entered: '%s'", command);
01267                         log_text(lcbuf);
01268                         free_lbuf(lcbuf);
01269                         ENDLOG;
01270                 }
01271         }
01272 
01273         /*
01274          * Reset recursion limits 
01275          */
01276         mudstate.func_nest_lev = 0;
01277         mudstate.func_invk_ctr = 0;
01278         mudstate.ntfy_nest_lev = 0;
01279         mudstate.lock_nest_lev = 0;
01280 
01281         if(Verbose(player))
01282                 notify_printf(Owner(player), "%s] %s", Name(player), command);
01283 
01284         /*
01285          * Eat leading whitespace, and space-compress if configured 
01286          */
01287 
01288         while (*command && isspace(*command))
01289                 command++;
01290         mudstate.debug_cmd = command;
01291 
01292         /*
01293          * Can we fix the @npemit thing? 
01294          */
01295         if(mudconf.space_compress && strncmp(command, "@npemit", 7)) {
01296                 p = q = command;
01297                 while (*p) {
01298                         while (*p && !isspace(*p))
01299                                 *q++ = *p++;
01300                         while (*p && isspace(*p))
01301                                 p++;
01302                         if(*p)
01303                                 *q++ = ' ';
01304                 }
01305                 *q = '\0';
01306         }
01307 
01308         /*
01309          * Now comes the fun stuff.  First check for single-letter leadins.
01310          * We check these before checking HOME because
01311          * they are among the most frequently executed commands, 
01312          * and they can never be the HOME command. 
01313          */
01314 
01315         i = command[0] & 0xff;
01316         if((prefix_cmds[i] != NULL) && command[0]) {
01317                 process_cmdent(prefix_cmds[i], NULL, player, cause,
01318                                            interactive, command, command, args, nargs);
01319                 mudstate.debug_cmd = cmdsave;
01320                 goto exit;
01321         }
01322         if(mudconf.have_macros && (command[0] == '.') && interactive) {
01323                 macerr = do_macro(player, command, &macroout);
01324                 if(!macerr)
01325                         goto exit;
01326                 if(macerr == 1) {
01327                         StringCopy(command, macroout);
01328                         free_lbuf(macroout);
01329                 }
01330         } else
01331                 macerr = 0;
01332         if(mudconf.have_comsys && !Slave(player))
01333                 if(!do_comsystem(player, command))
01334                         goto exit;
01335 
01336         /* Handle mecha stuff.. */
01337         if(mudconf.have_specials && !Slave(player))
01338                 if(HandledCommand(player, Location(player), command))
01339                         goto exit;
01340         /*
01341          * Check for the HOME command 
01342          */
01343 
01344         if(string_compare(command, "home") == 0) {
01345                 if(((Fixed(player)) || (Fixed(Owner(player)))) && !(WizRoy(player))) {
01346                         notify(player, mudconf.fixed_home_msg);
01347                         goto exit;
01348                 }
01349                 do_move(player, cause, 0, "home");
01350                 mudstate.debug_cmd = cmdsave;
01351                 goto exit;
01352         }
01353 
01354         /*
01355          * Only check for exits if we may use the goto command 
01356          */
01357         if(check_access(player, goto_cmdp->perms)) {
01358                 /*
01359                  * Check for an exit name 
01360                  */
01361                 init_match_check_keys(player, command, TYPE_EXIT);
01362                 match_exit_with_parents();
01363                 exit = last_match_result();
01364                 if(exit != NOTHING) {
01365                         move_exit(player, exit, 0, "You can't go that way.", 0);
01366                         mudstate.debug_cmd = cmdsave;
01367                         goto exit;
01368                 }
01369                 /*
01370                  * Check for an exit in the master room 
01371                  */
01372 
01373                 init_match_check_keys(player, command, TYPE_EXIT);
01374                 match_master_exit();
01375                 exit = last_match_result();
01376                 if(exit != NOTHING) {
01377                         move_exit(player, exit, 1, NULL, 0);
01378                         mudstate.debug_cmd = cmdsave;
01379                         goto exit;
01380                 }
01381         }
01382         /*
01383          * Set up a lowercase command and an arg pointer for the hashed
01384          * command check.  Since some types of argument
01385          * processing destroy the arguments, make a copy so that
01386          * we keep the original command line intact.  Store the
01387          * edible copy in lcbuf after the lowercased command. 
01388          */
01389         /*
01390          * Removed copy of the rest of the command, since it's ok do allow
01391          * it to be trashed.  -dcm 
01392          */
01393 
01394         lcbuf = alloc_lbuf("process_commands.LCbuf");
01395         for(p = command, q = lcbuf; *p && !isspace(*p); p++, q++)
01396                 *q = ToLower(*p);               /*
01397                                                                  * Make lowercase command 
01398                                                                  */
01399         *q++ = '\0';                            /*
01400                                                                  * Terminate command 
01401                                                                  */
01402         while (*p && isspace(*p))
01403                 p++;                                    /*
01404                                                                  * Skip spaces before arg 
01405                                                                  */
01406         arg = p;                                        /*
01407                                                                  * Remember where arg starts 
01408                                                                  */
01409 
01410         /*
01411          * Strip off any command switches and save them 
01412          */
01413 
01414         slashp = (char *) index(lcbuf, '/');
01415         if(slashp)
01416                 *slashp++ = '\0';
01417 
01418         /*
01419          * Check for a builtin command (or an alias of a builtin command) 
01420          */
01421 
01422         cmdp = (CMDENT *) hashfind(lcbuf, &mudstate.command_htab);
01423         if(cmdp != NULL) {
01424                 if((cmdp->callseq & CS_NO_MACRO) && macerr == 1)
01425                         notify(player,
01426                                    "This command is unavailable as macro. Please use an attribute instead.");
01427                 else
01428                         process_cmdent(cmdp, slashp, player, cause, interactive, arg,
01429                                                    command, args, nargs);
01430                 free_lbuf(lcbuf);
01431                 mudstate.debug_cmd = cmdsave;
01432                 goto exit;
01433         }
01434         /*
01435          * Check for enter and leave aliases, user-defined commands on the *
01436          * * * * * * player, other objects where the player is, on objects in
01437          * * the  * *  * *  * player's inventory, and on the room that holds * 
01438          * the * player. * We * *  * evaluate the command line here to allow * 
01439          * chains  * of * $-commands to * * * work. 
01440          */
01441 
01442         bp = lcbuf;
01443         str = command;
01444         exec(lcbuf, &bp, 0, player, cause,
01445                  EV_EVAL | EV_FCHECK | EV_STRIP | EV_TOP, &str, args, nargs);
01446         length = strnlen(lcbuf, LBUF_SIZE-1);
01447         lcbuf[length] = '\0';
01448         succ = 0;
01449 
01450         /*
01451          * Idea for enter/leave aliases from R'nice@TinyTIM 
01452          */
01453 
01454         if(Has_location(player) && Good_obj(Location(player))) {
01455 
01456                 /* Check for a leave alias */
01457                 p = atr_pget(Location(player), A_LALIAS, &aowner, &aflags);
01458                 if(p && *p) {
01459                         if(matches_exit_from_list(lcbuf, p)) {
01460                                 free_lbuf(lcbuf);
01461                                 free_lbuf(p);
01462                                 do_leave(player, player, 0);
01463                                 goto exit;
01464                         }
01465                 }
01466                 free_lbuf(p);
01467 
01468                 /*
01469                  * Check for enter aliases 
01470                  */
01471 
01472                 DOLIST(exit, Contents(Location(player))) {
01473                         p = atr_pget(exit, A_EALIAS, &aowner, &aflags);
01474                         if(p && *p) {
01475                                 if(matches_exit_from_list(lcbuf, p)) {
01476                                         free_lbuf(lcbuf);
01477                                         free_lbuf(p);
01478                                         do_enter_internal(player, exit, 0);
01479                                         goto exit;
01480                                 }
01481                         }
01482                         free_lbuf(p);
01483                 }
01484         }
01485         /*
01486          * Check for $-command matches on me 
01487          */
01488 
01489         if(mudconf.match_mine && (!(No_Command(player)))) {
01490                 if(((Typeof(player) != TYPE_PLAYER) || mudconf.match_mine_pl) &&
01491                    (atr_match(player, player, AMATCH_CMD, lcbuf, 1) > 0)) {
01492                         succ++;
01493                 }
01494         }
01495         /*
01496          * Check for $-command matches on nearby things and on my room 
01497          */
01498 
01499         if(Has_location(player)) {
01500                 succ +=
01501                         list_check(Contents(Location(player)), player, AMATCH_CMD,
01502                                            lcbuf, 1);
01503 
01504                 if(!(No_Command(Location(player))))
01505                         if(atr_match(Location(player), player, AMATCH_CMD, lcbuf, 1) > 0) {
01506                                 succ++;
01507                         }
01508         }
01509 
01510         /*
01511          * Check for $-command matches in my inventory 
01512          */
01513 
01514         if(Has_contents(player))
01515                 succ += list_check(Contents(player), player, AMATCH_CMD, lcbuf, 1);
01516 
01517         /*
01518          * now do check on zones 
01519          */
01520 
01521         if((!succ) && mudconf.have_zones && (Zone(Location(player)) != NOTHING)) {
01522                 if(Typeof(Zone(Location(player))) == TYPE_ROOM) {
01523 
01524                         /*
01525                          * zone of player's location is a parent room 
01526                          */
01527                         if(Location(player) != Zone(player)) {
01528 
01529                                 /*
01530                                  * check parent room exits 
01531                                  */
01532                                 init_match_check_keys(player, command, TYPE_EXIT);
01533                                 match_zone_exit();
01534                                 exit = last_match_result();
01535                                 if(exit != NOTHING) {
01536                                         move_exit(player, exit, 1, NULL, 0);
01537                                         mudstate.debug_cmd = cmdsave;
01538                                         goto exit;
01539                                 }
01540                                 succ += list_check(Contents(Zone(Location(player))), player,
01541                                                                    AMATCH_CMD, lcbuf, 1);
01542                         }                                       /*
01543                                                                  * * end of parent room checks  
01544                                                                  */
01545                 } else
01546                         /*
01547                          * try matching commands on area zone object 
01548                          */
01549 
01550                 if((!succ) && mudconf.have_zones &&
01551                            (Zone(Location(player)) != NOTHING) &&
01552                            (!(No_Command(Zone(Location(player))))))
01553                         succ += atr_match(Zone(Location(player)), player, AMATCH_CMD,
01554                                                           lcbuf, 1);
01555         }
01556         /*
01557          * * end of matching on zone of player's * *
01558          * * * * * location  
01559          */
01560         /*
01561          * if nothing matched with parent room/zone object, try matching
01562          * zone commands on the player's personal zone  
01563          */
01564         if((!succ) && mudconf.have_zones && (Zone(player) != NOTHING) &&
01565            (!(No_Command(Zone(player)))) &&
01566            (Zone(Location(player)) != Zone(player))) {
01567                 succ += atr_match(Zone(player), player, AMATCH_CMD, lcbuf, 1);
01568 
01569         }
01570         /*
01571          * If we didn't find anything, try in the master room 
01572          */
01573 
01574         if(!succ) {
01575                 if(Good_obj(mudconf.master_room) && Has_contents(mudconf.master_room)) {
01576                         succ +=
01577                                 list_check(Contents(mudconf.master_room), player,
01578                                                    AMATCH_CMD, lcbuf, 0);
01579                         if(!(No_Command(mudconf.master_room)))
01580                                 if(atr_match(mudconf.master_room, player, AMATCH_CMD,
01581                                                          lcbuf, 0) > 0) {
01582                                         succ++;
01583                                 }
01584                 }
01585         }
01586         free_lbuf(lcbuf);
01587 
01588         /*
01589          * If we still didn't find anything, tell how to get help. 
01590          */
01591 
01592         if(!succ) {
01593                 notify(player, "Huh?  (Type \"help\" for help.)");
01594                 STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD") {
01595                         log_name_and_loc(player);
01596                         lcbuf = alloc_lbuf("process_commands.LOG.badcmd");
01597                         snprintf(lcbuf, LBUF_SIZE, " entered: '%s'", command);
01598                         log_text(lcbuf);
01599                         free_lbuf(lcbuf);
01600                         ENDLOG;
01601                 }
01602         }
01603         mudstate.debug_cmd = cmdsave;
01604 
01605   exit:
01606         //    if(isPlayer(player)) release_player(player);
01607         return;
01608 }
01609 
01610 /*
01611  * ---------------------------------------------------------------------------
01612  * * list_cmdtable: List internal commands.
01613  */
01614 
01615 static void list_cmdtable(dbref player)
01616 {
01617         CMDENT *cmdp;
01618         char *buf, *bp, *cp;
01619 
01620         buf = alloc_lbuf("list_cmdtable");
01621         bp = buf;
01622         for(cp = (char *) "Commands:"; *cp; cp++)
01623                 *bp++ = *cp;
01624         for(cmdp = command_table; cmdp->cmdname; cmdp++) {
01625                 if(check_access(player, cmdp->perms)) {
01626                         if(!(cmdp->perms & CF_DARK)) {
01627                                 *bp++ = ' ';
01628                                 for(cp = cmdp->cmdname; *cp; cp++)
01629                                         *bp++ = *cp;
01630                         }
01631                 }
01632         }
01633         *bp = '\0';
01634 
01635         /*
01636          * Players get the list of logged-out cmds too 
01637          */
01638 
01639         if(Typeof(player) == TYPE_PLAYER)
01640                 display_nametab(player, logout_cmdtable, buf, 1);
01641         else
01642                 notify(player, buf);
01643         free_lbuf(buf);
01644 }
01645 
01646 /*
01647  * ---------------------------------------------------------------------------
01648  * * list_attrtable: List available attributes.
01649  */
01650 
01651 static void list_attrtable(dbref player)
01652 {
01653         ATTR *ap;
01654         char *buf, *bp, *cp;
01655 
01656         buf = alloc_lbuf("list_attrtable");
01657         bp = buf;
01658         for(cp = (char *) "Attributes:"; *cp; cp++)
01659                 *bp++ = *cp;
01660         for(ap = attr; ap->name; ap++) {
01661                 if(See_attr(player, player, ap, player, 0)) {
01662                         *bp++ = ' ';
01663                         for(cp = (char *) (ap->name); *cp; cp++)
01664                                 *bp++ = *cp;
01665                 }
01666         }
01667         *bp = '\0';
01668         raw_notify(player, buf);
01669         free_lbuf(buf);
01670 }
01671 
01672 #if 0                                                   /* Currently unused function */
01673 
01674 /*
01675  * ---------------------------------------------------------------------------
01676  * * list_ntab_flags: List flags field of an ntab.
01677  */
01678 
01679 static void list_ntab_flags(player, ntab, flaglist)
01680          dbref player;
01681          NAMETAB *ntab, *flaglist;
01682 {
01683         char *buff;
01684         NAMETAB *np;
01685 
01686         buff = alloc_sbuf("list_attraccess");
01687         for(np = ntab; np->name; np++) {
01688                 if(check_access(player, np->perm)) {
01689                         sprintf(buff, "%s:", np->name);
01690                         listset_nametab(player, flaglist, np->flag, buff, 1);
01691                 }
01692         }
01693         free_sbuf(buff);
01694 }
01695 
01696 #endif
01697 
01698 /*
01699  * ---------------------------------------------------------------------------
01700  * * list_cmdaccess: List access commands.
01701  */
01702 
01703 NAMETAB access_nametab[] = {
01704         {(char *) "god", 2, CA_GOD, CA_GOD},
01705         {(char *) "wizard", 3, CA_WIZARD, CA_WIZARD},
01706         {(char *) "builder", 6, CA_WIZARD, CA_BUILDER},
01707         {(char *) "immortal", 3, CA_WIZARD, CA_IMMORTAL},
01708         {(char *) "robot", 2, CA_WIZARD, CA_ROBOT},
01709         {(char *) "no_haven", 4, CA_PUBLIC, CA_NO_HAVEN},
01710         {(char *) "no_robot", 4, CA_WIZARD, CA_NO_ROBOT},
01711         {(char *) "no_slave", 5, CA_PUBLIC, CA_NO_SLAVE},
01712         {(char *) "no_suspect", 5, CA_WIZARD, CA_NO_SUSPECT},
01713         {(char *) "no_guest", 5, CA_WIZARD, CA_NO_GUEST},
01714         {(char *) "global_build", 8, CA_PUBLIC, CA_GBL_BUILD},
01715         {(char *) "global_interp", 8, CA_PUBLIC, CA_GBL_INTERP},
01716         {(char *) "disabled", 4, CA_GOD, CA_DISABLED},
01717         {(char *) "need_location", 6, CA_PUBLIC, CA_LOCATION},
01718         {(char *) "need_contents", 6, CA_PUBLIC, CA_CONTENTS},
01719         {(char *) "need_player", 6, CA_PUBLIC, CA_PLAYER},
01720         {(char *) "dark", 4, CA_GOD, CF_DARK},
01721         {NULL, 0, 0, 0}
01722 };
01723 
01724 static void list_cmdaccess(dbref player)
01725 {
01726         char *buff, *p, *q;
01727         CMDENT *cmdp;
01728         ATTR *ap;
01729 
01730         buff = alloc_sbuf("list_cmdaccess");
01731         for(cmdp = command_table; cmdp->cmdname; cmdp++) {
01732                 if(check_access(player, cmdp->perms)) {
01733                         if(!(cmdp->perms & CF_DARK)) {
01734                                 sprintf(buff, "%s:", cmdp->cmdname);
01735                                 listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
01736                         }
01737                 }
01738         }
01739         for(ap = attr; ap->name; ap++) {
01740                 p = buff;
01741                 *p++ = '@';
01742                 for(q = (char *) ap->name; *q; p++, q++)
01743                         *p = ToLower(*q);
01744                 if(ap->flags & AF_NOCMD)
01745                         continue;
01746                 *p = '\0';
01747                 cmdp = (CMDENT *) hashfind(buff, &mudstate.command_htab);
01748                 if(cmdp == NULL)
01749                         continue;
01750                 if(!check_access(player, cmdp->perms))
01751                         continue;
01752                 if(!(cmdp->perms & CF_DARK)) {
01753                         sprintf(buff, "%s:", cmdp->cmdname);
01754                         listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
01755                 }
01756         }
01757         free_sbuf(buff);
01758 }
01759 
01760 /*
01761  * ---------------------------------------------------------------------------
01762  * * list_cmdswitches: List switches for commands.
01763  */
01764 
01765 static void list_cmdswitches(dbref player)
01766 {
01767         char *buff;
01768         CMDENT *cmdp;
01769 
01770         buff = alloc_sbuf("list_cmdswitches");
01771         for(cmdp = command_table; cmdp->cmdname; cmdp++) {
01772                 if(cmdp->switches) {
01773                         if(check_access(player, cmdp->perms)) {
01774                                 if(!(cmdp->perms & CF_DARK)) {
01775                                         sprintf(buff, "%s:", cmdp->cmdname);
01776                                         display_nametab(player, cmdp->switches, buff, 0);
01777                                 }
01778                         }
01779                 }
01780         }
01781         free_sbuf(buff);
01782 }
01783 /* *INDENT-OFF* */
01784 
01785 /* ---------------------------------------------------------------------------
01786  * list_attraccess: List access to attributes.
01787  */
01788 
01789 NAMETAB attraccess_nametab[] = {
01790     {(char *)"dark",            2,      CA_WIZARD,      AF_DARK},
01791     {(char *)"deleted",         2,      CA_WIZARD,      AF_DELETED},
01792     {(char *)"god",                     1,      CA_PUBLIC,      AF_GOD},
01793     {(char *)"hidden",          1,      CA_WIZARD,      AF_MDARK},
01794     {(char *)"ignore",          2,      CA_WIZARD,      AF_NOCMD},
01795     {(char *)"internal",                2,      CA_WIZARD,      AF_INTERNAL},
01796     {(char *)"is_lock",         4,      CA_PUBLIC,      AF_IS_LOCK},
01797     {(char *)"locked",          1,      CA_PUBLIC,      AF_LOCK},
01798     {(char *)"no_command",              4,      CA_PUBLIC,      AF_NOPROG},
01799     {(char *)"no_inherit",              4,      CA_PUBLIC,      AF_PRIVATE},
01800     {(char *)"private",         1,      CA_PUBLIC,      AF_ODARK},
01801     {(char *)"regexp",              1,      CA_PUBLIC,      AF_REGEXP},
01802     {(char *)"visual",          1,      CA_PUBLIC,      AF_VISUAL},
01803     {(char *)"wizard",          1,      CA_PUBLIC,      AF_WIZARD},
01804     { NULL,                             0,      0,              0}};
01805 
01806 NAMETAB indiv_attraccess_nametab[] = {
01807     {(char *)"hidden",          1,      CA_WIZARD,      AF_MDARK},
01808     {(char *)"wizard",          1,      CA_WIZARD,      AF_WIZARD},
01809     {(char *)"no_command",              4,      CA_PUBLIC,      AF_NOPROG},
01810     {(char *)"no_inherit",              4,      CA_PUBLIC,      AF_PRIVATE},
01811     {(char *)"visual",          1,      CA_PUBLIC,      AF_VISUAL},
01812     {(char *)"regexp",              1,      CA_PUBLIC,      AF_REGEXP},
01813     { NULL,                             0,      0,              0}};
01814 
01815 /* *INDENT-ON* */
01816 
01817 static void list_attraccess(player)
01818          dbref player;
01819 {
01820         char *buff;
01821         ATTR *ap;
01822 
01823         buff = alloc_sbuf("list_attraccess");
01824         for(ap = attr; ap->name; ap++) {
01825                 if(Read_attr(player, player, ap, player, 0)) {
01826                         sprintf(buff, "%s:", ap->name);
01827                         listset_nametab(player, attraccess_nametab, ap->flags, buff, 1);
01828                 }
01829         }
01830         free_sbuf(buff);
01831 }
01832 
01833 /*
01834  * ---------------------------------------------------------------------------
01835  * * cf_access: Change command or switch permissions.
01836  */
01837 
01838 extern void cf_log_notfound(dbref, char *, const char *, char *);
01839 
01840 int cf_access(int *vp, char *str, long extra, dbref player, char *cmd)
01841 {
01842         CMDENT *cmdp;
01843         char *ap;
01844         int set_switch;
01845 
01846         for(ap = str; *ap && !isspace(*ap) && (*ap != '/'); ap++);
01847         if(*ap == '/') {
01848                 set_switch = 1;
01849                 *ap++ = '\0';
01850         } else {
01851                 set_switch = 0;
01852                 if(*ap)
01853                         *ap++ = '\0';
01854                 while (*ap && isspace(*ap))
01855                         ap++;
01856         }
01857 
01858         cmdp = (CMDENT *) hashfind(str, &mudstate.command_htab);
01859         if(cmdp != NULL) {
01860                 if(set_switch)
01861                         return cf_ntab_access((int *) cmdp->switches, ap, extra,
01862                                                                   player, cmd);
01863                 else
01864                         return cf_modify_bits(&(cmdp->perms), ap, extra, player, cmd);
01865         } else {
01866                 cf_log_notfound(player, cmd, "Command", str);
01867                 return -1;
01868         }
01869 }
01870 
01871 /*
01872  * ---------------------------------------------------------------------------
01873  * * cf_acmd_access: Chante command permissions for all attr-setting cmds.
01874  */
01875 
01876 int cf_acmd_access(int *vp, char *str, long extra, dbref player, char *cmd)
01877 {
01878         CMDENT *cmdp;
01879         ATTR *ap;
01880         char *buff, *p, *q;
01881         int failure, save;
01882 
01883         buff = alloc_sbuf("cf_acmd_access");
01884         for(ap = attr; ap->name; ap++) {
01885                 p = buff;
01886                 *p++ = '@';
01887                 for(q = (char *) ap->name; *q; p++, q++)
01888                         *p = ToLower(*q);
01889                 *p = '\0';
01890                 cmdp = (CMDENT *) hashfind(buff, &mudstate.command_htab);
01891                 if(cmdp != NULL) {
01892                         save = cmdp->perms;
01893                         failure = cf_modify_bits(&(cmdp->perms), str, extra, player, cmd);
01894                         if(failure != 0) {
01895                                 cmdp->perms = save;
01896                                 free_sbuf(buff);
01897                                 return -1;
01898                         }
01899                 }
01900         }
01901         free_sbuf(buff);
01902         return 0;
01903 }
01904 
01905 /*
01906  * ---------------------------------------------------------------------------
01907  * * cf_attr_access: Change access on an attribute.
01908  */
01909 
01910 int cf_attr_access(int *vp, char *str, long extra, dbref player, char *cmd)
01911 {
01912         ATTR *ap;
01913         char *sp;
01914 
01915         for(sp = str; *sp && !isspace(*sp); sp++);
01916         if(*sp)
01917                 *sp++ = '\0';
01918         while (*sp && isspace(*sp))
01919                 sp++;
01920 
01921         ap = atr_str(str);
01922         if(ap != NULL)
01923                 return cf_modify_bits(&(ap->flags), sp, extra, player, cmd);
01924         else {
01925                 cf_log_notfound(player, cmd, "Attribute", str);
01926                 return -1;
01927         }
01928 }
01929 
01930 /*
01931  * ---------------------------------------------------------------------------
01932  * * cf_cmd_alias: Add a command alias.
01933  */
01934 
01935 int cf_cmd_alias(int *vp, char *str, long extra, dbref player, char *cmd)
01936 {
01937         char *alias, *orig, *ap;
01938         CMDENT *cmdp, *cmd2;
01939         NAMETAB *nt;
01940         int *hp;
01941 
01942         alias = strtok(str, " \t=,");
01943         orig = strtok(NULL, " \t=,");
01944 
01945         if(!orig)                                       /*
01946                                                                  * * we only got one argument to @alias.
01947                                                                  * Bad.  
01948                                                                  */
01949                 return -1;
01950 
01951         for(ap = orig; *ap && (*ap != '/'); ap++);
01952         if(*ap == '/') {
01953 
01954                 /*
01955                  * Switch form of command aliasing: create an alias for a  *
01956                  * * * * * * command + a switch 
01957                  */
01958 
01959                 *ap++ = '\0';
01960 
01961                 /*
01962                  * Look up the command 
01963                  */
01964 
01965                 cmdp = (CMDENT *) hashfind(orig, (HASHTAB *) vp);
01966                 if(cmdp == NULL) {
01967                         cf_log_notfound(player, cmd, "Command", orig);
01968                         return -1;
01969                 }
01970                 /*
01971                  * Look up the switch 
01972                  */
01973 
01974                 nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap);
01975                 if(!nt) {
01976                         cf_log_notfound(player, cmd, "Switch", ap);
01977                         return -1;
01978                 }
01979                 /*
01980                  * Got it, create the new command table entry 
01981                  */
01982 
01983                 cmd2 = (CMDENT *) malloc(sizeof(CMDENT));
01984                 cmd2->cmdname = strsave(alias);
01985                 cmd2->switches = cmdp->switches;
01986                 cmd2->perms = cmdp->perms | nt->perm;
01987                 cmd2->extra = (cmdp->extra | nt->flag) & ~SW_MULTIPLE;
01988                 if(!(nt->flag & SW_MULTIPLE))
01989                         cmd2->extra |= SW_GOT_UNIQUE;
01990                 cmd2->callseq = cmdp->callseq;
01991                 cmd2->handler = cmdp->handler;
01992                 if(hashadd(cmd2->cmdname, (int *) cmd2, (HASHTAB *) vp)) {
01993                         free(cmd2->cmdname);
01994                         free(cmd2);
01995                 }
01996         } else {
01997 
01998                 /*
01999                  * A normal (non-switch) alias 
02000                  */
02001 
02002                 hp = hashfind(orig, (HASHTAB *) vp);
02003                 if(hp == NULL) {
02004                         cf_log_notfound(player, cmd, "Entry", orig);
02005                         return -1;
02006                 }
02007                 hashadd(alias, hp, (HASHTAB *) vp);
02008         }
02009         return 0;
02010 }
02011 
02012 /*
02013  * ---------------------------------------------------------------------------
02014  * * list_df_flags: List default flags at create time.
02015  */
02016 
02017 static void list_df_flags(dbref player)
02018 {
02019         char *playerb, *roomb, *thingb, *exitb, *robotb, *buff;
02020 
02021         playerb =
02022                 decode_flags(player, (mudconf.player_flags.word1 | TYPE_PLAYER),
02023                                          mudconf.player_flags.word2, mudconf.player_flags.word3);
02024         roomb =
02025                 decode_flags(player, (mudconf.room_flags.word1 | TYPE_ROOM),
02026                                          mudconf.room_flags.word2, mudconf.room_flags.word3);
02027         exitb =
02028                 decode_flags(player, (mudconf.exit_flags.word1 | TYPE_EXIT),
02029                                          mudconf.exit_flags.word2, mudconf.exit_flags.word3);
02030         thingb =
02031                 decode_flags(player, (mudconf.thing_flags.word1 | TYPE_THING),
02032                                          mudconf.thing_flags.word2, mudconf.thing_flags.word3);
02033         robotb =
02034                 decode_flags(player, (mudconf.robot_flags.word1 | TYPE_PLAYER),
02035                                          mudconf.robot_flags.word2, mudconf.robot_flags.word3);
02036         buff = alloc_lbuf("list_df_flags");
02037         sprintf(buff,
02038                         "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s",
02039                         playerb, roomb, exitb, thingb, robotb);
02040         raw_notify(player, buff);
02041         free_lbuf(buff);
02042         free_sbuf(playerb);
02043         free_sbuf(roomb);
02044         free_sbuf(exitb);
02045         free_sbuf(thingb);
02046         free_sbuf(robotb);
02047 }
02048 
02049 /*
02050  * ---------------------------------------------------------------------------
02051  * * list_costs: List the costs of things.
02052  */
02053 
02054 #define coin_name(s)    (((s)==1) ? mudconf.one_coin : mudconf.many_coins)
02055 
02056 static void list_costs(dbref player)
02057 {
02058         char *buff;
02059 
02060         buff = alloc_mbuf("list_costs");
02061         *buff = '\0';
02062         if(mudconf.quotas)
02063                 sprintf(buff, " and %d quota", mudconf.room_quota);
02064         notify_printf(player, "Digging a room costs %d %s%s.",
02065                                   mudconf.digcost, coin_name(mudconf.digcost), buff);
02066         if(mudconf.quotas)
02067                 sprintf(buff, " and %d quota", mudconf.exit_quota);
02068         notify_printf(player, "Opening a new exit costs %d %s%s.",
02069                                   mudconf.opencost, coin_name(mudconf.opencost), buff);
02070         notify_printf(player, "Linking an exit, home, or dropto costs %d %s.",
02071                                   mudconf.linkcost, coin_name(mudconf.linkcost));
02072         if(mudconf.quotas)
02073                 sprintf(buff, " and %d quota", mudconf.thing_quota);
02074         if(mudconf.createmin == mudconf.createmax)
02075                 raw_notify(player, tprintf("Creating a new thing costs %d %s%s.",
02076                                                                    mudconf.createmin,
02077                                                                    coin_name(mudconf.createmin), buff));
02078         else
02079                 raw_notify(player,
02080                                    tprintf
02081                                    ("Creating a new thing costs between %d and %d %s%s.",
02082                                         mudconf.createmin, mudconf.createmax, mudconf.many_coins,
02083                                         buff));
02084         if(mudconf.quotas)
02085                 sprintf(buff, " and %d quota", mudconf.player_quota);
02086         notify_printf(player, "Creating a robot costs %d %s%s.",
02087                                   mudconf.robotcost, coin_name(mudconf.robotcost), buff);
02088         if(mudconf.killmin == mudconf.killmax) {
02089                 raw_notify(player,
02090                                    tprintf
02091                                    ("Killing costs %d %s, with a %d%% chance of success.",
02092                                         mudconf.killmin, coin_name(mudconf.digcost),
02093                                         (mudconf.killmin * 100) / mudconf.killguarantee));
02094         } else {
02095                 raw_notify(player, tprintf("Killing costs between %d and %d %s.",
02096                                                                    mudconf.killmin, mudconf.killmax,
02097                                                                    mudconf.many_coins));
02098                 raw_notify(player,
02099                                    tprintf("You must spend %d %s to guarantee success.",
02100                                                    mudconf.killguarantee,
02101                                                    coin_name(mudconf.killguarantee)));
02102         }
02103         raw_notify(player,
02104                            tprintf
02105                            ("Computationally expensive commands and functions (ie: @entrances, @find, @search, @stats (with an argument or switch), search(), and stats()) cost %d %s.",
02106                                 mudconf.searchcost, coin_name(mudconf.searchcost)));
02107         if(mudconf.machinecost > 0)
02108                 raw_notify(player,
02109                                    tprintf("Each command run from the queue costs 1/%d %s.",
02110                                                    mudconf.machinecost, mudconf.one_coin));
02111         if(mudconf.waitcost > 0) {
02112                 raw_notify(player,
02113                                    tprintf
02114                                    ("A %d %s deposit is charged for putting a command on the queue.",
02115                                         mudconf.waitcost, mudconf.one_coin));
02116                 raw_notify(player,
02117                                    "The deposit is refunded when the command is run or canceled.");
02118         }
02119         if(mudconf.sacfactor == 0)
02120                 sprintf(buff, "%d", mudconf.sacadjust);
02121         else if(mudconf.sacfactor == 1) {
02122                 if(mudconf.sacadjust < 0)
02123                         sprintf(buff, "<create cost> - %d", -mudconf.sacadjust);
02124                 else if(mudconf.sacadjust > 0)
02125                         sprintf(buff, "<create cost> + %d", mudconf.sacadjust);
02126                 else
02127                         sprintf(buff, "<create cost>");
02128         } else {
02129                 if(mudconf.sacadjust < 0)
02130                         sprintf(buff, "(<create cost> / %d) - %d", mudconf.sacfactor,
02131                                         -mudconf.sacadjust);
02132                 else if(mudconf.sacadjust > 0)
02133                         sprintf(buff, "(<create cost> / %d) + %d", mudconf.sacfactor,
02134                                         mudconf.sacadjust);
02135                 else
02136                         sprintf(buff, "<create cost> / %d", mudconf.sacfactor);
02137         }
02138         raw_notify(player, tprintf("The value of an object is %s.", buff));
02139         if(mudconf.clone_copy_cost)
02140                 raw_notify(player,
02141                                    "The default value of cloned objects is the value of the original object.");
02142         else
02143                 raw_notify(player,
02144                                    tprintf("The default value of cloned objects is %d %s.",
02145                                                    mudconf.createmin, coin_name(mudconf.createmin)));
02146 
02147         free_mbuf(buff);
02148 }
02149 
02150 /*
02151  * ---------------------------------------------------------------------------
02152  * * list_options: List more game options from mudconf.
02153  */
02154 
02155 static const char *switchd[] = { "/first", "/all" };
02156 static const char *examd[] = { "/brief", "/full" };
02157 static const char *ed[] = { "Disabled", "Enabled" };
02158 
02159 static void list_options(dbref player)
02160 {
02161         char *buff;
02162         time_t now;
02163 
02164         now = time(NULL);
02165         if(mudconf.quotas)
02166                 raw_notify(player, "Building quotas are enforced.");
02167         if(mudconf.name_spaces)
02168                 raw_notify(player, "Player names may contain spaces.");
02169         else
02170                 raw_notify(player, "Player names may not contain spaces.");
02171         if(!mudconf.robot_speak)
02172                 raw_notify(player,
02173                                    "Robots are not allowed to speak in public areas.");
02174         if(mudconf.player_listen)
02175                 raw_notify(player,
02176                                    "The @Listen/@Ahear attribute set works on player objects.");
02177         if(mudconf.ex_flags)
02178                 raw_notify(player,
02179                                    "The 'examine' command lists the flag names for the object's flags.");
02180         if(!mudconf.quiet_look)
02181                 raw_notify(player,
02182                                    "The 'look' command shows visible attributes in addition to the description.");
02183         if(mudconf.see_own_dark)
02184                 raw_notify(player,
02185                                    "The 'look' command lists DARK objects owned by you.");
02186         if(!mudconf.dark_sleepers)
02187                 raw_notify(player, "The 'look' command shows disconnected players.");
02188         if(mudconf.terse_look)
02189                 raw_notify(player, "The 'look' command obeys the TERSE flag.");
02190         if(mudconf.trace_topdown) {
02191                 raw_notify(player,
02192                                    "Trace output is presented top-down (whole expression first, then sub-exprs).");
02193                 raw_notify(player,
02194                                    tprintf("Only %d lines of trace output are displayed.",
02195                                                    mudconf.trace_limit));
02196         } else {
02197                 raw_notify(player,
02198                                    "Trace output is presented bottom-up (subexpressions first).");
02199         }
02200         if(!mudconf.quiet_whisper)
02201                 raw_notify(player,
02202                                    "The 'whisper' command lets others in the room with you know you whispered.");
02203         if(mudconf.pemit_players)
02204                 raw_notify(player,
02205                                    "The '@pemit' command may be used to emit to faraway players.");
02206         if(!mudconf.terse_contents)
02207                 raw_notify(player,
02208                                    "The TERSE flag suppresses listing the contents of a location.");
02209         if(!mudconf.terse_exits)
02210                 raw_notify(player,
02211                                    "The TERSE flag suppresses listing obvious exits in a location.");
02212         if(!mudconf.terse_movemsg)
02213                 raw_notify(player,
02214                                    "The TERSE flag suppresses enter/leave/succ/drop messages generated by moving.");
02215         if(mudconf.pub_flags)
02216                 raw_notify(player,
02217                                    "The 'flags()' function will return the flags of any object.");
02218         if(mudconf.read_rem_desc)
02219                 raw_notify(player,
02220                                    "The 'get()' function will return the description of faraway objects,");
02221         if(mudconf.read_rem_name)
02222                 raw_notify(player,
02223                                    "The 'name()' function will return the name of faraway objects.");
02224         raw_notify(player,
02225                            tprintf("The default switch for the '@switch' command is %s.",
02226                                            switchd[mudconf.switch_df_all]));
02227         raw_notify(player,
02228                            tprintf("The default switch for the 'examine' command is %s.",
02229                                            examd[mudconf.exam_public]));
02230         if(mudconf.sweep_dark)
02231                 raw_notify(player, "Players may @sweep dark locations.");
02232         if(mudconf.fascist_tport)
02233                 raw_notify(player,
02234                                    "You may only @teleport out of locations that are JUMP_OK or that you control.");
02235         raw_notify(player,
02236                            tprintf
02237                            ("Players may have at most %d commands in the queue at one time.",
02238                                 mudconf.queuemax));
02239         if(mudconf.match_mine) {
02240                 if(mudconf.match_mine_pl)
02241                         raw_notify(player,
02242                                            "All objects search themselves for $-commands.");
02243                 else
02244                         raw_notify(player,
02245                                            "Objects other than players search themselves for $-commands.");
02246         }
02247         if(!Wizard(player))
02248                 return;
02249         buff = alloc_mbuf("list_options");
02250 
02251         raw_notify(player,
02252                            tprintf
02253                            ("%d commands are run from the queue when there is no net activity.",
02254                                 mudconf.queue_chunk));
02255         raw_notify(player,
02256                            tprintf
02257                            ("%d commands are run from the queue when there is net activity.",
02258                                 mudconf.active_q_chunk));
02259         if(mudconf.idle_wiz_dark)
02260                 raw_notify(player,
02261                                    "Wizards idle for longer than the default timeout are automatically set DARK.");
02262         if(mudconf.safe_unowned)
02263                 raw_notify(player,
02264                                    "Objects not owned by you are automatically considered SAFE.");
02265         if(mudconf.paranoid_alloc)
02266                 raw_notify(player,
02267                                    "The buffer pools are checked for consistency on each allocate or free.");
02268         raw_notify(player,
02269                            tprintf("The %s cache is %d entries wide by %d entries deep.",
02270                                            CACHING, mudconf.cache_width, mudconf.cache_depth));
02271         if(mudconf.cache_names)
02272                 raw_notify(player, "A seperate name cache is used.");
02273         if(mudconf.cache_trim)
02274                 raw_notify(player,
02275                                    "The cache depth is periodically trimmed back to its initial value.");
02276         if(mudconf.fork_dump) {
02277                 raw_notify(player,
02278                                    "Database dumps are performed by a fork()ed process.");
02279                 if(mudconf.fork_vfork)
02280                         raw_notify(player,
02281                                            "The 'vfork()' call is used to perform the fork.");
02282         }
02283         if(mudconf.max_players >= 0)
02284                 raw_notify(player,
02285                                    tprintf
02286                                    ("There may be at most %d players logged in at once.",
02287                                         mudconf.max_players));
02288         if(mudconf.quotas)
02289                 sprintf(buff, " and %d quota", mudconf.start_quota);
02290         else
02291                 *buff = '\0';
02292         raw_notify(player,
02293                            tprintf("New players are given %d %s to start with.",
02294                                            mudconf.paystart, mudconf.many_coins));
02295         raw_notify(player,
02296                            tprintf("Players are given %d %s each day they connect.",
02297                                            mudconf.paycheck, mudconf.many_coins));
02298         raw_notify(player,
02299                            tprintf
02300                            ("Earning money is difficult if you have more than %d %s.",
02301                                 mudconf.paylimit, mudconf.many_coins));
02302         if(mudconf.payfind > 0)
02303                 raw_notify(player,
02304                                    tprintf
02305                                    ("Players have a 1 in %d chance of finding a %s each time they move.",
02306                                         mudconf.payfind, mudconf.one_coin));
02307         raw_notify(player, tprintf("The head of the object freelist is #%d.",
02308                                                            mudstate.freelist));
02309 
02310         sprintf(buff, "Intervals: Dump...%d  Clean...%d  Idlecheck...%d",
02311                         mudconf.dump_interval, mudconf.check_interval,
02312                         mudconf.idle_interval);
02313         raw_notify(player, buff);
02314 
02315         sprintf(buff, "Timers: Dump...%ld  Clean...%ld  Idlecheck...%ld",
02316                         (long) mudstate.dump_counter - now,
02317                         (long) mudstate.check_counter - now,
02318                         (long) mudstate.idle_counter - now);
02319         raw_notify(player, buff);
02320 
02321         sprintf(buff, "Timeouts: Idle...%d  Connect...%d  Tries...%d",
02322                         mudconf.idle_timeout, mudconf.conn_timeout, mudconf.retry_limit);
02323         raw_notify(player, buff);
02324 
02325         sprintf(buff,
02326                         "Scheduling: Timeslice...%d  Max_Quota...%d  Increment...%d",
02327                         mudconf.timeslice, mudconf.cmd_quota_max, mudconf.cmd_quota_incr);
02328         raw_notify(player, buff);
02329 
02330         sprintf(buff, "Spaces...%s  Savefiles...%s",
02331                         ed[mudconf.space_compress], ed[mudconf.compress_db]);
02332         raw_notify(player, buff);
02333 
02334         sprintf(buff,
02335                         "New characters: Room...#%d  Home...#%d  DefaultHome...#%d  Quota...%d",
02336                         mudconf.start_room, mudconf.start_home, mudconf.default_home,
02337                         mudconf.start_quota);
02338         raw_notify(player, buff);
02339 
02340         sprintf(buff,
02341                         "Misc: GuestChar...#%d  IdleQueueChunk...%d  ActiveQueueChunk...%d  Master_room...#%d",
02342                         mudconf.guest_char, mudconf.queue_chunk, mudconf.active_q_chunk,
02343                         mudconf.master_room);
02344         raw_notify(player, buff);
02345 
02346         free_mbuf(buff);
02347 }
02348 
02349 /*
02350  * ---------------------------------------------------------------------------
02351  * * list_vattrs: List user-defined attributes
02352  */
02353 static void list_vattrs(dbref player)
02354 {
02355         VATTR *va;
02356         int na;
02357         char *buff;
02358 
02359         buff = alloc_lbuf("list_vattrs");
02360         raw_notify(player, "--- User-Defined Attributes ---");
02361         for(va = vattr_first(), na = 0; va; va = vattr_next(va), na++) {
02362                 if(!(va->flags & AF_DELETED)) {
02363                         sprintf(buff, "%s(%d):", va->name, va->number);
02364                         listset_nametab(player, attraccess_nametab, va->flags, buff, 1);
02365                 }
02366         }
02367 
02368         raw_notify(player, tprintf("%d attributes, next=%d", na,
02369                                                            mudstate.attr_next));
02370         free_lbuf(buff);
02371 }
02372 
02373 /*
02374  * ---------------------------------------------------------------------------
02375  * * list_db_stats: Get useful info from the DB layer about hash stats, etc.
02376  */
02377 static void list_db_stats(dbref player)
02378 {
02379         raw_notify(player, "Database is memory based.");
02380 }
02381 
02382 /*
02383  * ---------------------------------------------------------------------------
02384  * * list_process: List local resource usage stats of the mush process.
02385  * * Adapted from code by Claudius@PythonMUCK,
02386  * *     posted to the net by Howard/Dark_Lord.
02387  */
02388 
02389 static void list_process(dbref player)
02390 {
02391         int pid, psize, maxfds;
02392 
02393 #ifdef HAVE_GETRUSAGE
02394         struct rusage usage;
02395         int ixrss, idrss, isrss, curr, last, dur;
02396 
02397         getrusage(RUSAGE_SELF, &usage);
02398         /*
02399          * Calculate memory use from the aggregate totals 
02400          */
02401 
02402         curr = mudstate.mstat_curr;
02403         last = 1 - curr;
02404         dur = mudstate.mstat_secs[curr] - mudstate.mstat_secs[last];
02405         if(dur > 0) {
02406                 ixrss =
02407                         (mudstate.mstat_ixrss[curr] - mudstate.mstat_ixrss[last]) / dur;
02408                 idrss =
02409                         (mudstate.mstat_idrss[curr] - mudstate.mstat_idrss[last]) / dur;
02410                 isrss =
02411                         (mudstate.mstat_isrss[curr] - mudstate.mstat_isrss[last]) / dur;
02412         } else {
02413                 ixrss = 0;
02414                 idrss = 0;
02415                 isrss = 0;
02416         }
02417 #endif
02418 
02419 #ifdef HAVE_GETDTABLESIZE
02420         maxfds = getdtablesize();
02421 #else
02422         maxfds = sysconf(_SC_OPEN_MAX);
02423 #endif
02424 
02425         pid = getpid();
02426         psize = getpagesize();
02427 
02428         /*
02429          * Go display everything 
02430          */
02431 
02432         raw_notify(player,
02433                            tprintf("Process ID:  %10d        %10d bytes per page", pid,
02434                                            psize));
02435 #ifdef HAVE_GETRUSAGE
02436         raw_notify(player, tprintf("Time used:   %10d user   %10d sys",
02437                                                            usage.ru_utime.tv_sec, usage.ru_stime.tv_sec));
02438 
02439         /*
02440          * raw_notify(player,
02441          * * tprintf("Resident mem:%10d shared %10d private%10d stack",
02442          * * ixrss, idrss, isrss));
02443          */
02444         raw_notify(player,
02445                            tprintf("Integral mem:%10d shared %10d private%10d stack",
02446                                            usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss));
02447         raw_notify(player, tprintf("Max res mem: %10d pages  %10d bytes",
02448                                                            usage.ru_maxrss, (usage.ru_maxrss * psize)));
02449         raw_notify(player,
02450                            tprintf("Page faults: %10d hard   %10d soft   %10d swapouts",
02451                                            usage.ru_majflt, usage.ru_minflt, usage.ru_nswap));
02452         raw_notify(player, tprintf("Disk I/O:    %10d reads  %10d writes",
02453                                                            usage.ru_inblock, usage.ru_oublock));
02454         raw_notify(player, tprintf("Network I/O: %10d in     %10d out",
02455                                                            usage.ru_msgrcv, usage.ru_msgsnd));
02456         raw_notify(player,
02457                            tprintf("Context swi: %10d vol    %10d forced %10d sigs",
02458                                            usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals));
02459         raw_notify(player, tprintf("Descs avail: %10d", maxfds));
02460 #endif
02461 }
02462 
02463 /*
02464  * ---------------------------------------------------------------------------
02465  * * do_list: List information stored in internal structures.
02466  */
02467 
02468 #define LIST_ATTRIBUTES 1
02469 #define LIST_COMMANDS   2
02470 #define LIST_COSTS      3
02471 #define LIST_FLAGS      4
02472 #define LIST_FUNCTIONS  5
02473 #define LIST_GLOBALS    6
02474 #define LIST_ALLOCATOR  7
02475 #define LIST_LOGGING    8
02476 #define LIST_DF_FLAGS   9
02477 #define LIST_PERMS      10
02478 #define LIST_ATTRPERMS  11
02479 #define LIST_OPTIONS    12
02480 #define LIST_HASHSTATS  13
02481 #define LIST_BUFTRACE   14
02482 #define LIST_CONF_PERMS 15
02483 #define LIST_SITEINFO   16
02484 #define LIST_POWERS     17
02485 #define LIST_SWITCHES   18
02486 #define LIST_VATTRS     19
02487 #define LIST_DB_STATS   20
02488 #define LIST_PROCESS    21
02489 #define LIST_BADNAMES   22
02490 #define LIST_LOGFILES   23
02491 
02492 NAMETAB list_names[] = {
02493         {(char *) "attr_permissions", 5, CA_WIZARD, LIST_ATTRPERMS},
02494         {(char *) "attributes", 2, CA_PUBLIC, LIST_ATTRIBUTES},
02495         {(char *) "bad_names", 2, CA_WIZARD, LIST_BADNAMES},
02496         {(char *) "commands", 3, CA_PUBLIC, LIST_COMMANDS},
02497         {(char *) "config_permissions", 3, CA_GOD, LIST_CONF_PERMS},
02498         {(char *) "costs", 3, CA_PUBLIC, LIST_COSTS},
02499         {(char *) "db_stats", 2, CA_WIZARD, LIST_DB_STATS},
02500         {(char *) "default_flags", 1, CA_PUBLIC, LIST_DF_FLAGS},
02501         {(char *) "flags", 2, CA_PUBLIC, LIST_FLAGS},
02502         {(char *) "functions", 2, CA_PUBLIC, LIST_FUNCTIONS},
02503         {(char *) "globals", 1, CA_WIZARD, LIST_GLOBALS},
02504         {(char *) "logging", 4, CA_GOD, LIST_LOGGING},
02505         {(char *) "options", 1, CA_PUBLIC, LIST_OPTIONS},
02506         {(char *) "permissions", 2, CA_WIZARD, LIST_PERMS},
02507         {(char *) "powers", 2, CA_WIZARD, LIST_POWERS},
02508         {(char *) "process", 2, CA_WIZARD, LIST_PROCESS},
02509         {(char *) "site_information", 2, CA_WIZARD, LIST_SITEINFO},
02510         {(char *) "switches", 2, CA_PUBLIC, LIST_SWITCHES},
02511         {(char *) "user_attributes", 1, CA_WIZARD, LIST_VATTRS},
02512 #ifdef ARBITRARY_LOGFILES
02513         {(char *) "logfiles", 4, CA_WIZARD, LIST_LOGFILES},
02514 #endif
02515         {NULL, 0, 0, 0}
02516 };
02517 
02518 extern NAMETAB enable_names[];
02519 extern NAMETAB logoptions_nametab[];
02520 extern NAMETAB logdata_nametab[];
02521 
02522 void do_list(dbref player, dbref cause, int extra, char *arg)
02523 {
02524         int flagvalue;
02525 
02526         flagvalue = search_nametab(player, list_names, arg);
02527         switch (flagvalue) {
02528         case LIST_ATTRIBUTES:
02529                 list_attrtable(player);
02530                 break;
02531         case LIST_COMMANDS:
02532                 list_cmdtable(player);
02533                 break;
02534         case LIST_SWITCHES:
02535                 list_cmdswitches(player);
02536                 break;
02537         case LIST_COSTS:
02538                 list_costs(player);
02539                 break;
02540         case LIST_OPTIONS:
02541                 list_options(player);
02542                 break;
02543         case LIST_SITEINFO:
02544                 list_siteinfo(player);
02545                 break;
02546         case LIST_FLAGS:
02547                 display_flagtab(player);
02548                 break;
02549         case LIST_FUNCTIONS:
02550                 list_functable(player);
02551                 break;
02552         case LIST_GLOBALS:
02553                 interp_nametab(player, enable_names, mudconf.control_flags,
02554                                            (char *) "Global parameters:", (char *) "enabled",
02555                                            (char *) "disabled");
02556                 break;
02557         case LIST_DF_FLAGS:
02558                 list_df_flags(player);
02559                 break;
02560         case LIST_PERMS:
02561                 list_cmdaccess(player);
02562                 break;
02563         case LIST_CONF_PERMS:
02564                 list_cf_access(player);
02565                 break;
02566         case LIST_POWERS:
02567                 display_powertab(player);
02568                 break;
02569         case LIST_ATTRPERMS:
02570                 list_attraccess(player);
02571                 break;
02572         case LIST_VATTRS:
02573                 list_vattrs(player);
02574                 break;
02575         case LIST_LOGGING:
02576                 interp_nametab(player, logoptions_nametab, mudconf.log_options,
02577                                            (char *) "Events Logged:", (char *) "enabled",
02578                                            (char *) "disabled");
02579                 interp_nametab(player, logdata_nametab, mudconf.log_info,
02580                                            (char *) "Information Logged:", (char *) "yes",
02581                                            (char *) "no");
02582                 break;
02583         case LIST_DB_STATS:
02584                 list_db_stats(player);
02585                 break;
02586         case LIST_PROCESS:
02587                 list_process(player);
02588                 break;
02589         case LIST_BADNAMES:
02590                 badname_list(player, "Disallowed names:");
02591                 break;
02592 #ifdef ARBITRARY_LOGFILES
02593         case LIST_LOGFILES:
02594                 logcache_list(player);
02595                 break;
02596 #endif
02597         default:
02598                 display_nametab(player, list_names,
02599                                                 (char *) "Unknown option.  Use one of:", 1);
02600         }
02601 }

Generated on Mon May 28 04:25:19 2007 for BattletechMUX by  doxygen 1.4.7