This is patch21 to PennMUSH 1.7.7. After applying this patch, you will have version 1.7.7p21 To apply this patch, save it to a file in your top-level MUSH directory, and do the following: patch -p1 < 1.7.7-patch21 make install If you use GNU patch 2.2, you probably want the above to be 'patch -b -p1', not just 'patch -p1'. Unix (or cygwin) users need not worry about failed hunks in src/switchinc.c, hdrs/switches.h, hdrs/cmds.h, or hdrs/funs.h. These files are automatically rebuilt on compile. On the off chance they appear not to be, simply rm them and re-run make. Then @shutdown and restart your MUSH. - Alan/Javelin In this patch: Major Changes: * Attribute trees. Attributes may now be organized hierarchically like files and directories in a filesystem, using the backtick (`) character as the branch separator. Attribute access restrictions propagate down trees. New wildcard ** is introduced to match all attributes at all tree levels. Suggested by Tabbifli. [TAP] Locks: * New framework for performing lock failure activities in hardcode. As a proof-of-concept, the attributes FOLLOW_LOCK`FAILURE, FOLLOW_LOCK`OFAILURE, FOLLOW_LOCK`AFAILURE do what you'd expect when set on a potential leader. Suggested by Sholevi@M*U*S*H. Channels: * New per-channel flags NoTitles, NoNames, and NoCemit do what you'd expect. Set them with @chan/privs. Based on suggestion by Saturn@M3. * @chan/recall/quiet omits timestamps. Suggested by Vadiv@M*U*S*H. Commands: * 'help ' now lists all help topics that match that pattern. By popular request. [MUX,SW] * @flag/letter can be used to change or clear the one-letter alias for a flag. Suggested by Nymeria@M*U*S*H. [SW] * @flag/list by God notes disabled flags. Suggested by Nymeria@M*U*S*H. [SW] Functions: * rand() now comes in a two-argument (low,high) flavor, and randword() selects a random word from a list. The latter is aliased to pickrand() to match Mux's name. Patch by Luke@M*U*S*H. Minor Changes: * Although we're Pueblo 2.50 compliant, go back to sending Pueblo 1.10 as the server version until everyone upgrades their clients so they can handle the 2.50 string. Suggested by Shirow. * The locate() function is no longer noisy (no longer notifies the executor in addition to returning a value). Suggested by Mystery8@ST:AW. * @lock/interact now has a higher priority than other interaction checks, so it will work for Wizards. Suggested by Viila@M*U*S*H. * Tweaks to facilitate a Debian package of PennMUSH. [EEH] Fixes: * max descriptor could get stomped in some cases. [SW] * Removed extra struct def in hdrs/mushtype.h. Suggested by Kyle. * Help tweak by Kevin@M*U*S*H. * Fix to locks on players messing up their connection failure counts. Reported by Luke@M*U*S*H. * Fix to @entrances by Luke@M*U*S*H. * Fix to Win32 not handling a missing minimal.db by Luke@M*U*S*H. * The confirmation message for setting/clearing attribute flags would use the flag name given as an argument, not neccessarily the the full name of the flag. Reported by Vadiv@M*U*S*H. [SW] * Fix a potential memory leak in ident.c [SW] Prereq: 1.7.7p20 *** 1_7_7.624/Patchlevel Thu, 04 Sep 2003 17:36:31 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.22 600) --- 1_7_7.664(w)/Patchlevel Tue, 23 Sep 2003 12:12:35 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.23 600) *************** *** 1,2 **** Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.7.7p20 --- 1,2 ---- Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.7.7p21 *** 1_7_7.624/CHANGES.176 Thu, 14 Aug 2003 09:59:50 -0500 dunemush (pennmush/g/17_CHANGES 1.10.1.6.1.2.1.2.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.9.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.2 600) --- 1_7_7.664(w)/CHANGES.176 Wed, 24 Sep 2003 11:53:01 -0500 dunemush (pennmush/g/17_CHANGES 1.10.1.6.1.2.1.2.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.9.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.2.1.1.1.1.1.2.1.1.1.2 600) *************** *** 13,18 **** --- 13,29 ---- ========================================================================== + Version 1.7.6 patchlevel 14 September 23, 2003 + + Fixes: + * Fix to help @search2 by LeeLaLimaLLama@M*U*S*H. + * The max file descriptor could get stomped in some cases. [SW] + * Powers and toggles on destroyed objects are reset, as they + caused anomalous lsearch/haspower behavior. Report by Mordie@M*U*S*H. + * Changing channel privs and loading channels with objects no longer + permitted could cause crashes. Report by Septimus@SW RP Forum. + + Version 1.7.6 patchlevel 13 August 11, 2003 Fixes: *** 1_7_7.624/CHANGES.177 Fri, 05 Sep 2003 20:59:37 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.165 600) --- 1_7_7.664(w)/CHANGES.177 Mon, 29 Sep 2003 16:35:25 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.184 600) *************** *** 18,23 **** --- 18,74 ---- ========================================================================== + Version 1.7.7 patchlevel 21 September 23, 2003 + + Major Changes: + * Attribute trees. Attributes may now be organized hierarchically + like files and directories in a filesystem, using the backtick (`) + character as the branch separator. Attribute access restrictions + propagate down trees. New wildcard ** is introduced to match + all attributes at all tree levels. Suggested by Tabbifli. [TAP] + Locks: + * New framework for performing lock failure activities in hardcode. + As a proof-of-concept, the attributes FOLLOW_LOCK`FAILURE, + FOLLOW_LOCK`OFAILURE, FOLLOW_LOCK`AFAILURE do what you'd expect + when set on a potential leader. Suggested by Sholevi@M*U*S*H. + Channels: + * New per-channel flags NoTitles, NoNames, and NoCemit do what you'd + expect. Set them with @chan/privs. Based on suggestion by + Saturn@M3. + * @chan/recall/quiet omits timestamps. Suggested by Vadiv@M*U*S*H. + Commands: + * 'help ' now lists all help topics that match that + pattern. By popular request. [MUX,SW] + * @flag/letter can be used to change or clear the one-letter alias for a + flag. Suggested by Nymeria@M*U*S*H. [SW] + * @flag/list by God notes disabled flags. Suggested by Nymeria@M*U*S*H. [SW] + Functions: + * rand() now comes in a two-argument (low,high) flavor, and randword() + selects a random word from a list. The latter is aliased to + pickrand() to match Mux's name. Patch by Luke@M*U*S*H. + Minor Changes: + * Although we're Pueblo 2.50 compliant, go back to sending Pueblo 1.10 + as the server version until everyone upgrades their clients so + they can handle the 2.50 string. Suggested by Shirow. + * The locate() function is no longer noisy (no longer notifies + the executor in addition to returning a value). Suggested by + Mystery8@ST:AW. + * @lock/interact now has a higher priority than other interaction + checks, so it will work for Wizards. Suggested by Viila@M*U*S*H. + * Tweaks to facilitate a Debian package of PennMUSH. [EEH] + Fixes: + * max descriptor could get stomped in some cases. [SW] + * Removed extra struct def in hdrs/mushtype.h. Suggested by Kyle. + * Help tweak by Kevin@M*U*S*H. + * Fix to locks on players messing up their connection failure counts. + Reported by Luke@M*U*S*H. + * Fix to @entrances by Luke@M*U*S*H. + * Fix to Win32 not handling a missing minimal.db by Luke@M*U*S*H. + * The confirmation message for setting/clearing attribute flags would use + the flag name given as an argument, not neccessarily the the full name of + the flag. Reported by Vadiv@M*U*S*H. [SW] + * Fix a potential memory leak in ident.c [SW] + Version 1.7.7 patchlevel 20 September 4, 2003 Major Changes: *** 1_7_7.624/game/txt/hlp/penntop.hlp Sat, 31 May 2003 16:32:59 -0500 dunemush (pennmush/13_penntop.hl 1.2.1.27.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.1.1.1.1.2 600) --- 1_7_7.664(w)/game/txt/hlp/penntop.hlp Mon, 15 Sep 2003 11:38:53 -0500 dunemush (pennmush/13_penntop.hl 1.2.1.27.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.1.1.1.1.4 600) *************** *** 6,11 **** --- 6,12 ---- For the list of MUSH commands, type: help commands For the list of MUSH topics, type: help topics For an alphabetical list of all help entries: help entries + For a list of entries that match a pattern: help For information about PennMUSH: help code For a list of flags: help flag list *************** *** 227,236 **** would. To see the attributes that are set on you or on any of the objects you own, ! you should use the "examine" command. This will list all of the attributes ! and their contents. As this can get very spammy for any large object, you ! can also examine specific attributes by using this format: ! examine / (continued in help attributes4) & ATTRIBUTES4 --- 228,234 ---- would. To see the attributes that are set on you or on any of the objects you own, ! you should use the "examine" command. See 'help examine'. (continued in help attributes4) & ATTRIBUTES4 *************** *** 250,256 **** to examine and work on objects. See also: ATTRIB-OWNERSHIP, @set, examine, @atrchown, @atrlock, hasattr() ! get(), v(), NON-STANDARD ATTRIBUTES, SETTING-ATTRIBUTES & BEING KILLED Getting killed is no big deal. If you are killed, you return to --- 248,255 ---- to examine and work on objects. See also: ATTRIB-OWNERSHIP, @set, examine, @atrchown, @atrlock, hasattr() ! get(), v(), NON-STANDARD ATTRIBUTES, SETTING-ATTRIBUTES, ATTRIBUTE TREES ! & BEING KILLED Getting killed is no big deal. If you are killed, you return to *************** *** 866,872 **** All attributes can be used in attribute locks and can be 'owned' independent of object ownership. ! See also: ATTRIBUTES, ATTRIB-OWNERSHIP, Attribute Functions & PARENT & PARENTS & OBJECT PARENTS --- 865,872 ---- All attributes can be used in attribute locks and can be 'owned' independent of object ownership. ! See also: ATTRIBUTES, ATTRIB-OWNERSHIP, Attribute Functions, ! ATTRIBUTE TREES & PARENT & PARENTS & OBJECT PARENTS *** 1_7_7.624/game/txt/hlp/pennfunc.hlp Fri, 05 Sep 2003 20:59:37 -0500 dunemush (pennmush/16_pennfunc.h 1.2.1.50.1.1.1.1.1.2.1.7.1.8.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.10 600) --- 1_7_7.664(w)/game/txt/hlp/pennfunc.hlp Tue, 23 Sep 2003 11:10:53 -0500 dunemush (pennmush/16_pennfunc.h 1.2.1.50.1.1.1.1.1.2.1.7.1.8.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.13 600) *************** *** 1359,1365 **** These functions return a list of attributes on containing (or matching ). is a wildcard pattern for ! attribute names to search; if you want to search all attributes, use "*". The list returned is similar to that returned by @grep/list /= --- 1359,1365 ---- These functions return a list of attributes on containing (or matching ). is a wildcard pattern for ! attribute names to search. The list returned is similar to that returned by @grep/list /= *************** *** 1690,1698 **** function on the object. If a wildcarded attribute pattern is provided, only attribute names ! matching that pattern will be returned. ! See also: nattr() & NATTR() & ATTRCNT() nattr() --- 1690,1699 ---- function on the object. If a wildcarded attribute pattern is provided, only attribute names ! matching that pattern will be returned. lattr() uses the same ! wildcards as examine (?, *, **). ! See also: nattr(), examine & NATTR() & ATTRCNT() nattr() *************** *** 2632,2641 **** See "help SETQ()" for details about registers. & RAND() rand() - Rand returns an integer between 0 and num-1, inclusive. If called with an invalid argument, rand() returns an error message beginning with #-1. & REGEDIT() & REGEDITALL() & REGEDITI() --- 2633,2655 ---- See "help SETQ()" for details about registers. & RAND() rand() + rand(, ) + + Return a random number. + + The first form returns an integer between 0 and -1, inclusive. + The second returns an integer between and , inclusive. If called with an invalid argument, rand() returns an error message beginning with #-1. + & RANDWORD() + & PICKRAND() + randword([, ]) + + Returns a randomly selected element from . is the list + delimiter: if not specified, whitespace delimits the list. + + pickrand() may be an alias for randword() on some servers. & REGEDIT() & REGEDITALL() & REGEDITI() *** 1_7_7.624/game/txt/hlp/penncmd.hlp Tue, 02 Sep 2003 10:07:23 -0500 dunemush (pennmush/18_penncmd.hl 1.2.1.1.1.47.1.1.1.1.1.3.1.4.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.10.1.1.1.1.1.1.1.1.1.11 600) --- 1_7_7.664(w)/game/txt/hlp/penncmd.hlp Thu, 18 Sep 2003 09:00:30 -0500 dunemush (pennmush/18_penncmd.hl 1.2.1.1.1.47.1.1.1.1.1.3.1.4.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.10.1.1.1.1.1.1.1.1.1.1.1.3 600) *************** *** 1291,1296 **** --- 1291,1297 ---- @flag/add =[], [], [], [] @flag/delete @flag/alias = + @flag/letter [=] @flag/restrict =[], [] @flag/enable @flag/disable *************** *** 1305,1310 **** --- 1306,1312 ---- /disable disables a flag, making it invisible and unusable /enable re-enables a disabled flag /alias adds a new alias for an existing flag + /letter changes or removes a single-letter alias for an existing flag. /restrict changes flag permissions (see help @flag2) /delete deletes a flag completely, removing it from all objects in the database and the removing it permanently from the *************** *** 2764,2769 **** --- 2766,2772 ---- prefixmatch When a user attempts to set an attribute using @, this attribute will be matched down to its unique prefixes. This flag is primarily used internally. + ` This attribute is a branch. See: help ATTRIBUTE TREES & @sex @sex = *************** *** 3456,3464 **** you do not own the object, or it is not visible, you will just see the name of the object's owner. May be abbreviated 'ex '. If the attribute parameter is given, you will only see that attribute (good ! for looking at code). You can also wild-card match on attributes. For ! example. to see all the attributes that began with a 'v' you could do ! ex /v* The /brief switch is equivalent to the 'brief' command. The /debug switch is wizard-only and shows raw values for certa --- 3459,3470 ---- you do not own the object, or it is not visible, you will just see the name of the object's owner. May be abbreviated 'ex '. If the attribute parameter is given, you will only see that attribute (good ! for looking at code). You can also wild-card match on attributes. ! The * wildcard matches any number of characters except a backtick (`). ! The ? wildcard matches a single character except a backtick (`). ! The ** wildcard matches any number of characters, including backticks. ! For example. to see all the attributes that began with a 'v' you could do ! ex /v** The /brief switch is equivalent to the 'brief' command. The /debug switch is wizard-only and shows raw values for certa *************** *** 3467,3472 **** --- 3473,3480 ---- the object's owner and is primarily useful to admins. This switch ignores the object's VISUAL flag (but not its attribute flags) The /all switch shows the values of VEILED attributes. + + See also: ATTRIBUTE TREES & follow follow *** 1_7_7.624/game/txt/hlp/pennchat.hlp Sun, 16 Mar 2003 16:55:02 -0600 dunemush (pennmush/19_pennchat.h 1.2.1.4.1.5 600) --- 1_7_7.664(w)/game/txt/hlp/pennchat.hlp Mon, 15 Sep 2003 23:31:51 -0500 dunemush (pennmush/19_pennchat.h 1.2.1.4.1.6 600) *************** *** 126,131 **** --- 126,134 ---- * "quiet" - channel will not show connection messages * "open" - you may speak even if you aren't listening to the channel * "hide_ok" - you may hide from the channel who list. + * "notitles" - chantitles are not displayed in channel messages. + * "nonames" - player names are not displayed in channel messages. + * "nocemit" - @cemit is prohibited on the channel. Specifications may be combined, space-separated. Default is "player" @channel/delete removes a channel. You must own it or be Wizard. *************** *** 142,148 **** @channel/decompile[/brief] @channel/chown = ! The "priv" switch changes the channel's access privileges. The "quiet" switch turns the quiet status of a channel on and off. The "wipe" switch clears a channel of players without deleting it. The "buffer" switch sets the maximum number of full-length lines that --- 145,152 ---- @channel/decompile[/brief] @channel/chown = ! The "priv" switch changes the channel's access privileges. Use ! ! to reset a privilege. The "quiet" switch turns the quiet status of a channel on and off. The "wipe" switch clears a channel of players without deleting it. The "buffer" switch sets the maximum number of full-length lines that *** 1_7_7.624/game/txt/index-files.pl Sat, 31 May 2003 16:07:52 -0500 dunemush (pennmush/28_index-file 1.9 600) --- 1_7_7.664(w)/game/txt/index-files.pl Mon, 15 Sep 2003 11:35:05 -0500 dunemush (pennmush/28_index-file 1.10 600) *************** *** 1,4 **** ! #!/usr/local/bin/perl # # index-files.pl - make an & index topic for events/news/help # --- 1,4 ---- ! #!/usr/bin/perl # # index-files.pl - make an & index topic for events/news/help # *** 1_7_7.624/game/txt/compose.sh.SH Sat, 19 Jul 2003 09:31:25 -0500 dunemush (pennmush/33_compose.sh 1.5 700) --- 1_7_7.664(w)/game/txt/compose.sh.SH Mon, 15 Sep 2003 11:35:05 -0500 dunemush (pennmush/33_compose.sh 1.5.1.1 700) *************** *** 1,3 **** --- 1,4 ---- + #!/bin/sh case $CONFIG in '') if test -f config.sh; then TOP=.; *** 1_7_7.624/game/restart Tue, 02 Sep 2003 21:18:49 -0500 dunemush (pennmush/39_restart 1.1.1.1.1.1.1.2.1.1.1.1.1.2.1.2.2.1.2.2.1.1 700) --- 1_7_7.664(w)/game/restart Mon, 15 Sep 2003 11:35:05 -0500 dunemush (pennmush/39_restart 1.1.1.1.1.1.1.2.1.1.1.1.1.2.1.2.2.1.2.2.1.1.1.1 700) *************** *** 26,31 **** --- 26,32 ---- if [ ! -f $CONF_FILE ]; then echo "CONF_FILE doesn't exist. It's: $CONF_FILE" + echo "Create $CONF_FILE from $GAMEDIR/mushcnf.dst" exit 1 fi *** 1_7_7.624/game/mushcnf.dst Sun, 17 Aug 2003 08:30:54 -0500 dunemush (pennmush/41_mushcnf.ds 1.1.1.19.1.1.1.2.1.1.1.8.1.1.1.1.1.17 600) --- 1_7_7.664(w)/game/mushcnf.dst Mon, 15 Sep 2003 22:20:00 -0500 dunemush (pennmush/41_mushcnf.ds 1.1.1.19.1.1.1.2.1.1.1.8.1.1.1.1.1.18 600) *************** *** 76,84 **** #uncompress_program bunzip2 #compress_suffix .bz2 # ! compress_program compress ! uncompress_program uncompress ! compress_suffix .Z # Room where new players are created. player_start 0 --- 76,84 ---- #uncompress_program bunzip2 #compress_suffix .bz2 # ! compress_program gzip ! uncompress_program gunzip ! compress_suffix .gz # Room where new players are created. player_start 0 *** 1_7_7.624/utils/mkcmds.sh.SH Wed, 02 Jul 2003 14:19:13 -0500 dunemush (pennmush/g/16_mkcmds.sh. 1.3.1.2 750) --- 1_7_7.664(w)/utils/mkcmds.sh.SH Tue, 23 Sep 2003 12:07:40 -0500 dunemush (pennmush/g/16_mkcmds.sh. 1.3.1.3 750) *************** *** 118,124 **** $echo "Rebuilding command prototype file" $echo "/* AUTOGENERATED FILE. DO NOT EDIT */" > ../hdrs/temp.h ! for c in `grep "^COMMAND *(" ../src/*.c | cut -f2 -d\( | cut -f1 -d\) | sort | uniq`; do $echo >>../hdrs/temp.h "COMMAND_PROTO($c);" $echo $n "." done --- 118,124 ---- $echo "Rebuilding command prototype file" $echo "/* AUTOGENERATED FILE. DO NOT EDIT */" > ../hdrs/temp.h ! for c in `grep "^COMMAND *(" ../src/*.c | grep -v cmd_local_silly | cut -f2 -d\( | cut -f1 -d\) | sort | uniq`; do $echo >>../hdrs/temp.h "COMMAND_PROTO($c);" $echo $n "." done *************** *** 140,146 **** $echo "Rebuilding function prototype file" $echo "/* AUTOGENERATED FILE. DO NOT EDIT */" > ../hdrs/temp.h ! for c in `grep "^FUNCTION *(" ../src/*.c | cut -f2 -d\( | cut -f1 -d\) | sort | uniq`; do $echo >>../hdrs/temp.h "FUNCTION_PROTO($c);" $echo $n "." done --- 140,146 ---- $echo "Rebuilding function prototype file" $echo "/* AUTOGENERATED FILE. DO NOT EDIT */" > ../hdrs/temp.h ! for c in `grep "^FUNCTION *(" ../src/*.c | grep -v local_fun_silly | cut -f2 -d\( | cut -f1 -d\) | sort | uniq`; do $echo >>../hdrs/temp.h "FUNCTION_PROTO($c);" $echo $n "." done *** 1_7_7.624/src/SWITCHES Mon, 01 Sep 2003 18:39:12 -0500 dunemush (pennmush/b/22_SWITCHES 1.12.1.3.1.7 600) --- 1_7_7.664(w)/src/SWITCHES Mon, 29 Sep 2003 16:42:36 -0500 dunemush (pennmush/b/22_SWITCHES 1.12.1.3.1.8 600) *************** *** 59,64 **** --- 59,65 ---- INVENTORY IPRINT JOIN + LETTER LIST LOWERCASE ME *** 1_7_7.624/src/wiz.c Thu, 04 Sep 2003 17:27:46 -0500 dunemush (pennmush/b/23_wiz.c 1.44.1.1.1.1.1.2.1.7.1.1.1.1.1.1.1.1.1.1.1.8.1.2.2.2.1.2.1.1.1.1.1.1.1.2.1.1.1.2.2.17.1.1 660) --- 1_7_7.664(w)/src/wiz.c Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/b/23_wiz.c 1.44.1.1.1.1.1.2.1.7.1.1.1.1.1.1.1.1.1.1.1.8.1.2.2.2.1.2.1.1.1.1.1.1.1.2.1.1.1.2.2.17.1.2 660) *************** *** 529,536 **** return; } /* we can't do it */ ! did_it(player, destination, "EFAIL", T("Permission denied."), ! "OEFAIL", NULL, "AEFAIL", Location(player)); return; } else { /* attempted teleport to an exit */ --- 529,536 ---- return; } /* we can't do it */ ! fail_lock(player, destination, Enter_Lock, T("Permission denied."), ! Location(player)); return; } else { /* attempted teleport to an exit */ *** 1_7_7.624/src/wild.c Mon, 14 Jul 2003 09:12:36 -0500 dunemush (pennmush/b/24_wild.c 1.11.1.1.1.8.1.1.1.4.1.2.1.4 660) --- 1_7_7.664(w)/src/wild.c Mon, 29 Sep 2003 16:42:34 -0500 dunemush (pennmush/b/24_wild.c 1.11.1.1.1.8.1.1.1.4.1.2.1.5 660) *************** *** 153,158 **** --- 153,262 ---- return 0; } + /** Do an attribute name wildcard match. + * + * This probably crashes if fed NULLs instead of strings, too. + * The special thing about this one is that ` doesn't match normal + * wildcards; you have to use ** to match embedded `. Also, patterns + * ending in ` are treated as patterns ending in `*, and empty patterns + * are treated as *. + * + * \param tstr pattern to match against. + * \param dstr string to check. + * \retval 1 dstr matches the tstr pattern. + * \retval 0 dstr does not match the tstr pattern. + */ + int + atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) + { + int starcount; + + if (!*tstr) + return !strchr(dstr, '`'); + + while (*tstr != '*') { + switch (*tstr) { + case '?': + /* Single character match. Return false if at + * end of data. + */ + if (!*dstr || *dstr == '`') + return 0; + break; + case '`': + /* Delimiter match. Special handling if at end of pattern. */ + if (*dstr != '`') + return 0; + if (!tstr[1]) + return !strchr(dstr + 1, '`'); + break; + case '\\': + /* Escape character. Move up, and force literal + * match of next character. + */ + tstr++; + /* FALL THROUGH */ + default: + /* Literal character. Check for a match. + * If matching end of data, return true. + */ + if (NOTEQUAL(0, *dstr, *tstr)) + return 0; + if (!*dstr) + return 1; + } + tstr++; + dstr++; + } + + /* Skip over '*'. */ + tstr++; + starcount = 1; + + /* Skip over wildcards. */ + while (starcount < 2 && ((*tstr == '?') || (*tstr == '*'))) { + if (*tstr == '?') { + if (!*dstr || *dstr == '`') + return 0; + dstr++; + starcount = 0; + } else + starcount++; + tstr++; + } + + /* Skip over long strings of '*'. */ + while (*tstr == '*') + tstr++; + + /* Return true on trailing '**'. */ + if (!*tstr) + return starcount == 2 || !strchr(dstr, '`'); + + if (*tstr == '?') { + /* Scan for possible matches. */ + while (*dstr) { + if (*dstr != '`' && atr_wild(tstr + 1, dstr + 1)) + return 1; + dstr++; + } + } else { + /* Skip over a backslash in the pattern string if it is there. */ + if (*tstr == '\\') + tstr++; + + /* Scan for possible matches. */ + while (*dstr) { + if (EQUAL(0, *dstr, *tstr) && atr_wild(tstr + 1, dstr + 1)) + return 1; + if (starcount < 2 && *dstr == '`') + return 0; + dstr++; + } + } + return 0; + } + /* --------------------------------------------------------------------------- * wild1: INTERNAL: do a wildcard match, remembering the wild data. * *** 1_7_7.624/src/utils.c Mon, 01 Sep 2003 15:56:43 -0500 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.14 660) --- 1_7_7.664(w)/src/utils.c Mon, 29 Sep 2003 16:42:34 -0500 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.15 660) *************** *** 572,577 **** --- 572,584 ---- /* Standard checks */ + /* If it's an audible message, it must pass your Interact_Lock + * (or be from a privileged speaker) + */ + if ((type == INTERACT_HEAR) && !Pemit_All(from) + && !eval_lock(from, to, Interact_Lock)) + return 0; + /* You can interact with the object you are in or any objects * you're holding. * You can interact with objects you control, but not *************** *** 580,592 **** if ((from == Location(to)) || (to == Location(from)) || controls(to, from)) return 1; - /* If it's an audible message, it must pass your Interact_Lock - * (or be from a privileged speaker) - */ - if ((type == INTERACT_HEAR) && !Pemit_All(from) - && !eval_lock(from, to, Interact_Lock)) - return 0; - lci = local_can_interact_last(from, to, type); if (lci != NOTHING) --- 587,592 ---- *** 1_7_7.624/src/help.c Sun, 10 Aug 2003 11:13:00 -0500 dunemush (pennmush/f/32_help.c 1.4.1.2.1.1.1.3.2.2.1.1.2.1.1.2.1.2.1.2.1.3.1.15 660) --- 1_7_7.664(w)/src/help.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/f/32_help.c 1.4.1.2.1.1.1.3.2.2.1.1.2.1.1.2.1.2.1.2.1.3.1.17 660) *************** *** 32,41 **** static int help_init = 0; ! static void do_new_spitfile(dbref player, char *arg1, ! help_file *help_dat, int restricted); static const char *string_spitfile(help_file *help_dat, char *arg1); static help_indx *help_find_entry(help_file *help_dat, const char *the_topic); static void help_build_index(help_file *h, int restricted); --- 32,41 ---- static int help_init = 0; ! static void do_new_spitfile(dbref player, char *arg1, help_file *help_dat); static const char *string_spitfile(help_file *help_dat, char *arg1); static help_indx *help_find_entry(help_file *help_dat, const char *the_topic); + static char *list_matching_entries(const char *pattern, help_file *help_dat); static void help_build_index(help_file *h, int restricted); *************** *** 66,72 **** return; } ! do_new_spitfile(player, arg_left, h, h->admin); } /** Initialize the helpfile hashtable, which contains the names of the --- 66,81 ---- return; } ! if (h->admin && !Hasprivs(player)) { ! notify(player, T("You don't look like an admin to me.")); ! return; ! } ! ! if (wildcard(arg_left)) ! notify_format(player, T("Here are the entries which match '%s':\n%s"), ! arg_left, list_matching_entries(arg_left, h)); ! else ! do_new_spitfile(player, arg_left, h); } /** Initialize the helpfile hashtable, which contains the names of the *************** *** 159,165 **** } static void ! do_new_spitfile(dbref player, char *arg1, help_file *help_dat, int restricted) { help_indx *entry = NULL; FILE *fp; --- 168,174 ---- } static void ! do_new_spitfile(dbref player, char *arg1, help_file *help_dat) { help_indx *entry = NULL; FILE *fp; *************** *** 178,188 **** if (strlen(arg1) > LINE_SIZE) *(arg1 + LINE_SIZE) = '\0'; ! if (restricted) { ! if (!Hasprivs(player)) { ! notify(player, T("You don't look like an admin to me.")); ! return; ! } sprintf(the_topic, "&%s", arg1); } else strcpy(the_topic, arg1); --- 187,193 ---- if (strlen(arg1) > LINE_SIZE) *(arg1 + LINE_SIZE) = '\0'; ! if (help_dat->admin) { sprintf(the_topic, "&%s", arg1); } else strcpy(the_topic, arg1); *************** *** 195,201 **** entry = help_find_entry(help_dat, the_topic); if (!entry && default_topic) ! entry = help_find_entry(help_dat, (restricted ? "&help" : "help")); if (!entry) { notify_format(player, T("No entry for '%s'."), arg1); --- 200,206 ---- entry = help_find_entry(help_dat, the_topic); if (!entry && default_topic) ! entry = help_find_entry(help_dat, (help_dat->admin ? "&help" : "help")); if (!entry) { notify_format(player, T("No entry for '%s'."), arg1); *************** *** 458,464 **** safe_str(T(e_perm), buff, bp); return; } ! safe_str(string_spitfile(h, args[1]), buff, bp); } --- 463,473 ---- safe_str(T(e_perm), buff, bp); return; } ! ! if (wildcard(args[1])) ! safe_str(list_matching_entries(args[1], h), buff, bp); ! else ! safe_str(string_spitfile(h, args[1]), buff, bp); } *************** *** 488,537 **** if (!help_dat->indx || help_dat->entries == 0) return T("#-1 NO INDEX FOR FILE"); ! if (help_dat->entries < 10) { /* Just do a linear search for small files */ ! for (n = 0; n < help_dat->entries; n++) { ! if (string_prefix(help_dat->indx[n].topic, the_topic)) { ! entry = &help_dat->indx[n]; ! break; ! } ! } ! } else { /* Binary search of the index */ ! int left = 0; ! int cmp; ! int right = help_dat->entries - 1; ! ! while (1) { ! n = (left + right) / 2; ! ! if (left > right) ! break; ! ! cmp = strcasecmp(the_topic, help_dat->indx[n].topic); ! ! if (cmp == 0) { ! entry = &help_dat->indx[n]; ! break; ! } else if (cmp < 0) { ! /* We need to catch the first prefix */ ! if (string_prefix(help_dat->indx[n].topic, the_topic)) { ! int m; ! for (m = n - 1; m >= 0; m--) { ! if (!string_prefix(help_dat->indx[m].topic, the_topic)) ! break; ! } ! entry = &help_dat->indx[m + 1]; ! break; ! } ! if (left == right) ! break; ! right = n - 1; ! } else { /* cmp > 0 */ ! if (left == right) ! break; ! left = n + 1; ! } ! } ! } if (!entry) { return T("#-1 NO ENTRY"); --- 497,503 ---- if (!help_dat->indx || help_dat->entries == 0) return T("#-1 NO INDEX FOR FILE"); ! entry = help_find_entry(help_dat, the_topic); if (!entry) { return T("#-1 NO ENTRY"); *************** *** 555,557 **** --- 521,555 ---- fclose(fp); return buff; } + + /** Return a string with all help entries that match a pattern */ + static char * + list_matching_entries(const char *pattern, help_file *help_dat) + { + static char buff[BUFFER_LEN]; + int offset; + char *bp; + size_t n; + + bp = buff; + + if (help_dat->admin) + offset = 1; /* To skip the leading & */ + else + offset = 0; + + for (n = 0; n < help_dat->entries; n++) + if (quick_wild(pattern, help_dat->indx[n].topic + offset)) { + safe_str(help_dat->indx[n].topic + offset, buff, &bp); + safe_strl(", ", 2, buff, &bp); + } + + if (bp > buff) + *(bp - 2) = '\0'; + else { + safe_str(T("No matching help topics."), buff, &bp); + *bp = '\0'; + } + + return buff; + } *** 1_7_7.624/src/switchinc.c Mon, 01 Sep 2003 18:39:12 -0500 dunemush (pennmush/b/32_switchinc. 1.3.1.2.1.6.1.18.1.2.1.2.2.5.1.4.2.4.1.1.1.2.1.5.1.2.1.5.2.1.1.31.3.4.1.5.1.4.1.1.1.1.1.1.1.7.1.1 660) --- 1_7_7.664(w)/src/switchinc.c Mon, 29 Sep 2003 16:42:41 -0500 dunemush (pennmush/b/32_switchinc. 1.3.1.2.1.6.1.18.1.2.1.2.2.5.1.4.2.4.1.1.1.2.1.5.1.2.1.5.2.1.1.31.3.4.1.5.1.4.1.1.1.1.1.1.1.7.1.1.1.1 660) *************** *** 61,66 **** --- 61,67 ---- {"INVENTORY", SWITCH_INVENTORY}, {"IPRINT", SWITCH_IPRINT}, {"JOIN", SWITCH_JOIN}, + {"LETTER", SWITCH_LETTER}, {"LIST", SWITCH_LIST}, {"LOWERCASE", SWITCH_LOWERCASE}, {"ME", SWITCH_ME}, *** 1_7_7.624/src/set.c Wed, 03 Sep 2003 22:39:22 -0500 dunemush (pennmush/b/38_set.c 1.26.1.5.1.1.2.1.1.1.1.1.1.11.1.1.1.1.1.1.1.1.1.1.1.1.1.9 660) --- 1_7_7.664(w)/src/set.c Mon, 29 Sep 2003 16:42:34 -0500 dunemush (pennmush/b/38_set.c 1.26.1.5.1.1.2.1.1.1.1.1.1.11.1.1.1.1.1.1.1.1.1.1.1.1.1.12 660) *************** *** 538,546 **** notify(player, T("Unrecognized attribute flag.")); return; } ! af.flag = flag; ! if (!atr_iter_get(player, thing, atrname, af_helper, &af)) notify(player, T("No attribute found to change.")); } --- 538,547 ---- notify(player, T("Unrecognized attribute flag.")); return; } ! af.flag = mush_strdup(atrflag_to_string(af.f), "af_flag list"); ! if (!atr_iter_get(player, thing, atrname, 0, af_helper, &af)) notify(player, T("No attribute found to change.")); + mush_free(af.flag, "af_flag list"); } *************** *** 869,875 **** notify(player, T("Nothing to do.")); return; } ! if (!atr_iter_get(player, thing, q, gedit_helper, argv)) notify(player, T("No matching attributes.")); } --- 870,876 ---- notify(player, T("Nothing to do.")); return; } ! if (!atr_iter_get(player, thing, q, 0, gedit_helper, argv)) notify(player, T("No matching attributes.")); } *************** *** 939,946 **** noisy_match_result(player, what, TYPE_THING, MAT_NEAR_THINGS)) != NOTHING) { if (!eval_lock(player, thing, Use_Lock)) { ! did_it(player, thing, "UFAIL", T("Pemission denied."), "OUFAIL", NULL, ! "AUFAIL", NOTHING); return; } else did_it(player, thing, "USE", "Used.", "OUSE", NULL, "AUSE", NOTHING); --- 940,946 ---- noisy_match_result(player, what, TYPE_THING, MAT_NEAR_THINGS)) != NOTHING) { if (!eval_lock(player, thing, Use_Lock)) { ! fail_lock(player, thing, Use_Lock, T("Permission denied."), NOTHING); return; } else did_it(player, thing, "USE", "Used.", "OUSE", NULL, "AUSE", NOTHING); *************** *** 1058,1065 **** notify(player, T("That object is protected.")); return; } ! if (!atr_iter_get(player, thing, pattern, wipe_helper, NULL)) notify(player, T("No matching attributes.")); else notify(player, T("Attributes wiped.")); } --- 1058,1070 ---- notify(player, T("That object is protected.")); return; } ! ! we_are_wiping = 1; ! ! if (!atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL)) notify(player, T("No matching attributes.")); else notify(player, T("Attributes wiped.")); + + we_are_wiping = 0; } *** 1_7_7.624/src/predicat.c Wed, 03 Sep 2003 22:39:22 -0500 dunemush (pennmush/b/44_predicat.c 1.1.1.34.1.1.1.3.1.4.2.27 660) --- 1_7_7.664(w)/src/predicat.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/b/44_predicat.c 1.1.1.34.1.1.1.3.1.4.2.28 660) *************** *** 1105,1111 **** guh.lookfor = lookfor; guh.len = len; guh.insensitive = insensitive; ! (void) atr_iter_get(player, thing, pattern, grep_util_helper, &guh); *guh.bp = '\0'; return guh.buff; } --- 1105,1111 ---- guh.lookfor = lookfor; guh.len = len; guh.insensitive = insensitive; ! (void) atr_iter_get(player, thing, pattern, 0, grep_util_helper, &guh); *guh.bp = '\0'; return guh.buff; } *************** *** 1201,1207 **** gh.lookfor = lookfor; gh.len = len; gh.insensitive = insensitive; ! if (!atr_iter_get(player, thing, pattern, grep_helper, &gh)) notify(player, T("No matching attributes.")); } else { tp = grep_util(player, thing, pattern, lookfor, len, insensitive); --- 1201,1207 ---- gh.lookfor = lookfor; gh.len = len; gh.insensitive = insensitive; ! if (!atr_iter_get(player, thing, pattern, 0, grep_helper, &gh)) notify(player, T("No matching attributes.")); } else { tp = grep_util(player, thing, pattern, lookfor, len, insensitive); *** 1_7_7.624/src/move.c Tue, 06 May 2003 17:31:42 -0500 dunemush (pennmush/b/51_move.c 1.1.1.18.1.5.1.13.1.3.1.9.1.1.1.1.1.2.1.1.1.1.1.21 660) --- 1_7_7.664(w)/src/move.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/b/51_move.c 1.1.1.18.1.5.1.13.1.3.1.9.1.1.1.1.1.2.1.1.1.1.1.22 660) *************** *** 467,474 **** break; } } else ! did_it(player, exit_m, "FAILURE", T("You can't go that way."), ! "OFAILURE", NULL, "AFAILURE", NOTHING); break; } } --- 467,474 ---- break; } } else ! fail_lock(player, exit_m, Basic_Lock, T("You can't go that way."), ! NOTHING); break; } } *************** *** 562,569 **** "ARECEIVE", NOTHING, myenv, NA_INTER_SEE); mush_free(myenv[0], "dbref"); } else ! did_it(player, thing, "FAILURE", T("You can't take that from there."), ! "OFAILURE", NULL, "AFAILURE", NOTHING); } else { notify(player, T("I don't see that here.")); } --- 562,569 ---- "ARECEIVE", NOTHING, myenv, NA_INTER_SEE); mush_free(myenv[0], "dbref"); } else ! fail_lock(player, thing, Basic_Lock, ! T("You can't take that from there."), NOTHING); } else { notify(player, T("I don't see that here.")); } *************** *** 609,616 **** "ARECEIVE", NOTHING, myenv, NA_INTER_SEE); mush_free(myenv[0], "dbref"); } else ! did_it(player, thing, "FAILURE", T("You can't pick that up."), ! "OFAILURE", NULL, "AFAILURE", NOTHING); break; case TYPE_EXIT: notify(player, T("You can't pick up exits.")); --- 609,616 ---- "ARECEIVE", NOTHING, myenv, NA_INTER_SEE); mush_free(myenv[0], "dbref"); } else ! fail_lock(player, thing, Basic_Lock, T("You can't pick that up."), ! NOTHING); break; case TYPE_EXIT: notify(player, T("You can't pick up exits.")); *************** *** 715,722 **** if (!((EnterOk(thing) || controls(player, thing)) && (eval_lock(player, thing, Enter_Lock)) )) { ! did_it(player, thing, "EFAIL", T("Permission denied."), "OEFAIL", ! NULL, "AEFAIL", NOTHING); return; } if (thing == player) { --- 715,721 ---- if (!((EnterOk(thing) || controls(player, thing)) && (eval_lock(player, thing, Enter_Lock)) )) { ! fail_lock(player, thing, Enter_Lock, T("Permission denied."), NOTHING); return; } if (thing == player) { *************** *** 744,751 **** || NoLeave(loc) || !eval_lock(player, loc, Leave_Lock) ) { ! did_it(player, loc, "LFAIL", T("You can't leave."), "OLFAIL", ! NULL, "ALFAIL", NOTHING); return; } enter_room(player, Location(loc), 0); --- 743,749 ---- || NoLeave(loc) || !eval_lock(player, loc, Leave_Lock) ) { ! fail_lock(player, loc, Leave_Lock, T("You can't leave."), NOTHING); return; } enter_room(player, Location(loc), 0); *************** *** 849,856 **** } /* Ok, are we allowed to follow them? */ if (!eval_lock(player, leader, Follow_Lock)) { ! notify_format(player, ! T("You're not allowed to follow %s."), Name(leader)); return; } /* Ok, looks good */ --- 847,854 ---- } /* Ok, are we allowed to follow them? */ if (!eval_lock(player, leader, Follow_Lock)) { ! fail_lock(player, leader, Follow_Lock, ! T("You're not alllowed to follow."), Location(player)); return; } /* Ok, looks good */ *** 1_7_7.624/src/look.c Mon, 25 Aug 2003 12:05:33 -0500 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.12 660) --- 1_7_7.664(w)/src/look.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.17 660) *************** *** 308,319 **** __attribute__ ((__unused__))) { char fbuf[BUFFER_LEN]; ! char *r; if (EX_PUBLIC_ATTRIBS && !strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*")) return 0; strcpy(fbuf, privs_to_letters(attr_privs, AL_FLAGS(atr))); if (AL_FLAGS(atr) & AF_VEILED) { if (ShowAnsi(player)) notify_format(player, --- 308,321 ---- __attribute__ ((__unused__))) { char fbuf[BUFFER_LEN]; ! char const *r; if (EX_PUBLIC_ATTRIBS && !strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*")) return 0; strcpy(fbuf, privs_to_letters(attr_privs, AL_FLAGS(atr))); + if (atr_sub_branch(atr)) + strcat(fbuf, "`"); if (AL_FLAGS(atr) & AF_VEILED) { if (ShowAnsi(player)) notify_format(player, *************** *** 343,354 **** __attribute__ ((__unused__))) { char fbuf[BUFFER_LEN]; ! char *r; if (EX_PUBLIC_ATTRIBS && !strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*")) return 0; strcpy(fbuf, privs_to_letters(attr_privs, AL_FLAGS(atr))); r = safe_atr_value(atr); if (ShowAnsi(player)) notify_format(player, --- 345,358 ---- __attribute__ ((__unused__))) { char fbuf[BUFFER_LEN]; ! char const *r; if (EX_PUBLIC_ATTRIBS && !strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*")) return 0; strcpy(fbuf, privs_to_letters(attr_privs, AL_FLAGS(atr))); + if (atr_sub_branch(atr)) + strcat(fbuf, "`"); r = safe_atr_value(atr); if (ShowAnsi(player)) notify_format(player, *************** *** 365,374 **** look_atrs(dbref player, dbref thing, const char *mstr, int all) { if (all || (mstr && *mstr && !wildcard(mstr))) { ! if (!atr_iter_get(player, thing, mstr, look_helper, NULL) && mstr) notify(player, T("No matching attributes.")); } else { ! if (!atr_iter_get(player, thing, mstr, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } } --- 369,378 ---- look_atrs(dbref player, dbref thing, const char *mstr, int all) { if (all || (mstr && *mstr && !wildcard(mstr))) { ! if (!atr_iter_get(player, thing, mstr, 0, look_helper, NULL) && mstr) notify(player, T("No matching attributes.")); } else { ! if (!atr_iter_get(player, thing, mstr, 0, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } } *************** *** 377,386 **** mortal_look_atrs(dbref player, dbref thing, const char *mstr, int all) { if (all || (mstr && *mstr && !wildcard(mstr))) { ! if (!atr_iter_get_visible(player, thing, mstr, look_helper, NULL) && mstr) notify(player, T("No matching attributes.")); } else { ! if (!atr_iter_get_visible(player, thing, mstr, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } --- 381,390 ---- mortal_look_atrs(dbref player, dbref thing, const char *mstr, int all) { if (all || (mstr && *mstr && !wildcard(mstr))) { ! if (!atr_iter_get(player, thing, mstr, 1, look_helper, NULL) && mstr) notify(player, T("No matching attributes.")); } else { ! if (!atr_iter_get(player, thing, mstr, 1, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } *************** *** 485,492 **** did_it(player, loc, "SUCCESS", NULL, "OSUCCESS", NULL, "ASUCCESS", NOTHING); else ! did_it(player, loc, "FAILURE", NULL, "OFAILURE", NULL, "AFAILURE", ! NOTHING); } /* tell him the contents */ if (style != LOOK_CLOUDYTRANS) --- 489,495 ---- did_it(player, loc, "SUCCESS", NULL, "OSUCCESS", NULL, "ASUCCESS", NOTHING); else ! fail_lock(player, loc, Basic_Lock, NULL, NOTHING); } /* tell him the contents */ if (style != LOOK_CLOUDYTRANS) *************** *** 1315,1321 **** dh.name = name; dh.skipdef = skipdef; /* Comment complaints if none are found */ ! if (!atr_iter_get(player, thing, pattern, decompile_helper, &dh)) notify(player, T("@@ No attributes found. @@")); } --- 1318,1324 ---- dh.name = name; dh.skipdef = skipdef; /* Comment complaints if none are found */ ! if (!atr_iter_get(player, thing, pattern, 0, decompile_helper, &dh)) notify(player, T("@@ No attributes found. @@")); } *************** *** 1483,1488 **** decompile_powers(player, thing, object); } if (dbflag != DEC_FLAG) { ! decompile_atrs(player, thing, object, "*", "", skipdef); } } --- 1486,1491 ---- decompile_powers(player, thing, object); } if (dbflag != DEC_FLAG) { ! decompile_atrs(player, thing, object, "**", "", skipdef); } } *** 1_7_7.624/src/lock.c Mon, 01 Sep 2003 15:52:02 -0500 dunemush (pennmush/c/6_lock.c 1.17.1.13.1.1.1.1.1.7 660) --- 1_7_7.664(w)/src/lock.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/c/6_lock.c 1.17.1.13.1.1.1.1.1.11 660) *************** *** 111,116 **** --- 111,129 ---- {NULL, TRUE_BOOLEXP, GOD, 0, NULL} }; + /** Table of base attributes associated with success and failure of + * locks. These are the historical ones; we automatically generate + * such attribute names for those that aren't in this table using + * _LOCK` + */ + const LOCKMSGINFO lock_msgs[] = { + {"Basic", "SUCCESS", "FAILURE"}, + {"Enter", "ENTER", "EFAIL"}, + {"Use", "USE", "UFAIL"}, + {"Leave", "LEAVE", "LFAIL"}, + {NULL, NULL, NULL} + }; + /** Table of lock permissions */ PRIV lock_privs[] = { {"visual", 'v', LF_VISUAL, LF_VISUAL}, *************** *** 618,624 **** if (!AreQuiet(player, thing)) notify_format(player, T("%s(%s) - %s unlocked."), Name(thing), unparse_dbref(thing), real_type); ! ModTime(thing) = mudtime; } else notify(player, T("Permission denied.")); } --- 631,638 ---- if (!AreQuiet(player, thing)) notify_format(player, T("%s(%s) - %s unlocked."), Name(thing), unparse_dbref(thing), real_type); ! if (!IsPlayer(thing)) ! ModTime(thing) = mudtime; } else notify(player, T("Permission denied.")); } *************** *** 683,689 **** if (!AreQuiet(player, thing)) notify_format(player, T("%s(%s) - %s locked."), Name(thing), unparse_dbref(thing), real_type); ! ModTime(thing) = mudtime; } else notify(player, T("Permission denied.")); } --- 697,704 ---- if (!AreQuiet(player, thing)) notify_format(player, T("%s(%s) - %s locked."), Name(thing), unparse_dbref(thing), real_type); ! if (!IsPlayer(thing)) ! ModTime(thing) = mudtime; } else notify(player, T("Permission denied.")); } *************** *** 720,725 **** --- 735,791 ---- return eval_boolexp(player, getlock(thing, ltype), thing); } + /** Active a lock's failure attributes. + * \param player dbref failing to pass the lock. + * \param thing object containing the lock. + * \param ltype type of lock failed. + * \param def default message if there is no appropriate failure attribute. + * \param loc location in which action is taking place. + */ + void + fail_lock(dbref player, dbref thing, lock_type ltype, const char *def, + dbref loc) + { + const LOCKMSGINFO *lm; + char atr[BUFFER_LEN]; + char oatr[BUFFER_LEN]; + char aatr[BUFFER_LEN]; + char *bp; + + /* Find the lock's failure attribute, if it's there */ + for (lm = lock_msgs; lm->type; lm++) { + if (!strcmp(lm->type, ltype)) + break; + } + if (lm->type) { + strcpy(atr, lm->failbase); + bp = oatr; + safe_format(oatr, &bp, "O%s", lm->failbase); + *bp = '\0'; + strcpy(aatr, oatr); + aatr[0] = 'A'; + } else { + /* Oops, it's not in the table. So we construct them on these lines: + * _LOCK`FAILURE + */ + bp = atr; + safe_format(atr, &bp, "%s_LOCK`FAILURE", ltype); + *bp = '\0'; + bp = oatr; + safe_format(oatr, &bp, "%s_LOCK`OFAILURE", ltype); + *bp = '\0'; + bp = aatr; + safe_format(aatr, &bp, "%s_LOCK`AFAILURE", ltype); + *bp = '\0'; + } + /* Now do the work */ + upcasestr(atr); + upcasestr(oatr); + upcasestr(aatr); + did_it(player, thing, atr, def, oatr, NULL, aatr, loc); + } + + /** Determine if a lock is visual. * \param thing object containing the lock. * \param ltype type of lock to check. *************** *** 791,795 **** if (!Quiet(player) && !(Quiet(thing) && (Owner(thing) == player))) notify_format(player, "%s/%s - %s.", Name(thing), L_TYPE(l), unset ? T("lock flags unset") : T("lock flags set")); ! ModTime(thing) = mudtime; } --- 857,862 ---- if (!Quiet(player) && !(Quiet(thing) && (Owner(thing) == player))) notify_format(player, "%s/%s - %s.", Name(thing), L_TYPE(l), unset ? T("lock flags unset") : T("lock flags set")); ! if (!IsPlayer(thing)) ! ModTime(thing) = mudtime; } *** 1_7_7.624/src/ident.c Sat, 01 Mar 2003 23:51:32 -0600 dunemush (pennmush/c/8_ident.c 1.19.1.4.1.13 660) --- 1_7_7.664(w)/src/ident.c Mon, 29 Sep 2003 16:42:32 -0500 dunemush (pennmush/c/8_ident.c 1.19.1.4.1.14 660) *************** *** 228,235 **** memset(id, 0, sizeof(ident_t)); if (getnameinfo(faddr, flen, host, sizeof(host), NULL, 0, ! NI_NUMERICHOST | NI_NUMERICSERV) != 0) return 0; /* Make sure we connect from the right interface. Changing the pointer directly doesn't seem to work. So... */ --- 228,237 ---- memset(id, 0, sizeof(ident_t)); if (getnameinfo(faddr, flen, host, sizeof(host), NULL, 0, ! NI_NUMERICHOST | NI_NUMERICSERV) != 0) { ! free(id); return 0; + } /* Make sure we connect from the right interface. Changing the pointer directly doesn't seem to work. So... */ *** 1_7_7.624/src/funmisc.c Wed, 03 Sep 2003 22:39:22 -0500 dunemush (pennmush/c/14_funmisc.c 1.30.1.1.1.22 660) --- 1_7_7.664(w)/src/funmisc.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/14_funmisc.c 1.30.1.1.1.25 660) *************** *** 181,193 **** * Uses Sh'dow's random number generator, found in utils.c. Better * distribution than original, w/ minimal speed losses. */ ! int i; if (!is_integer(args[0])) { safe_str(T(e_int), buff, bp); return; } ! i = get_random_long(0, parse_integer(args[0]) - 1); ! safe_integer(i, buff, bp); } /* ARGSUSED */ --- 181,209 ---- * Uses Sh'dow's random number generator, found in utils.c. Better * distribution than original, w/ minimal speed losses. */ ! int low, high; if (!is_integer(args[0])) { safe_str(T(e_int), buff, bp); return; } ! if (nargs == 1) { ! low = 0; ! high = parse_integer(args[0]) - 1; ! } else { ! if (!is_integer(args[1])) { ! safe_str(T(e_ints), buff, bp); ! return; ! } ! low = parse_integer(args[0]); ! high = parse_integer(args[1]); ! } ! ! if (low > high) { ! safe_str(T(e_range), buff, bp); ! return; ! } ! ! safe_integer(get_random_long(low, high), buff, bp); } /* ARGSUSED */ *** 1_7_7.624/src/funlist.c Mon, 14 Jul 2003 09:07:25 -0500 dunemush (pennmush/c/16_funlist.c 1.3.1.1.1.5.1.2.1.1.1.1.1.4.1.2.1.2.1.19.1.2.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.1.1.12.1.14 660) --- 1_7_7.664(w)/src/funlist.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/16_funlist.c 1.3.1.1.1.5.1.2.1.1.1.1.1.4.1.2.1.2.1.19.1.2.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.1.1.12.1.14.1.2 660) *************** *** 1481,1486 **** --- 1481,1519 ---- } /* ARGSUSED */ + FUNCTION(fun_randword) + { + char *s, *r; + char sep; + int word_count, word_index; + + if (!*args[0]) + return; + + if (!delim_check(buff, bp, nargs, args, 2, &sep)) + return; + + s = trim_space_sep(args[0], sep); + word_count = do_wordcount(s, sep); + word_index = get_random_long(0, word_count - 1); + + /* Go to the start of the token we're interested in. */ + while (word_index && s) { + s = next_token(s, sep); + word_index--; + } + + if (!s || !*s) /* ran off the end of the string */ + return; + + /* Chop off the end, and copy. No length checking needed. */ + r = s; + if (s && *s) + (void) split_token(&s, sep); + safe_str(r, buff, bp); + } + + /* ARGSUSED */ FUNCTION(fun_rest) { char *p; *************** *** 2859,2865 **** reharg.buff = buff; reharg.bp = bp; ! atr_iter_get(executor, it, args[1], regrep_helper, (void *) &reharg); mush_free(reharg.re, "pcre"); if (reharg.study) mush_free(reharg.study, "pcre.extra"); --- 2892,2898 ---- reharg.buff = buff; reharg.bp = bp; ! atr_iter_get(executor, it, args[1], 0, regrep_helper, (void *) &reharg); mush_free(reharg.re, "pcre"); if (reharg.study) mush_free(reharg.study, "pcre.extra"); *** 1_7_7.624/src/fundb.c Fri, 05 Sep 2003 20:59:37 -0500 dunemush (pennmush/c/17_fundb.c 1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.7.1.3.1.3.1.3.1.2.1.2.1.3.2.1.2.1.2.1.1.1.1.4.1.1.1.1.1.1.1.1.1.1.1.3.1.1.2.2.2.1.1.1.1.1.1.19 660) --- 1_7_7.664(w)/src/fundb.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/17_fundb.c 1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.7.1.3.1.3.1.3.1.2.1.2.1.3.2.1.2.1.2.1.1.1.1.4.1.1.1.1.1.1.1.1.1.1.1.3.1.1.2.2.2.1.1.1.1.1.1.22 660) *************** *** 125,131 **** lh.first = 1; lh.buff = buff; lh.bp = bp; ! (void) atr_iter_get(executor, thing, pattern, lattr_helper, &lh); } /* ARGSUSED */ --- 125,131 ---- lh.first = 1; lh.buff = buff; lh.bp = bp; ! (void) atr_iter_get(executor, thing, pattern, 0, lattr_helper, &lh); } /* ARGSUSED */ *************** *** 437,442 **** --- 437,444 ---- return; } safe_str(privs_to_letters(attr_privs, AL_FLAGS(a)), buff, bp); + if (atr_sub_branch(a)) + safe_chr('`', buff, bp); } else { /* Object flags, visible to all */ safe_str(unparse_flags(thing, executor), buff, bp); *************** *** 1501,1512 **** /* find out what we're matching in relation to */ looker = match_thing(executor, args[0]); if (!GoodObject(looker)) { - notify(executor, T("I don't see that here.")); safe_str("#-1", buff, bp); return; } if (!See_All(executor) && !controls(executor, looker)) { - notify(executor, T("Permission denied.")); safe_str("#-1", buff, bp); return; } --- 1503,1512 ---- *************** *** 1587,1596 **** else item = last_match_result(looker, args[1], pref_type, match_flags); - if (item == NOTHING) - notify(executor, T("Nothing found.")); - else if (item == AMBIGUOUS) - notify(executor, T("More than one match found.")); if (GoodObject(item) && (force_type && pref_type != NOTYPE && !(Typeof(item) == pref_type))) safe_dbref(NOTHING, buff, bp); --- 1587,1592 ---- *** 1_7_7.624/src/function.c Mon, 11 Aug 2003 16:30:36 -0500 dunemush (pennmush/c/18_function.c 1.29.1.14.1.3.1.6.1.1.1.1.1.14.1.2.1.1.1.7.1.22 660) --- 1_7_7.664(w)/src/function.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/18_function.c 1.29.1.14.1.3.1.6.1.1.1.1.1.14.1.2.1.1.1.7.1.22.1.1 660) *************** *** 409,415 **** {"QUOTA", fun_quota, 1, 1, FN_REG}, #endif {"R", fun_r, 1, 1, FN_REG}, ! {"RAND", fun_rand, 1, 1, FN_REG}, {"REGEDIT", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALL", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALLI", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, --- 409,416 ---- {"QUOTA", fun_quota, 1, 1, FN_REG}, #endif {"R", fun_r, 1, 1, FN_REG}, ! {"RAND", fun_rand, 1, 2, FN_REG}, ! {"RANDWORD", fun_randword, 1, 2, FN_REG}, {"REGEDIT", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALL", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALLI", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, *** 1_7_7.624/src/flags.c Wed, 27 Aug 2003 23:03:24 -0500 dunemush (pennmush/c/20_flags.c 1.1.1.1.1.1.1.1.1.1.1.1.1.6.1.2.1.1.1.1.1.2.2.2.2.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.3.1.9.1.2.2.1.1.2.1.56 660) --- 1_7_7.664(w)/src/flags.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/20_flags.c 1.1.1.1.1.1.1.1.1.1.1.1.1.6.1.2.1.1.1.1.1.2.2.2.2.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.3.1.9.1.2.2.1.1.2.1.56.1.2 660) *************** *** 1911,1916 **** --- 1911,1961 ---- notify(player, T("Unknown failure adding alias.")); } + /** Change a flag's alias. + * \param player the enactor. + * \param name name of the flag. + * \param letter The new alias, or an empty string to remove the alias. + */ + void + do_flag_letter(dbref player, const char *name, const char *letter) + { + FLAG *f; + FLAGSPACE *n; + + if (!God(player)) { + notify(player, T("You don't look like God.")); + return; + } + Flagspace_Lookup(n, "FLAG"); + f = match_flag_ns(n, name); + if (!f) { + notify(player, T("I don't know that flag.")); + return; + } + if (letter && *letter) { + FLAG *other; + + if (strlen(letter) > 1) { + notify(player, T("Flag characters must be single characters.")); + return; + } + + if ((other = letter_to_flagptr(n, *letter, NOTYPE))) { + notify_format(player, T("Letter conflicts with the %s flag."), + other->name); + return; + } + + f->letter = *letter; + notify_format(player, T("Letter for flag %s set to '%c'."), + f->name, *letter); + } else { /* Clear a flag */ + f->letter = '\0'; + notify_format(player, T("Letter for flag %s cleared."), f->name); + } + } + + /** Disable a flag. * \verbatim * This function implements @flag/disable. *************** *** 2065,2071 **** /** Return a list of all flags. * \param name wildcard to match against flag names, or NULL for all. * \param privs the looker, for permission checking. ! * \param which a bitmask of 0x1 (flag chars) and 0x2 (flag names)u */ char * list_all_flags(const char *ns, const char *name, dbref privs, int which) --- 2110,2116 ---- /** Return a list of all flags. * \param name wildcard to match against flag names, or NULL for all. * \param privs the looker, for permission checking. ! * \param which a bitmask of 0x1 (flag chars) and 0x2 (flag names). */ char * list_all_flags(const char *ns, const char *name, dbref privs, int which) *************** *** 2093,2103 **** switch (which) { case 0x3: if (i) ! safe_chr(' ', buf, &bp); safe_str(ptrs[i], buf, &bp); f = match_flag_ns(n, ptrs[i]); ! if (f && (f->letter != '\0')) safe_format(buf, &bp, " (%c)", f->letter); break; case 0x2: if (i) --- 2138,2152 ---- switch (which) { case 0x3: if (i) ! safe_strl(", ", 2, buf, &bp); safe_str(ptrs[i], buf, &bp); f = match_flag_ns(n, ptrs[i]); ! if (!f) ! break; ! if (f->letter != '\0') safe_format(buf, &bp, " (%c)", f->letter); + if (f->perms & F_DISABLED) + safe_str(T(" (disabled)"), buf, &bp); break; case 0x2: if (i) *** 1_7_7.624/src/filecopy.c Thu, 28 Aug 2003 11:10:52 -0500 dunemush (pennmush/c/21_filecopy.c 1.80 660) --- 1_7_7.664(w)/src/filecopy.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/21_filecopy.c 1.81 660) *************** *** 256,262 **** if (panicdb_OK) { /* panicdb */ ConcatenateFiles(options.crash_db, options.input_db); } else { /* NOTHING */ ! exit(-1); } } } --- 256,262 ---- if (panicdb_OK) { /* panicdb */ ConcatenateFiles(options.crash_db, options.input_db); } else { /* NOTHING */ ! return; } } } *** 1_7_7.624/src/extchat.c Mon, 01 Sep 2003 15:54:38 -0500 dunemush (pennmush/c/23_extchat.c 1.1.1.1.1.1.1.1.1.2.1.1.1.3.1.1.1.5.1.1.1.1.1.5.1.2.1.3.1.3.1.1.1.4.1.2.1.6.1.2.1.1.2.4.2.9.1.2.1.2.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.2.1.1.2.1.1.2.1.1.1.1.1.37.1.2 660) --- 1_7_7.664(w)/src/extchat.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/23_extchat.c 1.1.1.1.1.1.1.1.1.2.1.1.1.3.1.1.1.5.1.1.1.1.1.5.1.2.1.3.1.3.1.1.1.4.1.2.1.6.1.2.1.1.2.4.2.9.1.2.1.2.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.2.1.1.2.1.1.2.1.1.1.1.1.1.1.3 660) *************** *** 80,85 **** --- 80,88 ---- static void channel_push_buffer(CHAN *c, char *tbuf1); static void channel_shift_buffer(CHAN *c, int space_needed); static int channel_buffer_lines(CHAN *c); + static void format_channel_broadcast(CHAN *chan, CHANUSER *u, dbref victim, + int flags, const char *msg, + const char *extra); const char *chan_speak_lock = "ChanSpeakLock"; /**< Name of speak lock */ const char *chan_join_lock = "ChanJoinLock"; /**< Name of join lock */ *************** *** 111,116 **** --- 114,122 ---- {"Quiet", 'Q', CHANNEL_QUIET, CHANNEL_QUIET}, {"Open", 'o', CHANNEL_OPEN, CHANNEL_OPEN}, {"Hide_Ok", 'H', CHANNEL_CANHIDE, CHANNEL_CANHIDE}, + {"NoTitles", 'T', CHANNEL_NOTITLES, CHANNEL_NOTITLES}, + {"NoNames", 'N', CHANNEL_NONAMES, CHANNEL_NONAMES}, + {"NoCemit", 'C', CHANNEL_NOCEMIT, CHANNEL_NOCEMIT}, {NULL, '\0', 0, 0} }; *************** *** 287,292 **** --- 293,299 ---- static int load_channel(FILE * fp, CHAN *ch) { + int ret = 1; strcpy(ChanName(ch), getstring_noalloc(fp)); if (feof(fp)) return 0; *************** *** 303,310 **** ChanNumUsers(ch) = getref(fp); ChanMaxUsers(ch) = ChanNumUsers(ch); ChanUsers(ch) = NULL; ! if (ChanNumUsers(ch) > 0) ! return (ChanNumUsers(ch) = load_chanusers(fp, ch)); return 1; } --- 310,321 ---- ChanNumUsers(ch) = getref(fp); ChanMaxUsers(ch) = ChanNumUsers(ch); ChanUsers(ch) = NULL; ! if (ChanNumUsers(ch) > 0) { ! ret = load_chanusers(fp, ch); ! if (ret < 0) ! return 0; ! ChanNumUsers(ch) = ret; ! } return 1; } *************** *** 321,327 **** if (GoodObject(player) && Chan_Ok_Type(ch, player)) { user = new_user(player); if (!user) ! return 0; CUtype(user) = getref(fp); strcpy(CUtitle(user), getstring_noalloc(fp)); CUnext(user) = NULL; --- 332,338 ---- if (GoodObject(player) && Chan_Ok_Type(ch, player)) { user = new_user(player); if (!user) ! return -1; CUtype(user) = getref(fp); strcpy(CUtitle(user), getstring_noalloc(fp)); CUnext(user) = NULL; *************** *** 876,881 **** --- 887,893 ---- do_channel(dbref player, const char *name, const char *target, const char *com) { CHAN *chan = NULL; + CHANUSER *u; dbref victim; if (!name && !*name) { *************** *** 973,990 **** notify_format(player, T("CHAT: You join %s to channel <%s>."), Name(victim), ChanName(chan)); ! if (!Channel_Quiet(chan) && !DarkLegal(victim)) ! channel_broadcast(chan, victim, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has joined this channel."), ChanName(chan), ! Name(victim)); ! ChanNumUsers(chan)++; ! } else { ! notify_format(player, ! T("%s is already on channel <%s>."), Name(victim), ! ChanName(chan)); } - return; } else if (!strcasecmp("off", com) || !strcasecmp("leave", com)) { /* You must control either the victim or the channel */ if (!controls(player, victim) && !Chan_Can_Modify(chan, player)) { notify(player, T("Invalid target.")); --- 985,1004 ---- notify_format(player, T("CHAT: You join %s to channel <%s>."), Name(victim), ChanName(chan)); ! u = onchannel(victim, chan); ! if (!Channel_Quiet(chan) && !DarkLegal(victim)) { ! format_channel_broadcast(chan, u, victim, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has joined this channel."), NULL); ! ChanNumUsers(chan)++; ! } else { ! notify_format(player, ! T("%s is already on channel <%s>."), Name(victim), ! ChanName(chan)); ! } ! return; } } else if (!strcasecmp("off", com) || !strcasecmp("leave", com)) { + char title[CU_TITLE_LEN]; /* You must control either the victim or the channel */ if (!controls(player, victim) && !Chan_Can_Modify(chan, player)) { notify(player, T("Invalid target.")); *************** *** 994,1004 **** notify(player, T("Guests may not leave channels.")); return; } ! if (remove_user_by_dbref(victim, chan)) { ! if (!Channel_Quiet(chan) && !DarkLegal(victim)) ! channel_broadcast(chan, victim, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has left this channel."), ChanName(chan), ! Name(victim)); notify_format(victim, T("CHAT: %s removes you from channel <%s>."), Name(player), ChanName(chan)); --- 1008,1021 ---- notify(player, T("Guests may not leave channels.")); return; } ! u = onchannel(victim, chan); ! strcpy(title, (u &&CUtitle(u)) ? CUtitle(u) : ""); ! if (remove_user(u, chan)) { ! if (!Channel_Quiet(chan) && !DarkLegal(victim)) { ! format_channel_broadcast(chan, NULL, victim, ! CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has left this channel."), title); ! } notify_format(victim, T("CHAT: %s removes you from channel <%s>."), Name(player), ChanName(chan)); *************** *** 1020,1031 **** channel_join_self(dbref player, const char *name) { CHAN *chan = NULL; if (Guest(player)) { notify(player, T("Guests are not allowed to join channels.")); return; } - switch (find_channel_partial_off(name, &chan, player)) { case CMATCH_NONE: if (find_channel_partial_on(name, &chan, player)) --- 1037,1049 ---- channel_join_self(dbref player, const char *name) { CHAN *chan = NULL; + CHANUSER *u; + if (Guest(player)) { notify(player, T("Guests are not allowed to join channels.")); return; } switch (find_channel_partial_off(name, &chan, player)) { case CMATCH_NONE: if (find_channel_partial_on(name, &chan, player)) *************** *** 1062,1071 **** } if (insert_user_by_dbref(player, chan)) { notify_format(player, T("CHAT: You join channel <%s>."), ChanName(chan)); if (!Channel_Quiet(chan) && !DarkLegal(player)) ! channel_broadcast(chan, player, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has joined this channel."), ChanName(chan), ! Name(player)); ChanNumUsers(chan)++; } else { /* Should never happen */ --- 1080,1089 ---- } if (insert_user_by_dbref(player, chan)) { notify_format(player, T("CHAT: You join channel <%s>."), ChanName(chan)); + u = onchannel(player, chan); if (!Channel_Quiet(chan) && !DarkLegal(player)) ! format_channel_broadcast(chan, u, player, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has joined this channel."), NULL); ChanNumUsers(chan)++; } else { /* Should never happen */ *************** *** 1079,1084 **** --- 1097,1105 ---- channel_leave_self(dbref player, const char *name) { CHAN *chan = NULL; + CHANUSER *u; + char title[CU_TITLE_LEN]; + if (Guest(player)) { notify(player, T("Guests are not allowed to leave channels.")); return; *************** *** 1096,1106 **** notify(player, T("CHAT: I don't know which channel you mean.")); return; } ! if (remove_user_by_dbref(player, chan)) { if (!Channel_Quiet(chan) && !DarkLegal(player)) ! channel_broadcast(chan, player, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has left this channel."), ChanName(chan), ! Name(player)); notify_format(player, T("CHAT: You leave channel <%s>."), ChanName(chan)); } else { /* Should never happen */ --- 1117,1128 ---- notify(player, T("CHAT: I don't know which channel you mean.")); return; } ! u = onchannel(player, chan); ! strcpy(title, (u &&CUtitle(u)) ? CUtitle(u) : ""); ! if (remove_user(u, chan)) { if (!Channel_Quiet(chan) && !DarkLegal(player)) ! format_channel_broadcast(chan, NULL, player, CB_CHECKQUIET | CB_PRESENCE, ! T("<%s> %s has left this channel."), title); notify_format(player, T("CHAT: You leave channel <%s>."), ChanName(chan)); } else { /* Should never happen */ *************** *** 1196,1207 **** { CHANUSER *u; const char *gap; char *title; int canhear; if (!Chan_Ok_Type(chan, player)) { notify_format(player, ! T("Sorry, you're not the right type to be on channel <%s>."), ChanName(chan)); return; } --- 1218,1232 ---- { CHANUSER *u; const char *gap; + const char *someone = "Someone"; char *title; + const char *name; int canhear; if (!Chan_Ok_Type(chan, player)) { notify_format(player, ! T ! ("Sorry, you're not the right type to be on channel <%s>."), ChanName(chan)); return; } *************** *** 1232,1241 **** return; } ! if (u &&CUtitle(u) && *CUtitle(u)) title = CUtitle(u); else title = NULL; /* figure out what kind of message we have */ gap = " "; --- 1257,1272 ---- return; } ! if (!Channel_NoTitles(chan) && u &&CUtitle(u) && *CUtitle(u)) title = CUtitle(u); else title = NULL; + if (Channel_NoNames(chan)) + name = NULL; + else + name = accented_name(player); + if (!title && !name) + name = someone; /* figure out what kind of message we have */ gap = " "; *************** *** 1247,1268 **** arg1 = arg1 + 1; channel_broadcast(chan, player, 0, "<%s> %s%s%s%s%s%s", ChanName(chan), title ? title : "", title ? ANSI_NORMAL : "", ! title ? " " : "", accented_name(player), gap, arg1); if (!canhear) ! notify_format(player, T("To channel %s: %s%s%s"), ChanName(chan), ! accented_name(player), gap, arg1); break; default: if (CHAT_STRIP_QUOTE && (*arg1 == SAY_TOKEN)) arg1 = arg1 + 1; channel_broadcast(chan, player, 0, T("<%s> %s%s%s%s says, \"%s\""), ChanName(chan), title ? title : "", ! title ? ANSI_NORMAL : "", title ? " " : "", ! accented_name(player), arg1); if (!canhear) notify_format(player, ! T("To channel %s: %s says, \"%s\""), ChanName(chan), ! accented_name(player), arg1); break; } --- 1278,1302 ---- arg1 = arg1 + 1; channel_broadcast(chan, player, 0, "<%s> %s%s%s%s%s%s", ChanName(chan), title ? title : "", title ? ANSI_NORMAL : "", ! (title && name) ? " " : "", name ? name : "", gap, arg1); if (!canhear) ! notify_format(player, T("To channel %s: %s%s%s%s%s%s"), ChanName(chan), ! title ? title : "", title ? ANSI_NORMAL : "", ! (title && name) ? " " : "", name ? name : "", gap, arg1); break; default: if (CHAT_STRIP_QUOTE && (*arg1 == SAY_TOKEN)) arg1 = arg1 + 1; channel_broadcast(chan, player, 0, T("<%s> %s%s%s%s says, \"%s\""), ChanName(chan), title ? title : "", ! title ? ANSI_NORMAL : "", (title && name) ? " " : "", ! name ? name : "", arg1); if (!canhear) notify_format(player, ! T("To channel %s: %s%s%s%s says, \"%s\""), ! ChanName(chan), title ? title : "", ! title ? ANSI_NORMAL : "", (title && name) ? " " : "", ! name ? name : "", arg1); break; } *************** *** 1303,1315 **** } if (!Chan_Ok_Type(chan, player)) { notify_format(player, ! T("Sorry, you're not the right type to be on channel <%s>."), ChanName(chan)); return; } ! if (!Chan_Can_Speak(chan, player)) { notify_format(player, ! T("Sorry, you're not allowed to speak on channel <%s>."), ChanName(chan)); return; } --- 1337,1350 ---- } if (!Chan_Ok_Type(chan, player)) { notify_format(player, ! T ! ("Sorry, you're not the right type to be on channel <%s>."), ChanName(chan)); return; } ! if (!Chan_Can_Cemit(chan, player)) { notify_format(player, ! T("Sorry, you're not allowed to @cemit on channel <%s>."), ChanName(chan)); return; } *************** *** 1343,1354 **** /** Administrative channel commands. * \verbatim * This is one of top-level functions for @channel. This one handles ! * the /add, /delete, /rename, /priv, and /quiet switches. * \endverbatim * \param player the enactor. * \param name the name of the channel. * \param perms the permissions to set on an added/priv'd channel, the newname for a renamed channel, or on/off for a quieted channel. ! * \param flag switch indicator: 0=add, 1=delete, 2=rename, 3=priv, 4=quiet */ void do_chan_admin(dbref player, char *name, const char *perms, int flag) --- 1378,1389 ---- /** Administrative channel commands. * \verbatim * This is one of top-level functions for @channel. This one handles ! * the /add, /delete, /rename, and /priv switches. * \endverbatim * \param player the enactor. * \param name the name of the channel. * \param perms the permissions to set on an added/priv'd channel, the newname for a renamed channel, or on/off for a quieted channel. ! * \param flag switch indicator: 0=add, 1=delete, 2=rename, 3=priv */ void do_chan_admin(dbref player, char *name, const char *perms, int flag) *************** *** 1509,1527 **** T("Permissions on channel <%s> changed."), ChanName(chan)); } break; - case 4: - /* Quiet a channel */ - if (!Chan_Can_Modify(chan, player)) { - notify(player, T("Permission denied. Use @channel/mute =")); - return; - } - if (abs(yesno(perms))) - ChanType(chan) |= CHANNEL_QUIET; - else - ChanType(chan) &= ~CHANNEL_QUIET; - notify_format(player, - T("Quiet status on channel <%s> changed."), ChanName(chan)); - break; } } --- 1544,1549 ---- *************** *** 1653,1659 **** CUtype(u) |= CU_HIDE; if (!silent) notify_format(player, ! T("You no longer appear on channel <%s>'s who list."), ChanName(c)); } } else { --- 1675,1682 ---- CUtype(u) |= CU_HIDE; if (!silent) notify_format(player, ! T ! ("You no longer appear on channel <%s>'s who list."), ChanName(c)); } } else { *************** *** 1670,1676 **** CUtype(u) |= CU_GAG; if (!silent) notify_format(player, ! T("You will no longer hear messages on channel <%s>."), ChanName(c)); } else { CUtype(u) &= ~CU_GAG; --- 1693,1700 ---- CUtype(u) |= CU_GAG; if (!silent) notify_format(player, ! T ! ("You will no longer hear messages on channel <%s>."), ChanName(c)); } else { CUtype(u) &= ~CU_GAG; *************** *** 2447,2460 **** { CHAN *c; CHANUSER *u; for (c = channels; c; c = c->next) { u = onchannel(player, c); if (u) { if (!Channel_Quiet(c) && (Channel_Admin(c) || Channel_Wizard(c) ! || (!Chanuser_Hide(u) && !Dark(player)))) ! channel_broadcast(c, player, CB_CHECKQUIET | CB_PRESENCE, "<%s> %s", ! ChanName(c), msg); CUtype(u) &= ~CU_GAG; } } --- 2471,2490 ---- { CHAN *c; CHANUSER *u; + char buff[BUFFER_LEN], *bp; for (c = channels; c; c = c->next) { u = onchannel(player, c); if (u) { if (!Channel_Quiet(c) && (Channel_Admin(c) || Channel_Wizard(c) ! || (!Chanuser_Hide(u) && !Dark(player)))) { ! bp = buff; ! ! safe_format(buff, &bp, "<%s> %s", "%s", msg); ! *bp = '\0'; ! format_channel_broadcast(c, u, player, CB_CHECKQUIET | CB_PRESENCE, ! buff, NULL); ! } CUtype(u) &= ~CU_GAG; } } *************** *** 2639,2648 **** do_chan_admin(player, arg_left, arg_right, 2); else if (SW_ISSET(sw, SWITCH_PRIVS)) do_chan_admin(player, arg_left, arg_right, 3); else if (SW_ISSET(sw, SWITCH_QUIET)) ! do_chan_admin(player, arg_left, arg_right, 4); else if (SW_ISSET(sw, SWITCH_NOISY)) ! do_chan_admin(player, arg_left, "n", 4); else if (SW_ISSET(sw, SWITCH_DECOMPILE)) do_chan_decompile(player, arg_left, SW_ISSET(sw, SWITCH_BRIEF)); else if (SW_ISSET(sw, SWITCH_DESCRIBE)) --- 2669,2680 ---- do_chan_admin(player, arg_left, arg_right, 2); else if (SW_ISSET(sw, SWITCH_PRIVS)) do_chan_admin(player, arg_left, arg_right, 3); + else if (SW_ISSET(sw, SWITCH_RECALL)) + do_chan_recall(player, arg_left, arg_right, SW_ISSET(sw, SWITCH_QUIET)); else if (SW_ISSET(sw, SWITCH_QUIET)) ! do_chan_admin(player, arg_left, "quiet", 3); else if (SW_ISSET(sw, SWITCH_NOISY)) ! do_chan_admin(player, arg_left, "!quiet", 3); else if (SW_ISSET(sw, SWITCH_DECOMPILE)) do_chan_decompile(player, arg_left, SW_ISSET(sw, SWITCH_BRIEF)); else if (SW_ISSET(sw, SWITCH_DESCRIBE)) *************** *** 2667,2674 **** do_chan_user_flags(player, arg_left, "n", 2, 0); else if (SW_ISSET(sw, SWITCH_WHAT)) do_chan_what(player, arg_left); - else if (SW_ISSET(sw, SWITCH_RECALL)) - do_chan_recall(player, arg_left, arg_right); else if (SW_ISSET(sw, SWITCH_BUFFER)) do_chan_buffer(player, arg_left, arg_right); else --- 2699,2704 ---- *************** *** 2896,2904 **** * \param player the enactor. * \param name the name of the channel. * \param lines a string given the number of lines to recall (default all). */ void ! do_chan_recall(dbref player, const char *name, const char *lines) { CHAN *chan; CHANUSER *u; --- 2926,2935 ---- * \param player the enactor. * \param name the name of the channel. * \param lines a string given the number of lines to recall (default all). + * \param quiet if true, don't show timestamps. */ void ! do_chan_recall(dbref player, const char *name, const char *lines, int quiet) { CHAN *chan; CHANUSER *u; *************** *** 2967,2982 **** memcpy(&size, p, sizeof size); p += sizeof size; memcpy(×tamp, p, sizeof timestamp); - stamp = show_time(timestamp, 0); p += sizeof timestamp; memcpy(tbuf1, p, size + 1); ! notify_format(player, "[%s] %s", stamp, tbuf1); p += size + 1; } notify(player, T("CHAT: End recall")); if (!lines || !*lines) notify_format(player, ! T("CHAT: To recall the entire buffer, use @chan/recall %s=0"), ChanName(chan)); } --- 2998,3018 ---- memcpy(&size, p, sizeof size); p += sizeof size; memcpy(×tamp, p, sizeof timestamp); p += sizeof timestamp; memcpy(tbuf1, p, size + 1); ! if (quiet) { ! notify(player, tbuf1); ! } else { ! stamp = show_time(timestamp, 0); ! notify_format(player, "[%s] %s", stamp, tbuf1); ! } p += size + 1; } notify(player, T("CHAT: End recall")); if (!lines || !*lines) notify_format(player, ! T ! ("CHAT: To recall the entire buffer, use @chan/recall %s=0"), ChanName(chan)); } *************** *** 3041,3046 **** --- 3077,3100 ---- } } + static void + format_channel_broadcast(CHAN *chan, CHANUSER *u, dbref victim, int flags, + const char *msg, const char *extra) + { + const char *title = NULL; + if (extra && *extra) + title = extra; + else if (u &&CUtitle(u)) + title = CUtitle(u); + + if (Channel_NoNames(chan)) { + if (Channel_NoTitles(chan) || !title) + channel_broadcast(chan, victim, flags, msg, ChanName(chan), "Someone"); + else + channel_broadcast(chan, victim, flags, msg, ChanName(chan), title); + } else + channel_broadcast(chan, victim, flags, msg, ChanName(chan), Name(victim)); + } #endif /* CHAT_SYSTEM */ *** 1_7_7.624/src/destroy.c Tue, 13 May 2003 12:53:40 -0500 dunemush (pennmush/c/24_destroy.c 1.24.2.2.1.3.1.1.1.1.1.1.1.4.1.1.1.2 660) --- 1_7_7.664(w)/src/destroy.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/24_destroy.c 1.24.2.2.1.3.1.1.1.1.1.1.1.4.1.1.1.1.1.3 660) *************** *** 726,731 **** --- 726,732 ---- Type(thing) = TYPE_GARBAGE; destroy_flag_bitmask(Flags(thing)); Flags(thing) = NULL; + Powers(thing) = 0; Location(thing) = NOTHING; set_name(thing, "Garbage"); Exits(thing) = NOTHING; *************** *** 1112,1118 **** * an invalid dbref, change its ownership to God. */ if (!IsGarbage(thing)) ! atr_iter_get(GOD, thing, NULL, attribute_owner_helper, NULL); } } } --- 1113,1119 ---- * an invalid dbref, change its ownership to God. */ if (!IsGarbage(thing)) ! atr_iter_get(GOD, thing, "**", 0, attribute_owner_helper, NULL); } } } *** 1_7_7.624/src/cque.c Mon, 28 Apr 2003 22:37:00 -0500 dunemush (pennmush/c/28_cque.c 1.36.1.5.1.1.1.1.1.1.1.2.1.6.1.9 660) --- 1_7_7.664(w)/src/cque.c Mon, 29 Sep 2003 16:42:31 -0500 dunemush (pennmush/c/28_cque.c 1.36.1.5.1.1.1.1.1.1.1.2.1.6.1.10 660) *************** *** 667,673 **** if (aname) (void) atr_clr(thing, aname, GOD); else ! atr_iter_get(GOD, thing, "*", drain_helper, NULL); } /* If @notify and count was higher than the number of queue entries, --- 667,673 ---- if (aname) (void) atr_clr(thing, aname, GOD); else ! atr_iter_get(GOD, thing, "**", 0, drain_helper, NULL); } /* If @notify and count was higher than the number of queue entries, *** 1_7_7.624/src/command.c Mon, 01 Sep 2003 23:41:11 -0500 dunemush (pennmush/c/36_command.c 1.56.1.1.1.1.1.1.1.2.1.1.1.1.1.5.1.2.1.1.1.1.1.2.1.3.1.10.1.1.3.20 660) --- 1_7_7.664(w)/src/command.c Mon, 29 Sep 2003 16:42:30 -0500 dunemush (pennmush/c/36_command.c 1.56.1.1.1.1.1.1.1.2.1.1.1.1.1.5.1.2.1.1.1.1.1.2.1.3.1.10.1.1.3.22 660) *************** *** 79,85 **** {"@CEMIT", "NOEVAL NOISY", cmd_cemit, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, {"@CHANNEL", ! "LIST ADD DELETE RENAME NAME PRIVS QUIET NOISY DECOMPILE DESCRIBE CHOWN WIPE MUTE UNMUTE GAG UNGAG HIDE UNHIDE WHAT TITLE BRIEF RECALL BUFFER", cmd_channel, CMD_T_ANY | CMD_T_SWITCHES | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, {"@CHAT", NULL, cmd_chat, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, --- 79,85 ---- {"@CEMIT", "NOEVAL NOISY", cmd_cemit, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, {"@CHANNEL", ! "LIST ADD DELETE RENAME NAME PRIVS QUIET NOISY DECOMPILE DESCRIBE CHOWN WIPE MUTE UNMUTE GAG UNGAG HIDE UNHIDE WHAT TITLE BRIEF RECALL BUFFER SET", cmd_channel, CMD_T_ANY | CMD_T_SWITCHES | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, {"@CHAT", NULL, cmd_chat, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, *************** *** 139,145 **** {"@FIND", NULL, cmd_find, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@FIRSTEXIT", NULL, cmd_firstexit, CMD_T_ANY, 0, 0}, ! {"@FLAG", "ADD LIST RESTRICT DELETE ALIAS DISABLE ENABLE", cmd_flag, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@FORCE", "NOEVAL", cmd_force, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, --- 139,145 ---- {"@FIND", NULL, cmd_find, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@FIRSTEXIT", NULL, cmd_firstexit, CMD_T_ANY, 0, 0}, ! {"@FLAG", "ADD LETTER LIST RESTRICT DELETE ALIAS DISABLE ENABLE", cmd_flag, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@FORCE", "NOEVAL", cmd_force, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, *** 1_7_7.624/src/cmds.c Mon, 01 Sep 2003 22:38:06 -0500 dunemush (pennmush/c/37_cmds.c 1.33.1.1.1.2.1.2.2.3.1.1.1.2.1.1.1.3.1.8.1.1.2.2.2.20.1.3 660) --- 1_7_7.664(w)/src/cmds.c Mon, 29 Sep 2003 16:42:30 -0500 dunemush (pennmush/c/37_cmds.c 1.33.1.1.1.2.1.2.2.3.1.1.1.2.1.1.1.3.1.8.1.1.2.2.2.20.1.3.1.2 660) *************** *** 249,263 **** COMMAND (cmd_entrances) { if (SW_ISSET(sw, SWITCH_EXITS)) ! do_entrances(player, arg_left, args_right, 1); else if (SW_ISSET(sw, SWITCH_THINGS)) ! do_entrances(player, arg_left, args_right, 2); else if (SW_ISSET(sw, SWITCH_PLAYERS)) ! do_entrances(player, arg_left, args_right, 3); else if (SW_ISSET(sw, SWITCH_ROOMS)) ! do_entrances(player, arg_left, args_right, 4); else ! do_entrances(player, arg_left, args_right, 0); } COMMAND (cmd_eunlock) { --- 249,263 ---- COMMAND (cmd_entrances) { if (SW_ISSET(sw, SWITCH_EXITS)) ! do_entrances(player, arg_left, args_right, ENT_EXITS); else if (SW_ISSET(sw, SWITCH_THINGS)) ! do_entrances(player, arg_left, args_right, ENT_THINGS); else if (SW_ISSET(sw, SWITCH_PLAYERS)) ! do_entrances(player, arg_left, args_right, ENT_PLAYERS); else if (SW_ISSET(sw, SWITCH_ROOMS)) ! do_entrances(player, arg_left, args_right, ENT_ROOMS); else ! do_entrances(player, arg_left, args_right, ENT_ALL); } COMMAND (cmd_eunlock) { *************** *** 287,292 **** --- 287,294 ---- do_flag_disable(player, arg_left); else if (SW_ISSET(sw, SWITCH_ENABLE)) do_flag_enable(player, arg_left); + else if (SW_ISSET(sw, SWITCH_LETTER)) + do_flag_letter(player, arg_left, args_right[1]); else do_flag_info("FLAG", player, arg_left); } *** 1_7_7.624/src/bsd.c Thu, 04 Sep 2003 17:27:46 -0500 dunemush (pennmush/c/38_bsd.c 1.58.1.11.1.2.1.5.1.7.1.14.1.13.1.9.1.4.1.2.1.12.1.1.1.1.1.2.1.1.1.13.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.8.2.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.24.1.8.1.2 660) --- 1_7_7.664(w)/src/bsd.c Mon, 29 Sep 2003 16:42:30 -0500 dunemush (pennmush/c/38_bsd.c 1.58.1.11.1.2.1.5.1.7.1.14.1.13.1.9.1.4.1.2.1.12.1.1.1.1.1.2.1.1.1.13.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.8.2.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.2 660) *************** *** 1014,1025 **** #endif if (!restarting) { sock = make_socket(port, NULL, NULL, MUSH_IP_ADDR); ! maxd = sock + 1; #ifdef HAS_OPENSSL if (sslport) { sslsock = make_socket(sslport, NULL, NULL, MUSH_IP_ADDR); ssl_master_socket = ssl_setup_socket(sslsock); ! maxd = sslsock + 1; } #endif } --- 1014,1027 ---- #endif if (!restarting) { sock = make_socket(port, NULL, NULL, MUSH_IP_ADDR); ! if (sock >= maxd) ! maxd = sock + 1; #ifdef HAS_OPENSSL if (sslport) { sslsock = make_socket(sslport, NULL, NULL, MUSH_IP_ADDR); ssl_master_socket = ssl_setup_socket(sslsock); ! if (sslsock >= maxd) ! maxd = sslsock + 1; } #endif } *************** *** 4697,4703 **** } sock = getref(f); ! maxd = getref(f); while ((val = getref(f)) != 0) { ndescriptors++; d = (DESC *) mush_malloc(sizeof(DESC), "descriptor"); --- 4699,4708 ---- } sock = getref(f); ! val = getref(f); ! if (val > maxd) ! maxd = val; ! while ((val = getref(f)) != 0) { ndescriptors++; d = (DESC *) mush_malloc(sizeof(DESC), "descriptor"); *** 1_7_7.624/src/attrib.c Wed, 03 Sep 2003 22:39:22 -0500 dunemush (pennmush/c/40_attrib.c 1.15.1.2.1.5.1.1.1.3.1.3.1.2.1.2.1.2.2.1.1.2.1.2.1.2.1.1.1.3.1.1.1.1.1.1.3.29 660) --- 1_7_7.664(w)/src/attrib.c Mon, 29 Sep 2003 16:42:30 -0500 dunemush (pennmush/c/40_attrib.c 1.15.1.2.1.5.1.1.1.3.1.3.1.2.1.2.1.2.2.1.1.2.1.2.1.2.1.1.1.3.1.1.1.1.1.1.3.36 660) *************** *** 46,51 **** --- 46,64 ---- /** Table of attribute flags. */ extern PRIV attr_privs[]; + /** A flag to show if we're in the middle of a @wipe (this changes + * behaviour for atr_clr()). Yes, this is gross and ugly, but it + * seemed like a better idea than propogating a signature changes + * for atr_clr() and do_set_atr() through the entire codebase. If + * you come up with a better way, PLEASE fix this... + */ + int we_are_wiping; + + /** A string to hold the name of a missing prefix branch, set by + * can_write_attr_internal. Again, gross and ugly. Please fix. + */ + static char missing_name[ATTRIBUTE_NAME_LIMIT + 1]; + /*======================================================================*/ /** How many attributes go in a "page" of attribute memory? */ *************** *** 79,85 **** /** Decide if a name is valid for an attribute. * A good attribute name is at least one character long, no more than * ATTRIBUTE_NAME_LIMIT characters long, and every character is a ! * valid character. * \param s a string to test for validity as an attribute name. */ int --- 92,99 ---- /** Decide if a name is valid for an attribute. * A good attribute name is at least one character long, no more than * ATTRIBUTE_NAME_LIMIT characters long, and every character is a ! * valid character. An attribute name may not start or end with a backtick. ! * An attribute name may not contain multiple consecutive backticks. * \param s a string to test for validity as an attribute name. */ int *************** *** 89,97 **** --- 103,117 ---- int len = 0; if (!s || !*s) return 0; + if (*s == '`') + return 0; + if (strstr(s, "``")) + return 0; for (a = (const unsigned char *) s; *a; a++, len++) if (!atr_name_table[*a]) return 0; + if (*(s + len - 1) == '`') + return 0; return len <= ATTRIBUTE_NAME_LIMIT; } *************** *** 105,110 **** --- 125,155 ---- return aname_hash_lookup(string); } + /** Find the first attribute branching off the specified attribute. + * \param branch the attribute to look under + */ + ATTR * + atr_sub_branch(ATTR *branch) + { + char const *name, *n2; + size_t len; + + name = AL_NAME(branch); + len = strlen(name); + for (branch = AL_NEXT(branch); branch; branch = AL_NEXT(branch)) { + n2 = AL_NAME(branch); + if (strlen(n2) <= len) + return NULL; + if (n2[len] == '`') { + if (!strncmp(n2, name, len)) + return branch; + else + return NULL; + } + } + return NULL; + } + /** Convert a string of attribute flags to a bitmask. * Given a space-separated string of attribute flags, look them up * and return a bitmask of them if player is permitted to use *************** *** 127,132 **** --- 172,188 ---- return f; } + /** Convert an attribute flag bitmask into a list of the full + * names of the flags. + * \param flags the attribute flags to display. + * \return a pointer to a static buffer with the full names of the flags. + */ + const char * + atrflag_to_string(int mask) + { + return privs_to_string(attr_privs, mask); + } + /** Add an attribute to an object, dangerously. * This is a stripped down version of atr_add, without duplicate checking, * permissions checking, attribute count checking, or auto-ODARKing. *************** *** 333,338 **** --- 389,395 ---- /** Remove an attribute from an object. * This function clears an attribute from an object. + * Permission is denied if the attribute is a branch, not a leaf. * \param thing object to clear attribute from. * \param atr name of attribute to remove. * \param player enactor attempting to remove attribute. *************** *** 340,347 **** int atr_clr(dbref thing, char const *atr, dbref player) { ! ATTR *ptr, **prev; int comp = 0; prev = &List(thing); ptr = *prev; --- 397,405 ---- int atr_clr(dbref thing, char const *atr, dbref player) { ! ATTR *ptr, **prev, *sub; int comp = 0; + size_t len; prev = &List(thing); ptr = *prev; *************** *** 358,363 **** --- 416,426 ---- if (!Can_Write_Attr(player, thing, ptr)) return -1; + len = strlen(AL_NAME(ptr)); + sub = atr_sub_branch(ptr); + if (!we_are_wiping && sub) + return -1; + if (!IsPlayer(thing) && !(AL_FLAGS(ptr) & AF_NODUMP)) ModTime(thing) = mudtime; *************** *** 371,376 **** --- 434,459 ---- AL_FLAGS(ptr) = 0; atr_free_list = ptr; AttrCount(thing)--; + + if (we_are_wiping && sub) { + while (*prev != sub) + prev = &AL_NEXT(*prev); + ptr = *prev; + while (ptr && strlen(AL_NAME(ptr)) > len && AL_NAME(ptr)[len] == '`') { + *prev = AL_NEXT(ptr); + + if (ptr->data) + chunk_delete(ptr->data); + st_delete(AL_NAME(ptr), &atr_names); + + AL_NEXT(ptr) = atr_free_list; + AL_FLAGS(ptr) = 0; + atr_free_list = ptr; + AttrCount(thing)--; + + ptr = *prev; + } + } return 1; } *************** *** 380,479 **** * matches or NULL. This is a pointer to an attribute structure, not * to the value of the attribute, so the value is usually accessed * through atr_value() or safe_atr_value(). ! * \param thing the object containing the attribute. ! * \param atr the name of the attribute. * \return pointer to the attribute structure retrieved, or NULL. */ ATTR * ! atr_get(dbref thing, char const *atr) { ! ATTR *ptr; int parent_depth; ! dbref temp; dbref ancestor; int comp; ! if (thing == NOTHING || !good_atr_name(atr)) return NULL; ! ancestor = Ancestor_Parent(thing); ! for (parent_depth = 0, temp = thing; ! parent_depth < MAX_PARENTS && temp != NOTHING; ! parent_depth++, temp = Parent(temp)) { ! /* If the ancestor of the object is in its explict parent chain, ! * we use it there, and don't check the ancestor later ! */ ! if (temp == ancestor) ! ancestor = NOTHING; ! for (ptr = List(temp); ptr; ptr = AL_NEXT(ptr)) { ! comp = strcoll(atr, AL_NAME(ptr)); ! if (comp < 0) ! break; ! if (comp == 0) { ! if (temp == thing || !(AL_FLAGS(ptr) & AF_PRIVATE)) ! return ptr; ! else ! break; ! } ! } ! } ! /* If we have a valid ancestor, search it as well */ ! if (GoodObject(ancestor)) { ! for (parent_depth = 0, temp = ancestor; ! parent_depth < MAX_PARENTS && temp != NOTHING; ! parent_depth++, temp = Parent(temp)) { ! for (ptr = List(temp); ptr; ptr = AL_NEXT(ptr)) { ! comp = strcoll(atr, AL_NAME(ptr)); ! if (comp < 0) ! break; ! if (comp == 0) { ! if (temp == thing || !(AL_FLAGS(ptr) & AF_PRIVATE)) ! return ptr; ! else ! break; } } - } - } ! /* Perhaps we should try the alias */ ! ptr = atr_match(atr); ! if (!ptr || !strcmp(atr, AL_NAME(ptr))) ! return NULL; ! atr = AL_NAME(ptr); ! ! for (parent_depth = 0, temp = thing; ! parent_depth < MAX_PARENTS && temp != NOTHING; ! parent_depth++, temp = Parent(temp)) { ! for (ptr = List(temp); ptr; ptr = AL_NEXT(ptr)) { ! comp = strcoll(atr, AL_NAME(ptr)); ! if (comp < 0) ! break; ! if (comp == 0) { ! if (temp == thing || !(AL_FLAGS(ptr) & AF_PRIVATE)) ! return ptr; ! else ! break; ! } ! } ! } ! /* If we have a valid ancestor, search it as well */ ! if (GoodObject(ancestor)) { ! for (parent_depth = 0, temp = ancestor; ! parent_depth < MAX_PARENTS && temp != NOTHING; ! parent_depth++, temp = Parent(temp)) { ! for (ptr = List(temp); ptr; ptr = AL_NEXT(ptr)) { ! comp = strcoll(atr, AL_NAME(ptr)); if (comp < 0) break; if (comp == 0) { ! if (temp == thing || !(AL_FLAGS(ptr) & AF_PRIVATE)) ! return ptr; else break; } } } } return NULL; --- 463,553 ---- * matches or NULL. This is a pointer to an attribute structure, not * to the value of the attribute, so the value is usually accessed * through atr_value() or safe_atr_value(). ! * \param obj the object containing the attribute. ! * \param atrname the name of the attribute. * \return pointer to the attribute structure retrieved, or NULL. */ ATTR * ! atr_get(dbref obj, char const *atrname) { ! static char name[ATTRIBUTE_NAME_LIMIT + 1]; ! char *p; ! ATTR *atr; int parent_depth; ! dbref target; dbref ancestor; int comp; ! if (obj == NOTHING || !good_atr_name(atrname)) return NULL; ! /* First try given name, then try alias match. */ ! strcpy(name, atrname); ! for (;;) { ! /* Hunt through the parents/ancestor chain... */ ! ancestor = Ancestor_Parent(obj); ! target = obj; ! parent_depth = 0; ! while (parent_depth < MAX_PARENTS && GoodObject(target)) { ! /* If the ancestor of the object is in its explict parent chain, ! * we use it there, and don't check the ancestor later. ! */ ! if (target == ancestor) ! ancestor = NOTHING; ! atr = List(target); ! ! /* If we're looking at a parent/ancestor, then we ! * need to check the branch path for privacy... */ ! if (target != obj) { ! for (p = strchr(name, '`'); p; p = strchr(p + 1, '`')) { ! *p = '\0'; ! while (atr) { ! comp = strcoll(name, AL_NAME(atr)); ! if (comp < 0) { ! *p = '`'; ! goto continue_target; ! } ! if (comp == 0) ! break; ! atr = AL_NEXT(atr); ! } ! if (!atr || (AL_FLAGS(atr) & AF_PRIVATE)) { ! *p = '`'; ! goto continue_target; ! } ! *p = '`'; } } ! /* Now actually find the attribute. */ ! while (atr) { ! comp = strcoll(name, AL_NAME(atr)); if (comp < 0) break; if (comp == 0) { ! if (target == obj || !(AL_FLAGS(atr) & AF_PRIVATE)) ! return atr; else break; } + atr = AL_NEXT(atr); + } + + continue_target: + /* Attribute wasn't on this object. Check a parent or ancestor. */ + parent_depth++; + target = Parent(target); + if (!GoodObject(target)) { + parent_depth = 0; + target = ancestor; } } + + /* Try the alias, too... */ + atr = atr_match(atrname); + if (!atr || !strcmp(name, AL_NAME(atr))) + break; + strcpy(name, AL_NAME(atr)); } return NULL; *************** *** 533,616 **** * \param player the enactor. * \param thing the object containing the attribute. * \param name the pattern to match against the attribute name. * \param func the function to call for each matching attribute. * \param args additional arguments to pass to the function. * \return the sum of the return values of the functions called. */ int ! atr_iter_get(dbref player, dbref thing, const char *name, aig_func func, ! void *args) ! { ! ATTR *ptr, *next; ! int result; ! ! result = 0; ! if (!name || !*name) ! name = "*"; ! ! if (!wildcard(name)) { ! ptr = atr_get_noparent(thing, strupper(name)); ! if (ptr && Can_Read_Attr(player, thing, ptr)) ! result = func(player, thing, name, ptr, args); ! } else { ! for (ptr = List(thing); ptr; ptr = next) { ! next = AL_NEXT(ptr); ! if (Can_Read_Attr(player, thing, ptr) && ! local_wild_match(name, AL_NAME(ptr))) ! result += func(player, thing, name, ptr, args); ! } ! } ! ! return result; ! } ! ! /** Apply a function to a set of visual attributes. ! * This function applies another function to a set of attributes on an ! * object specified by a (wildcarded) pattern to match against the ! * attribute name. ! * \param player the enactor. ! * \param thing the object containing the attribute. ! * \param name the pattern to match against the attribute name. ! * \param func the function to call for each matching attribute. ! * \param args additional arguments to pass to the function. ! * \return the sum of the return values of the functions called. ! */ ! int ! atr_iter_get_visible(dbref player, dbref thing, const char *name, aig_func func, ! void *args) { ! ATTR *ptr, *next; int result; ! int object_visual; result = 0; if (!name || !*name) name = "*"; ! object_visual = (Visual(thing) && ! (getlock(thing, Examine_Lock) == TRUE_BOOLEXP || ! (eval_lock(PLAYER_START, thing, Examine_Lock) && ! eval_lock(MASTER_ROOM, thing, Examine_Lock)))); ! ! if (!wildcard(name)) { ptr = atr_get_noparent(thing, strupper(name)); ! if (ptr && (object_visual ? Can_Read_Attr(player, thing, ptr) ! : Is_Visible_Attr(thing, ptr))) result = func(player, thing, name, ptr, args); } else { ! for (ptr = List(thing); ptr; ptr = next) { ! next = AL_NEXT(ptr); ! if ((object_visual ? Can_Read_Attr(player, thing, ptr) ! : Is_Visible_Attr(thing, ptr)) ! && local_wild_match(name, AL_NAME(ptr))) result += func(player, thing, name, ptr, args); } } return result; } - /** Free the memory associated with all attributes of an object. * This function frees all of an object's attribute memory. * This includes the memory allocated to hold the attribute's value, --- 607,650 ---- * \param player the enactor. * \param thing the object containing the attribute. * \param name the pattern to match against the attribute name. + * \param mortal only fetch mortal-visible attributes? * \param func the function to call for each matching attribute. * \param args additional arguments to pass to the function. * \return the sum of the return values of the functions called. */ int ! atr_iter_get(dbref player, dbref thing, const char *name, int mortal, ! aig_func func, void *args) { ! ATTR *ptr, **indirect; int result; ! int len; result = 0; if (!name || !*name) name = "*"; + len = strlen(name); ! if (!wildcard(name) && name[len - 1] != '`') { ptr = atr_get_noparent(thing, strupper(name)); ! if (ptr && (mortal ? Is_Visible_Attr(thing, ptr) ! : Can_Read_Attr(player, thing, ptr))) result = func(player, thing, name, ptr, args); } else { ! indirect = &List(thing); ! while (*indirect) { ! ptr = *indirect; ! if ((mortal ? Is_Visible_Attr(thing, ptr) ! : Can_Read_Attr(player, thing, ptr)) && atr_wild(name, AL_NAME(ptr))) result += func(player, thing, name, ptr, args); + if (ptr == *indirect) + indirect = &AL_NEXT(ptr); } } return result; } /** Free the memory associated with all attributes of an object. * This function frees all of an object's attribute memory. * This includes the memory allocated to hold the attribute's value, *************** *** 664,669 **** --- 698,771 ---- } } + /** Structure for keeping track of which attributes have appeared + * on children when doing command matching. */ + typedef struct used_attr { + struct used_attr *next; /**< Next attribute in list */ + char const *name; /**< The name of the attribute */ + int no_prog; /**< Was it AF_NOPROG */ + } UsedAttr; + + /** Find an attribute in the list of seen attributes. + * Since attributes are checked in collation order, the pointer to the + * list is updated to reflect the current search position. + * For efficiency of insertions, the pointer used is a trailing pointer, + * pointing at the pointer to the next used struct. + * To allow a useful return code, the pointer used is actually a pointer + * to the pointer mentioned above. Yes, I know three-star coding is bad, + * but I have good reason, here. + * \param prev the pointer to the pointer to the pointer to the next + * used attribute. + * \param name the name of the attribute to look for. + * \retval 0 the attribute was not in the list, + * **prev now points to the next atfer. + * \retval 1 the attribute was in the list, + * **prev now points to the entry for it. + */ + static int + find_attr(UsedAttr *** prev, char const *name) + { + int comp; + + comp = 1; + while (**prev) { + comp = strcoll(name, prev[0][0]->name); + if (comp <= 0) + break; + *prev = &prev[0][0]->next; + } + return comp == 0; + } + + /** Insert an attribute in the list of seen attributes. + * Since attributes are inserted in collation order, an updated insertion + * point is returned (so subsequent calls don't have to go hunting as far). + * \param prev the pointer to the pointer to the attribute list. + * \param name the name of the attribute to insert. + * \param no_prog the AF_NOPROG value from the attribute. + * \return the pointer to the pointer to the next attribute after + * the one inserted. + */ + static UsedAttr ** + use_attr(UsedAttr ** prev, char const *name, int no_prog) + { + int found; + UsedAttr *used; + + found = find_attr(&prev, name); + if (!found) { + used = mush_malloc(sizeof *used, "used_attr"); + used->next = *prev; + used->name = name; + used->no_prog = 0; + *prev = used; + } + prev[0]->no_prog |= no_prog; + /* do_rawlog(LT_TRACE, "Recorded %s: %d -> %d", name, + no_prog, prev[0]->no_prog); */ + return &prev[0]->next; + } + /** Match input against a $command or ^listen attribute. * This function attempts to match a string against either the $commands * or ^listens on an object. Matches may be glob or regex matches, *************** *** 694,699 **** --- 796,804 ---- char *s; int match, match_found; dbref parent; + UsedAttr *used_list, **prev; + ATTR *skip[ATTRIBUTE_NAME_LIMIT / 2]; + int skipcount; /* check for lots of easy ways out */ if ((type != '$' && type != '^') || !GoodObject(thing) || Halted(thing) *************** *** 713,724 **** } match = 0; ! st_init(&temp_attrib); for (ptr = List(thing); ptr; ptr = AL_NEXT(ptr)) { if (parent_depth) ! st_insert(AL_NAME(ptr), &temp_attrib); ! if (AL_FLAGS(ptr) & AF_NOPROG || !(AL_FLAGS(ptr) & flag_mask)) continue; strcpy(tbuf1, atr_value(ptr)); s = tbuf1; --- 818,848 ---- } match = 0; ! used_list = NULL; ! prev = &used_list; + skipcount = 0; + /* do_rawlog(LT_TRACE, "Searching %s:", Name(thing)); */ for (ptr = List(thing); ptr; ptr = AL_NEXT(ptr)) { + if (skipcount && ptr == skip[skipcount - 1]) { + size_t len = strrchr(AL_NAME(ptr), '`') - AL_NAME(ptr); + while (AL_NEXT(ptr) && strlen(AL_NAME(AL_NEXT(ptr))) > len && + AL_NAME(AL_NEXT(ptr))[len] == '`') { + ptr = AL_NEXT(ptr); + /* do_rawlog(LT_TRACE, " Skipping %s", AL_NAME(ptr)); */ + } + skipcount--; + continue; + } if (parent_depth) ! prev = use_attr(prev, AL_NAME(ptr), AL_FLAGS(ptr) & AF_NOPROG); ! if (AL_FLAGS(ptr) & AF_NOPROG) { ! skip[skipcount] = atr_sub_branch(ptr); ! if (skip[skipcount]) ! skipcount++; ! continue; ! } ! if (!(AL_FLAGS(ptr) & flag_mask)) continue; strcpy(tbuf1, atr_value(ptr)); s = tbuf1; *************** *** 777,789 **** for (parent_depth = MAX_PARENTS, parent = Parent(thing); parent_depth-- && parent != NOTHING; parent = Parent(parent)) { for (ptr = List(parent); ptr; ptr = AL_NEXT(ptr)) { ! if (st_find(AL_NAME(ptr), &temp_attrib)) continue; ! if (Parent(parent) != NOTHING) ! st_insert(AL_NAME(ptr), &temp_attrib); ! if (AL_FLAGS(ptr) & (AF_NOPROG | AF_PRIVATE) ! || !(AL_FLAGS(ptr) & flag_mask)) continue; strcpy(tbuf1, atr_value(ptr)); s = tbuf1; --- 901,947 ---- for (parent_depth = MAX_PARENTS, parent = Parent(thing); parent_depth-- && parent != NOTHING; parent = Parent(parent)) { + /* do_rawlog(LT_TRACE, "Searching %s:", Name(parent)); */ + skipcount = 0; + prev = &used_list; for (ptr = List(parent); ptr; ptr = AL_NEXT(ptr)) { ! if (skipcount && ptr == skip[skipcount - 1]) { ! size_t len = strrchr(AL_NAME(ptr), '`') - AL_NAME(ptr); ! while (AL_NEXT(ptr) && strlen(AL_NAME(AL_NEXT(ptr))) > len && ! AL_NAME(AL_NEXT(ptr))[len] == '`') { ! ptr = AL_NEXT(ptr); ! /* do_rawlog(LT_TRACE, " Skipping %s", AL_NAME(ptr)); */ ! } ! skipcount--; ! continue; ! } ! if (AL_FLAGS(ptr) & AF_PRIVATE) { ! /* do_rawlog(LT_TRACE, "Private %s:", AL_NAME(ptr)); */ ! skip[skipcount] = atr_sub_branch(ptr); ! if (skip[skipcount]) ! skipcount++; continue; ! } ! if (find_attr(&prev, AL_NAME(ptr))) { ! /* do_rawlog(LT_TRACE, "Found %s:", AL_NAME(ptr)); */ ! if (prev[0]->no_prog || (AL_FLAGS(ptr) & AF_NOPROG)) { ! skip[skipcount] = atr_sub_branch(ptr); ! if (skip[skipcount]) ! skipcount++; ! prev[0]->no_prog = AF_NOPROG; ! } ! continue; ! } ! if (GoodObject(Parent(parent))) ! prev = use_attr(prev, AL_NAME(ptr), AL_FLAGS(ptr) & AF_NOPROG); ! if (AL_FLAGS(ptr) & AF_NOPROG) { ! /* do_rawlog(LT_TRACE, "NoProg %s:", AL_NAME(ptr)); */ ! skip[skipcount] = atr_sub_branch(ptr); ! if (skip[skipcount]) ! skipcount++; ! continue; ! } ! if (!(AL_FLAGS(ptr) & flag_mask)) continue; strcpy(tbuf1, atr_value(ptr)); s = tbuf1; *************** *** 832,843 **** safe_chr('/', atrname, abp); safe_str(AL_NAME(ptr), atrname, abp); } ! if (!just_match) parse_que(thing, s, player); } } } ! st_flush(&temp_attrib); return match; } --- 990,1007 ---- safe_chr('/', atrname, abp); safe_str(AL_NAME(ptr), atrname, abp); } ! if (!just_match) { ! /* do_rawlog(LT_TRACE, "MATCHED %s:", AL_NAME(ptr)); */ parse_que(thing, s, player); + } } } } ! while (used_list) { ! UsedAttr *temp = used_list->next; ! mush_free(used_list, "used_attr"); ! used_list = temp; ! } return match; } *************** *** 1005,1011 **** notify(player, T("That's not a very good name for an attribute.")); return 0; } else if (res == AE_ERROR) { ! notify(player, T("That attribute cannot be changed by you.")); return 0; } else if (!res) { notify(player, T("No such attribute to reset.")); --- 1169,1178 ---- notify(player, T("That's not a very good name for an attribute.")); return 0; } else if (res == AE_ERROR) { ! if (*missing_name) ! notify_format(player, T("You must set %s first."), missing_name); ! else ! notify(player, T("That attribute cannot be changed by you.")); return 0; } else if (!res) { notify(player, T("No such attribute to reset.")); *************** *** 1208,1213 **** --- 1375,1545 ---- return atr_free_list; } + /** Traversal routine for Can_Read_Attr. + * This function determines if an attribute can be read by examining + * the tree path to the attribute. This is not the full Can_Read_Attr + * check; only the stuff after See_All (just to avoid function calls + * when the answer is trivialized by special powers). If the specified + * player is NOTHING, then we're doing a generic mortal visibility check. + * \param player the player trying to do the read. + * \param obj the object targetted for the read (may be a child of a parent!). + * \param attr the attribute being interrogated. + * \retval 0 if the player cannot read the attribute. + * \retval 1 if the player can read the attribute. + */ + int + can_read_attr_internal(dbref player, dbref obj, ATTR *atr) + { + static char name[ATTRIBUTE_NAME_LIMIT + 1]; + char *p; + int control; + int exam; + int comp; + dbref target; + dbref ancestor; + int visible; + int parent_depth; + + visible = (player == NOTHING); + if (visible) { + control = 0; + exam = (Visual(obj) && + eval_lock(PLAYER_START, obj, Examine_Lock) && + eval_lock(MASTER_ROOM, obj, Examine_Lock)); + } else { + control = controls(player, obj); + exam = (Visual(obj) && eval_lock(player, obj, Examine_Lock)); + } + + /* Take an easy out if there is one... */ + /* If we can't see the attribute itself, then that's easy. */ + if ((AL_FLAGS(atr) & AF_MDARK) || + !((AL_FLAGS(atr) & AF_VISUAL) || control || exam || + (!visible && !Mistrust(player) && + (Owner(AL_CREATOR(atr)) == Owner(player))))) + return 0; + + /* If the attribute isn't on a branch, then that's also easy. */ + if (!strchr(AL_NAME(atr), '`')) + return 1; + + /* Nope, we actually have to go looking for the attribute in a tree. */ + strcpy(name, AL_NAME(atr)); + ancestor = Ancestor_Parent(obj); + target = obj; + parent_depth = 0; + while (parent_depth < MAX_PARENTS && GoodObject(target)) { + /* If the ancestor of the object is in its explict parent chain, + * we use it there, and don't check the ancestor later. + */ + if (target == ancestor) + ancestor = NOTHING; + atr = List(target); + + /* Check along the branch for permissions... */ + for (p = strchr(name, '`'); p; p = strchr(p + 1, '`')) { + *p = '\0'; + while (atr) { + comp = strcoll(name, AL_NAME(atr)); + if (comp < 0) + goto continue_target; + if (comp == 0) + break; + atr = AL_NEXT(atr); + } + if (!atr || (target != obj && (AL_FLAGS(atr) & AF_PRIVATE))) + goto continue_target; + if ((AL_FLAGS(atr) & AF_INTERNAL) || (AL_FLAGS(atr) & AF_MDARK) || + !((AL_FLAGS(atr) & AF_VISUAL) || control || exam || + (!visible && !Mistrust(player) && + (Owner(AL_CREATOR(atr)) == Owner(player))))) + return 0; + *p = '`'; + } + + /* Now actually find the attribute. */ + while (atr) { + comp = strcoll(name, AL_NAME(atr)); + if (comp < 0) + break; + if (comp == 0) + return 1; + atr = AL_NEXT(atr); + } + + continue_target: + *p = '`'; + + /* Attribute wasn't on this object. Check a parent or ancestor. */ + parent_depth++; + target = Parent(target); + if (!GoodObject(target)) { + parent_depth = 0; + target = ancestor; + } + } + + return 0; + } + + /** Traversal routine for Can_Write_Attr. + * This function determines if an attribute can be written by examining + * the tree path to the attribute. As a side effect, missing_name is + * set to the name of a missing prefix branch, if any. Yes, side effects + * are evil. Please fix if you can. + * \param player the player trying to do the write. + * \param obj the object targetted for the write. + * \param atr the attribute being interrogated. + * \param safe whether to check the safe attribute flag. + * \retval 0 if the player cannot write the attribute. + * \retval 1 if the player can write the attribute. + */ + int + can_write_attr_internal(dbref player, dbref obj, ATTR *atr, int safe) + { + char *p; + int comp; + + missing_name[0] = '\0'; + + if (!God(player) && + ((AL_FLAGS(atr) & AF_INTERNAL) || + (safe && (AL_FLAGS(atr) & AF_SAFE)) || + !(Wizard(player) || + (!(AL_FLAGS(atr) & AF_WIZARD) && + (!(AL_FLAGS(atr) & AF_LOCKED) || + (AL_CREATOR(atr) == Owner(player))))))) + return 0; + + strcpy(missing_name, AL_NAME(atr)); + atr = List(obj); + for (p = strchr(missing_name, '`'); p; p = strchr(p + 1, '`')) { + *p = '\0'; + while (atr) { + comp = strcoll(missing_name, AL_NAME(atr)); + if (comp < 0) + return 0; + if (comp == 0) + break; + atr = AL_NEXT(atr); + } + if (!atr || + (!God(player) && + ((AL_FLAGS(atr) & AF_INTERNAL) || + (safe && (AL_FLAGS(atr) & AF_SAFE)) || + !(Wizard(player) || + (!(AL_FLAGS(atr) & AF_WIZARD) && + (!(AL_FLAGS(atr) & AF_LOCKED) || + (AL_CREATOR(atr) == Owner(player)))))))) { + missing_name[0] = '\0'; + return 0; + } + *p = '`'; + } + + return 1; + } + /** Return the compressed data for an attribute. * This is a chokepoint function for accessing the chunk data. * \param atr the attribute struct from which to get the data reference. *** 1_7_7.624/hdrs/version.h Thu, 04 Sep 2003 17:36:31 -0500 dunemush (pennmush/c/47_version.h 1.32.1.2.1.7.1.9.1.1.1.17.1.24 660) --- 1_7_7.664(w)/hdrs/version.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/c/47_version.h 1.32.1.2.1.7.1.9.1.1.1.17.1.25 660) *************** *** 1,3 **** ! #define VERSION "PennMUSH version 1.7.7 patchlevel 20 [09/04/2003]" ! #define SHORTVN "PennMUSH 1.7.7p20" ! #define NUMVERSION 001007007020 --- 1,3 ---- ! #define VERSION "PennMUSH version 1.7.7 patchlevel 21 [09/23/2003]" ! #define SHORTVN "PennMUSH 1.7.7p21" ! #define NUMVERSION 001007007021 *** 1_7_7.624/hdrs/mushdb.h Sat, 30 Aug 2003 14:51:01 -0500 dunemush (pennmush/d/2_mushdb.h 1.1.1.9.1.1.1.16 660) --- 1_7_7.664(w)/hdrs/mushdb.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/2_mushdb.h 1.1.1.9.1.1.1.17 660) *************** *** 85,101 **** /* can p access attribute a on object x? */ #define Can_Read_Attr(p,x,a) \ (!((a)->flags & AF_INTERNAL) && \ ! (See_All(p) || \ ! (!((a)->flags & AF_MDARK) && \ ! (controls(p,x) || ((a)->flags & AF_VISUAL) || \ ! (Visual(x) && eval_lock(p,x,Examine_Lock)) || \ ! (!Mistrust(p) && (Owner((a)->creator) == Owner(p))))))) /* can anyone access attribute a on object x? */ #define Is_Visible_Attr(x,a) \ (!((a)->flags & AF_INTERNAL) && \ ! !((a)->flags & AF_MDARK) && \ ! ((a)->flags & AF_VISUAL)) /* can p write attribute a on object x, assuming p may modify x? * Must be (1) God, or (2) a non-internal, non-safe flag and --- 85,96 ---- /* can p access attribute a on object x? */ #define Can_Read_Attr(p,x,a) \ (!((a)->flags & AF_INTERNAL) && \ ! (See_All(p) || can_read_attr_internal((p),(x),(a)))) /* can anyone access attribute a on object x? */ #define Is_Visible_Attr(x,a) \ (!((a)->flags & AF_INTERNAL) && \ ! can_read_attr_internal(NOTHING,(x),(a))) /* can p write attribute a on object x, assuming p may modify x? * Must be (1) God, or (2) a non-internal, non-safe flag and *************** *** 103,122 **** * the attrib or (2b2) it's not atrlocked. */ #define Can_Write_Attr(p,x,a) \ ! (God(p) || \ ! (!((a)->flags & AF_INTERNAL) && \ ! !((a)->flags & AF_SAFE) && \ ! (Wizard(p) || \ ! (!((a)->flags & AF_WIZARD) && \ ! (((a)->creator == Owner(p)) || !((a)->flags & AF_LOCKED)) \ ! )))) #define Can_Write_Attr_Ignore_Safe(p,x,a) \ ! (God(p) || \ ! (!((a)->flags & AF_INTERNAL) && \ ! (Wizard(p) || \ ! (!((a)->flags & AF_WIZARD) && \ ! (((a)->creator == Owner(p)) || !((a)->flags & AF_LOCKED)) \ ! )))) /* Can p forward a message to x (via @forwardlist)? */ --- 98,106 ---- * the attrib or (2b2) it's not atrlocked. */ #define Can_Write_Attr(p,x,a) \ ! (can_write_attr_internal((p),(x),(a),1)) #define Can_Write_Attr_Ignore_Safe(p,x,a) \ ! (can_write_attr_internal((p),(x),(a),0)) /* Can p forward a message to x (via @forwardlist)? */ *** 1_7_7.624/hdrs/lock.h Mon, 01 Sep 2003 15:52:02 -0500 dunemush (pennmush/d/6_lock.h 1.20 660) --- 1_7_7.664(w)/hdrs/lock.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/6_lock.h 1.22 660) *************** *** 30,44 **** }; /* Our table of lock types, attributes, and default flags */ ! typedef struct lock_info LOCKINFO; /** A lock. * This structure represents a lock in the table of lock types */ ! struct lock_info { lock_type type; /**< Type of lock */ const char *succbase; /**< Base name of success attribute */ const char *failbase; /**< Base name of failure attribute */ - int flags; /**< Default flags */ }; #define LF_VISUAL 0x1 /* Anyone can see this lock with lock()/elock() */ --- 30,43 ---- }; /* Our table of lock types, attributes, and default flags */ ! typedef struct lock_msg_info LOCKMSGINFO; /** A lock. * This structure represents a lock in the table of lock types */ ! struct lock_msg_info { lock_type type; /**< Type of lock */ const char *succbase; /**< Base name of success attribute */ const char *failbase; /**< Base name of failure attribute */ }; #define LF_VISUAL 0x1 /* Anyone can see this lock with lock()/elock() */ *************** *** 61,66 **** --- 60,67 ---- boolexp key, int flags); void free_locks(lock_list *ll); int eval_lock(dbref player, dbref thing, lock_type ltype); + void fail_lock(dbref player, dbref thing, lock_type ltype, const char *def, + dbref loc); void do_unlock(dbref player, const char *name, lock_type type); void do_lock(dbref player, const char *name, const char *keyname, lock_type type); *** 1_7_7.624/hdrs/flags.h Mon, 18 Aug 2003 20:59:29 -0500 dunemush (pennmush/d/14_flags.h 1.1.1.1.1.1.1.1.1.2.1.3.2.1.1.4.1.1.1.1.2.1.1.25 660) --- 1_7_7.664(w)/hdrs/flags.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/14_flags.h 1.1.1.1.1.1.1.1.1.2.1.3.2.1.1.4.1.1.1.1.2.1.1.26 660) *************** *** 122,128 **** extern void do_flag_restrict(dbref player, const char *name, char *args_right[]); extern void do_flag_add(dbref player, const char *name, char *args_right[]); ! #define twiddle_flag_bitmask(bm,b,neg) (neg ? clear_flag_bitmask(bm,b) : \ set_flag_bitmask(bm,b)) --- 122,128 ---- extern void do_flag_restrict(dbref player, const char *name, char *args_right[]); extern void do_flag_add(dbref player, const char *name, char *args_right[]); ! extern void do_flag_letter(dbref player, const char *name, const char *letter); #define twiddle_flag_bitmask(bm,b,neg) (neg ? clear_flag_bitmask(bm,b) : \ set_flag_bitmask(bm,b)) *** 1_7_7.624/hdrs/externs.h Wed, 03 Sep 2003 22:39:22 -0500 dunemush (pennmush/d/16_externs.h 1.1.1.53.1.2.1.8.2.1.1.2.1.1.1.1.1.2.1.6.1.3.1.4.3.1.1.1.1.18 660) --- 1_7_7.664(w)/hdrs/externs.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/16_externs.h 1.1.1.53.1.2.1.8.2.1.1.2.1.1.1.1.1.2.1.6.1.3.1.4.3.1.1.1.1.18.1.1 660) *************** *** 464,469 **** --- 464,470 ---- extern int wild_match_case(const char *RESTRICT s, const char *RESTRICT d, int cs); extern int quick_wild(const char *RESTRICT tsr, const char *RESTRICT dstr); + extern int atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr); #define regexp_match(s,d) regexp_match_case(s,d,1) #define wild_match(s,d) wild_match_case(s,d,0) #define local_wild_match(s,d) local_wild_match_case(s, d, 0) *** 1_7_7.624/hdrs/extchat.h Mon, 01 Sep 2003 15:52:02 -0500 dunemush (pennmush/d/17_extchat.h 1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.3.1.1.1.1.2.2.1.9.1.1 660) --- 1_7_7.664(w)/hdrs/extchat.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/17_extchat.h 1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.3.1.1.1.1.2.2.1.9.1.1.1.3 660) *************** *** 134,139 **** --- 134,142 ---- #define CHANNEL_WIZARD 0x20 /* Wizard only ok */ #define CHANNEL_CANHIDE 0x40 /* Can non-DARK Wizards hide here? */ #define CHANNEL_OPEN 0x80 /* Can you speak if you're not joined? */ + #define CHANNEL_NOTITLES 0x100 /* Don't show titles of speakers */ + #define CHANNEL_NONAMES 0x200 /* Don't show names of speakers */ + #define CHANNEL_NOCEMIT 0x400 /* Disallow @cemit */ #define CHANNEL_DEFAULT_FLAGS (CHANNEL_PLAYER) #define CL_JOIN 0x1 #define CL_SPEAK 0x2 *************** *** 171,176 **** --- 174,182 ---- #define Channel_Wizard(c) (ChanType(c) & CHANNEL_WIZARD) #define Channel_Admin(c) (ChanType(c) & CHANNEL_ADMIN) #define Channel_CanHide(c) (ChanType(c) & CHANNEL_CANHIDE) + #define Channel_NoTitles(c) (ChanType(c) & CHANNEL_NOTITLES) + #define Channel_NoNames(c) (ChanType(c) & CHANNEL_NONAMES) + #define Channel_NoCemit(c) (ChanType(c) & CHANNEL_NOCEMIT) #define Chan_Ok_Type(c,o) \ ((IsPlayer(o) && Channel_Player(c)) || \ (IsThing(o) && Channel_Object(c))) *************** *** 186,191 **** --- 192,199 ---- #define Chan_Can_Speak(c,p) \ (Chan_Can_Access(c,p) && \ (eval_boolexp(p,ChanSpeakLock(c),p))) + #define Chan_Can_Cemit(c,p) \ + (!Channel_NoCemit(c) && Chan_Can_Speak(c,p)) #define Chan_Can_Modify(c,p) \ (Wizard(p) || (ChanCreator(c) == (p)) || \ (!Guest(p) && Chan_Can_Access(c,p) && \ *************** *** 227,233 **** extern void do_chan_what(dbref player, const char *partname); extern void do_chan_desc(dbref player, const char *name, const char *title); extern void do_chan_title(dbref player, const char *name, const char *title); ! extern void do_chan_recall(dbref player, const char *name, const char *lines); extern void do_chan_buffer(dbref player, const char *name, const char *lines); extern void init_chat(void); extern void do_channel --- 235,242 ---- extern void do_chan_what(dbref player, const char *partname); extern void do_chan_desc(dbref player, const char *name, const char *title); extern void do_chan_title(dbref player, const char *name, const char *title); ! extern void do_chan_recall(dbref player, const char *name, const char *lines, ! int quiet); extern void do_chan_buffer(dbref player, const char *name, const char *lines); extern void init_chat(void); extern void do_channel *** 1_7_7.624/hdrs/conf.h Mon, 01 Sep 2003 17:25:53 -0500 dunemush (pennmush/d/20_conf.h 1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.2.1.1.2.1.2.13.1.4.1.20 660) --- 1_7_7.664(w)/hdrs/conf.h Mon, 29 Sep 2003 16:42:35 -0500 dunemush (pennmush/d/20_conf.h 1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.2.1.1.2.1.2.13.1.4.1.20.1.1 660) *************** *** 53,59 **** /* These CAN be modified, but it's heavily NOT suggested */ #define PUEBLO_SEND "\n" ! #define PUEBLO_HELLO "This world is Pueblo 2.50 Enhanced.\r\n" #define MAX_OUTPUT 16384 --- 53,59 ---- /* These CAN be modified, but it's heavily NOT suggested */ #define PUEBLO_SEND "\n" ! #define PUEBLO_HELLO "This world is Pueblo 1.10 Enhanced.\r\n" #define MAX_OUTPUT 16384 *** 1_7_7.624/hdrs/switches.h Mon, 01 Sep 2003 18:39:12 -0500 dunemush (pennmush/d/21_switches.h 1.2.1.6.2.7.1.5 660) --- 1_7_7.664(w)/hdrs/switches.h Mon, 29 Sep 2003 16:42:41 -0500 dunemush (pennmush/d/21_switches.h 1.2.1.6.2.7.1.6 660) *************** *** 60,139 **** #define SWITCH_INVENTORY 59 #define SWITCH_IPRINT 60 #define SWITCH_JOIN 61 ! #define SWITCH_LIST 62 ! #define SWITCH_LOWERCASE 63 ! #define SWITCH_ME 64 ! #define SWITCH_MEMBERS 65 ! #define SWITCH_MOD 66 ! #define SWITCH_MORTAL 67 ! #define SWITCH_MOTD 68 ! #define SWITCH_MUTE 69 ! #define SWITCH_NAME 70 ! #define SWITCH_NO 71 ! #define SWITCH_NOEVAL 72 ! #define SWITCH_NOFLAGCOPY 73 ! #define SWITCH_NOISY 74 ! #define SWITCH_NOSIG 75 ! #define SWITCH_NOSPACE 76 ! #define SWITCH_NOTIFY 77 ! #define SWITCH_NUKE 78 ! #define SWITCH_OFF 79 ! #define SWITCH_ON 80 ! #define SWITCH_OUTSIDE 81 ! #define SWITCH_OVERRIDE 82 ! #define SWITCH_PAGING 83 ! #define SWITCH_PANIC 84 ! #define SWITCH_PARANOID 85 ! #define SWITCH_PLAYERS 86 ! #define SWITCH_PORT 87 ! #define SWITCH_PRESERVE 88 ! #define SWITCH_PRINT 89 ! #define SWITCH_PRIVS 90 ! #define SWITCH_PURGE 91 ! #define SWITCH_QUICK 92 ! #define SWITCH_QUIET 93 ! #define SWITCH_READ 94 ! #define SWITCH_REBOOT 95 ! #define SWITCH_RECALL 96 ! #define SWITCH_REGIONS 97 ! #define SWITCH_REGISTER 98 ! #define SWITCH_REMOVE 99 ! #define SWITCH_RENAME 100 ! #define SWITCH_RESTORE 101 ! #define SWITCH_RESTRICT 102 ! #define SWITCH_RETROACTIVE 103 ! #define SWITCH_ROOM 104 ! #define SWITCH_ROOMS 105 ! #define SWITCH_SEE 106 ! #define SWITCH_SEEFLAG 107 ! #define SWITCH_SELF 108 ! #define SWITCH_SEND 109 ! #define SWITCH_SET 110 ! #define SWITCH_SILENT 111 ! #define SWITCH_SKIPDEFAULTS 112 ! #define SWITCH_SPEAK 113 ! #define SWITCH_STATS 114 ! #define SWITCH_SUMMARY 115 ! #define SWITCH_TABLES 116 ! #define SWITCH_TAG 117 ! #define SWITCH_TELEPORT 118 ! #define SWITCH_TF 119 ! #define SWITCH_THINGS 120 ! #define SWITCH_TITLE 121 ! #define SWITCH_TRACE 122 ! #define SWITCH_UNCLEAR 123 ! #define SWITCH_UNFOLDER 124 ! #define SWITCH_UNGAG 125 ! #define SWITCH_UNHIDE 126 ! #define SWITCH_UNMUTE 127 ! #define SWITCH_UNTAG 128 ! #define SWITCH_UNTIL 129 ! #define SWITCH_URGENT 130 ! #define SWITCH_USEFLAG 131 ! #define SWITCH_WHAT 132 ! #define SWITCH_WHO 133 ! #define SWITCH_WIPE 134 ! #define SWITCH_WIZ 135 ! #define SWITCH_WIZARD 136 ! #define SWITCH_YES 137 ! #define SWITCH_ZONE 138 --- 60,140 ---- #define SWITCH_INVENTORY 59 #define SWITCH_IPRINT 60 #define SWITCH_JOIN 61 ! #define SWITCH_LETTER 62 ! #define SWITCH_LIST 63 ! #define SWITCH_LOWERCASE 64 ! #define SWITCH_ME 65 ! #define SWITCH_MEMBERS 66 ! #define SWITCH_MOD 67 ! #define SWITCH_MORTAL 68 ! #define SWITCH_MOTD 69 ! #define SWITCH_MUTE 70 ! #define SWITCH_NAME 71 ! #define SWITCH_NO 72 ! #define SWITCH_NOEVAL 73 ! #define SWITCH_NOFLAGCOPY 74 ! #define SWITCH_NOISY 75 ! #define SWITCH_NOSIG 76 ! #define SWIT