[PENNMUSH-ANNOUNCE] 1.7.7-patch20

dunemush at tala.mede.uic.edu dunemush at tala.mede.uic.edu
Wed Sep 10 15:48:00 CDT 2003


This is patch20 to PennMUSH 1.7.7. After applying this patch, you will
have version 1.7.7p20

To apply this patch, save it to a file in your top-level MUSH directory,
and do the following:
	patch -p1 < 1.7.7-patch20
	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:
  * minimal.db is no more. If you start up the server and there's no
    db to be found, it creates a new minimal database in memory
    on the fly. Feel free to delete your coopy of minimal.db. [SW]
    (In related news, the default OSUCC on #0 in minimal.db is gone. 
    Suggested by Cheetah at M*U*S*H. So much for the mists.)
Minor Changes:
  * SSL connections are now ended before the dump when rebooting,
    but their descriptor information sticks around to ensure that
    their @adisconnect is run after the reboot. Based on suggestions
    by Vadiv at M*U*S*H and [TAP].
  * When _DEBUG is defined in a win32 build, don't copy pennmush.exe
    to pennmush_run.exe. Makes debugging easier. Patch by Luke at M*U*S*H.
  * In pueblo mode, no longer clear past images after each room look.
    Patch by Konstantine Shirow.
  * In pueblo mode, we no longer render ansi attributes or colors with
    HTML tags; we assume the client will correctly handle them as ansi
    intermixed with Pueblo. This solves a variety of problems.
    Based on a discussion with Konstantine Shirow.
  * When matching $commands and ^listens, insure that a matching attribute
    exists before testing locks. This may break some strange locks using
    %c, but hopefully won't. Suggested by Cheetah at M*U*S*H.
  * The @scan command temporarily sets %c to the command to be scanned
    (without "@scan" prefixed) so that it can detect commands that use
    %c-matching. Based on ideas from Cheetah and Walker at M*U*S*H.
  * Added support for Pueblo's md5 checksum. We track it on each
    descriptor, though we don't do anything with it currently.
  * Speed-up to fun_merge. Patch by Walker at M*U*S*H.
  * Internal cleanup of flags in channel_broadcast.
  * Wizards may @name themselves to names forbidden in names.cnf.
    Patch by LeeLaLimaLLama at M*U*S*H.
  * We are now forgiving of stupid non-RFC-compliant telnet clients
    that send CR only even when they claim to be sending CRLF
    (Read: MS Windows XP telnet). MS bug reported first by
    Intrevis at M*U*S*H.
  * Misleading restrict_command on @clone removed from restrict.cnf,
    as @dig/@open/@create permissions already control @clone.
    Suggested by Philip Mak.
Functions:
  * lstats() and quota() now allow objects to see stats/quota on other
    objects they control (e.g., on their owners, perhaps). Suggested
    by Philip Mak.
  * hastype() can now test for type GARBAGE. Suggested by Tanaku at M*U*S*H.
Commands:
  * The new ']' command prefix causes the rest of the command-line
    not to be evaluated by the expression parser. Try: ]think [add(1,1)]
    Inspired by Elendor.
  * @hook/ignore. [mux]
  * @hook/override [Rhost, though they don't call it that]
Attributes:
  * @debugforwardlist forwards DEBUG output to dbrefs on the list.
    Suggested by Balerion at M*U*S*H.
Tests:
  * A new test harness for developing regression test suites in perl
    for PennMUSH is now included; few test suites are. If you can figure
    out how to use this, write some tests for us! (If you can't, don't
    ask about it, please :)
Locks:
  * @lock/interact can prevent other players from transmitting any
    normal sound to you (that is, you won't hear them speak, pose, 
    emit, etc., like gagging them in a client). It doesn't control
    page (use @lock/page) or @mail (use @lock/mail). You still
    hear 'presence' messages (connects/disconnects/arrivals/leaves)
    so you can have a sense of who can hear you but you can't hear.
    Patch by Philip Mak.
Fixes:
  * Configure script no longer keeps adding -lssl -lcrypto over and
    over to the Makefile. Report by Sholevi at M*U*S*H.
  * Portability fixes for compiling with MSVC5 by Luke at M*U*S*H.
  * The behavior of spaces inside parentheses that aren't part of a
    function has been improved. Report by Jason Newquist. [TAP]
  * txt/*.html files were being improperly escaped before being
    sent to Pueblo connections. Report by Konstantine Shirow.
  * mushdb.h includes flags.h, as it relies on constants from there.
    Suggested by Philip Mak.
  * Better error reporting on some failure messages in chunk allocator.
    Patch by Philip Mak.
  * @config/set with an invalid option now returns an error.
    Report by Sholevi at M*U*S*H.
  * Fix to interaction checking in notify_anything that could result
    in the wrong check being performed. Report by Philip Mak.
  * Help fixes by LeeLaLimaLLama at M*U*S*H, Sunny at M*U*S*H, Sketch at M*U*S*H.


Prereq: 1.7.7p19
*** 1_7_7.561/Patchlevel Wed, 20 Aug 2003 01:05:31 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.21 600)
--- 1_7_7.623(w)/Patchlevel Thu, 04 Sep 2003 17:35:47 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.22 600)
***************
*** 1,2 ****
  Do not edit this file. It is maintained by the official PennMUSH patches.
! This is PennMUSH 1.7.7p19
--- 1,2 ----
  Do not edit this file. It is maintained by the official PennMUSH patches.
! This is PennMUSH 1.7.7p20
*** 1_7_7.561/CHANGES.177 Wed, 20 Aug 2003 01:05:31 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.135 600)
--- 1_7_7.623(w)/CHANGES.177 Fri, 05 Sep 2003 20:59:03 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.165 600)
***************
*** 18,23 ****
--- 18,109 ----
  
  ==========================================================================
  
+ Version 1.7.7 patchlevel 20                     September 4, 2003
+ 
+ Major Changes:
+   * minimal.db is no more. If you start up the server and there's no
+     db to be found, it creates a new minimal database in memory
+     on the fly. Feel free to delete your coopy of minimal.db. [SW]
+     (In related news, the default OSUCC on #0 in minimal.db is gone. 
+     Suggested by Cheetah at M*U*S*H. So much for the mists.)
+ Minor Changes:
+   * SSL connections are now ended before the dump when rebooting,
+     but their descriptor information sticks around to ensure that
+     their @adisconnect is run after the reboot. Based on suggestions
+     by Vadiv at M*U*S*H and [TAP].
+   * When _DEBUG is defined in a win32 build, don't copy pennmush.exe
+     to pennmush_run.exe. Makes debugging easier. Patch by Luke at M*U*S*H.
+   * In pueblo mode, no longer clear past images after each room look.
+     Patch by Konstantine Shirow.
+   * In pueblo mode, we no longer render ansi attributes or colors with
+     HTML tags; we assume the client will correctly handle them as ansi
+     intermixed with Pueblo. This solves a variety of problems.
+     Based on a discussion with Konstantine Shirow.
+   * When matching $commands and ^listens, insure that a matching attribute
+     exists before testing locks. This may break some strange locks using
+     %c, but hopefully won't. Suggested by Cheetah at M*U*S*H.
+   * The @scan command temporarily sets %c to the command to be scanned
+     (without "@scan" prefixed) so that it can detect commands that use
+     %c-matching. Based on ideas from Cheetah and Walker at M*U*S*H.
+   * Added support for Pueblo's md5 checksum. We track it on each
+     descriptor, though we don't do anything with it currently.
+   * Speed-up to fun_merge. Patch by Walker at M*U*S*H.
+   * Internal cleanup of flags in channel_broadcast.
+   * Wizards may @name themselves to names forbidden in names.cnf.
+     Patch by LeeLaLimaLLama at M*U*S*H.
+   * We are now forgiving of stupid non-RFC-compliant telnet clients
+     that send CR only even when they claim to be sending CRLF
+     (Read: MS Windows XP telnet). MS bug reported first by
+     Intrevis at M*U*S*H.
+   * Misleading restrict_command on @clone removed from restrict.cnf,
+     as @dig/@open/@create permissions already control @clone.
+     Suggested by Philip Mak.
+ Functions:
+   * lstats() and quota() now allow objects to see stats/quota on other
+     objects they control (e.g., on their owners, perhaps). Suggested
+     by Philip Mak.
+   * hastype() can now test for type GARBAGE. Suggested by Tanaku at M*U*S*H.
+ Commands:
+   * The new ']' command prefix causes the rest of the command-line
+     not to be evaluated by the expression parser. Try: ]think [add(1,1)]
+     Inspired by Elendor.
+   * @hook/ignore. [mux]
+   * @hook/override [Rhost, though they don't call it that]
+ Attributes:
+   * @debugforwardlist forwards DEBUG output to dbrefs on the list.
+     Suggested by Balerion at M*U*S*H.
+ Tests:
+   * A new test harness for developing regression test suites in perl
+     for PennMUSH is now included; few test suites are. If you can figure
+     out how to use this, write some tests for us! (If you can't, don't
+     ask about it, please :)
+ Locks:
+   * @lock/interact can prevent other players from transmitting any
+     normal sound to you (that is, you won't hear them speak, pose, 
+     emit, etc., like gagging them in a client). It doesn't control
+     page (use @lock/page) or @mail (use @lock/mail). You still
+     hear 'presence' messages (connects/disconnects/arrivals/leaves)
+     so you can have a sense of who can hear you but you can't hear.
+     Patch by Philip Mak.
+ Fixes:
+   * Configure script no longer keeps adding -lssl -lcrypto over and
+     over to the Makefile. Report by Sholevi at M*U*S*H.
+   * Portability fixes for compiling with MSVC5 by Luke at M*U*S*H.
+   * The behavior of spaces inside parentheses that aren't part of a
+     function has been improved. Report by Jason Newquist. [TAP]
+   * txt/*.html files were being improperly escaped before being
+     sent to Pueblo connections. Report by Konstantine Shirow.
+   * mushdb.h includes flags.h, as it relies on constants from there.
+     Suggested by Philip Mak.
+   * Better error reporting on some failure messages in chunk allocator.
+     Patch by Philip Mak.
+   * @config/set with an invalid option now returns an error.
+     Report by Sholevi at M*U*S*H.
+   * Fix to interaction checking in notify_anything that could result
+     in the wrong check being performed. Report by Philip Mak.
+   * Help fixes by LeeLaLimaLLama at M*U*S*H, Sunny at M*U*S*H, Sketch at M*U*S*H.
+ 
+ 
  Version 1.7.7 patchlevel 19                     August 19, 2003
  
  Fixes:
*** 1_7_7.561/game/txt/hlp/pennfunc.hlp Mon, 11 Aug 2003 16:30:36 -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.7 600)
--- 1_7_7.623(w)/game/txt/hlp/pennfunc.hlp Fri, 05 Sep 2003 20:58:18 -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)
***************
*** 65,73 ****
    
    aposs()       default()     edefault()    eval()        filter()
    filterbool()  fold()        foreach()     get()         grep()
!   grepi()       lattr()       obj()         poss()        regrep()
!   regrepi()     subj()        udefault()    ufun()        uldefault()
!   ulocal()      v-function    xget()        zfun()
  
    See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES
  & Bitwise functions
--- 65,73 ----
    
    aposs()       default()     edefault()    eval()        filter()
    filterbool()  fold()        foreach()     get()         grep()
!   grepi()       lattr()       nattr()       obj()         poss()        
!   regrep()      regrepi()     subj()        udefault()    ufun()        
!   uldefault()   ulocal()      v-function    xget()        zfun()
  
    See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES
  & Bitwise functions
***************
*** 609,617 ****
  & CLOCK()
    clock(<channel>[/<locktype>][, <new lock>])
  
!   With one argument, returns the value of a lock on a channel.
!   If no locktype is given, "JOIN" is assumed.
!   With two arguments, sets the lock.
  
    See also: @clock
  & CLONE()
--- 609,619 ----
  & CLOCK()
    clock(<channel>[/<locktype>][, <new lock>])
  
!   With one argument, returns the value of a lock on a channel, if you
!   own the channel or are See_All.  If no locktype is given, "JOIN" 
!   is assumed.
!   With two arguments, sets the lock if you would be able to do so via
!   @clock.
  
    See also: @clock
  & CLONE()
***************
*** 1431,1438 ****
    hastype(<object>, <type>)
  
    Returns 1 if the object is of the named type, otherwise 0.
!   Valid types are: ROOM, EXIT, PLAYER, THING.
!   If an invalid type is given, #-1 is returned.
  & HIDDEN()
    hidden(<player|descriptor>)
  
--- 1433,1440 ----
    hastype(<object>, <type>)
  
    Returns 1 if the object is of the named type, otherwise 0.
!   Valid types are: ROOM, EXIT, PLAYER, THING, GARBAGE.
!   If an invalid type is given, #-1 NO SUCH TYPE is returned.
  & HIDDEN()
    hidden(<player|descriptor>)
  
***************
*** 1690,1695 ****
--- 1692,1698 ----
    If a wildcarded attribute pattern is provided, only attribute names
    matching that pattern will be returned.
  
+   See also: nattr()
  & NATTR()
  & ATTRCNT()
    nattr(<object>)
***************
*** 3164,3171 ****
  & STARTTIME()
    Function: starttime()
   
!   Returns a string which is the time the MUSH first started up.  The time
!   is in the same format as the TIME() function returns.
   
    Example:
      > say starttime()
--- 3167,3175 ----
  & STARTTIME()
    Function: starttime()
   
!   Returns a string containing the time the MUSH first started up (not 
!   including @shutdown/reboots).  The time is in the same format that the 
!   TIME() function returns.
   
    Example:
      > say starttime()
*** 1_7_7.561/game/txt/hlp/pennflag.hlp Thu, 17 Jul 2003 15:28:00 -0500 dunemush (pennmush/17_pennflag.h 1.1.1.1.1.2.1.1.1.2.1.1.1.2.1.1.2.1.2.1.1.1.1.2.1.4.1.2.2.7 600)
--- 1_7_7.623(w)/game/txt/hlp/pennflag.hlp Mon, 01 Sep 2003 23:39:21 -0500 dunemush (pennmush/17_pennflag.h 1.1.1.1.1.2.1.1.1.2.1.1.1.2.1.1.2.1.2.1.1.1.1.2.1.4.1.2.2.8 600)
***************
*** 199,206 ****
    
    The DEBUG flag is used for debugging MUSHcode. It is meant to be used
    in conjunction with the VERBOSE flag. If an object is set DEBUG, all
!   parser evaluation results will be shown to the object's owner, in the
!   format:
   
    #dbref! <string to evaluate> :
    #dbref!  recursive evaluation of functions in string
--- 199,206 ----
    
    The DEBUG flag is used for debugging MUSHcode. It is meant to be used
    in conjunction with the VERBOSE flag. If an object is set DEBUG, all
!   parser evaluation results will be shown to the object's owner and to 
!   any dbrefs in the object's DEBUGFORWARDLIST, in the format:
   
    #dbref! <string to evaluate> :
    #dbref!  recursive evaluation of functions in string
***************
*** 212,221 ****
    messages evaluating specific parts of an expression. This enables you
    to pinpoint exactly which evaluation is going wrong.
    
!   Objects run under this flag are computationally expensive.
!   Avoid leaving it set on objects. It can also generate huge amounts of
!   spam from the output.
!   
    See "help DEBUG2" for more.
  & DEBUG2
    
--- 212,221 ----
    messages evaluating specific parts of an expression. This enables you
    to pinpoint exactly which evaluation is going wrong.
    
!   Objects run under this flag are computationally expensive.  Avoid
!   leaving it set on objects. It can also generate huge amounts of spam
!   from the output.
! 
    See "help DEBUG2" for more.
  & DEBUG2
    
*** 1_7_7.561/game/txt/hlp/penncmd.hlp Mon, 11 Aug 2003 13:09: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.6 600)
--- 1_7_7.623(w)/game/txt/hlp/penncmd.hlp Tue, 02 Sep 2003 10:07:16 -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)
***************
*** 8,14 ****
    pose           QUIT           read           rules          say
    score          slay           take           teach          think          
    unfollow       use            whisper        WHO            with
!   "              :              ;              +
   
    In addition to these, there are several types of '@' commands. @-commands 
    are usually commands which have permanent effects on the MUSH (such as
--- 8,14 ----
    pose           QUIT           read           rules          say
    score          slay           take           teach          think          
    unfollow       use            whisper        WHO            with
!   "              :              ;              +              ]
   
    In addition to these, there are several types of '@' commands. @-commands 
    are usually commands which have permanent effects on the MUSH (such as
***************
*** 73,78 ****
--- 73,98 ----
    @shutdown      @sitelock      @squota        @uptime        @wall
    @wizmotd       @wizwall       cd             ch             cv
   
+ & ]
+   The "]" command-prefix instructs the MUSH that the rest of the command
+   input that follows should not be evaluated. Here's an example:
+ 
+   > say [add(1,1)]
+   You say, "2"
+ 
+   > say \[add(1,1)\]
+   You say, "[add(1,1)]"
+ 
+   > ]say [add(1,1)]
+   You say, "[add(1,1)]"
+ 
+   > ]"[add(1,1)]
+   You say, "[add(1,1)]"
+   
+   This can be used to pass unevaluated MUSHcode to softcoded commands
+   without having to escape every special character, or to help objects
+   set attributes to contain unevaluated code.
+ 
  & @@
   
    The "@@" command is a special kind of command; it signals the start
***************
*** 1509,1522 ****
    @hook tells the command parser to evaluate given attributes at certain points
    in command evaluation. The possible points, indicated by the proper switch:
  
!   @hook/before: The attribute is evaluated before the command itself is run.
!   @hook/after: The attribute is evaluated after the command is run.
  
    In all cases, %# is the dbref of the object doing the command, and all
!   hooks share the same set of q-registers. The results of the evaluated
!   attribute is thrown away like it was wrapped in a call of null(). Also,
!   in cases where a command and function do the same thing (e.g., @pemit and
!   pemit()), only the command gets the hooks.
  
    Leaving out the object and attribute clears an existing hook. Wizards can
    see existing hooks with @command.
--- 1529,1553 ----
    @hook tells the command parser to evaluate given attributes at certain points
    in command evaluation. The possible points, indicated by the proper switch:
  
!   @hook/ignore: The attribute is evaluated before the built-in command is run.
!                 If it returns a false value, the command is skipped
!                 (the input is still matched against softcoded commands)
!   @hook/override: The object/attribute is matched for a $command,
!                 and if it matches, it is run instead of the built-in command,
!                 but with the precedence of the built-in command (thus
!                 overriding not only the built-in command but any local
!                 $commands that might match). If the match fails, normal
!                 built-in command processing continues. Note that all locks
!                 and flags on the object (HALT, etc.) still apply.
!   @hook/before: The attribute is evaluated before the built-in command is run.
!   @hook/after: The attribute is evaluated after the built-in command is run.
  
    In all cases, %# is the dbref of the object doing the command, and all
!   hooks share the same set of q-registers. With /before and /after, 
!   the results of the evaluated attribute is thrown away like it was
!   wrapped in a call of null(). Also, in cases where a command and function
!   do the same thing (e.g., @pemit and pemit()), only the command gets
!   the hooks.
  
    Leaving out the object and attribute clears an existing hook. Wizards can
    see existing hooks with @command.
***************
*** 1946,1951 ****
--- 1977,1983 ----
    @lock/control		Who can control this object (only if set)
    @lock/dropto		Who can trigger this container's drop-to.
    @lock/destroy		Who can destroy this object if it's DESTROY_OK
+   @lock/interact        Who can send sound (say/pose/emit/etc) to this object
  
    See also: @lock, @lset, @clock, FAILURE
  & @lset
***************
*** 2628,2633 ****
--- 2660,2666 ----
    'help @search2' for more.
  & @search2
    If <class>=EXITS, OBJECTS, ROOMS, or PLAYERS, only objects of that type
+   will be listed.
  
    If <class>=FLAGS or LFLAGS, only objects with the list of flags
    specified by <restriction> will be listed. For FLAGS, flags to match
*** 1_7_7.561/game/restart Thu, 29 May 2003 11:46:13 -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 700)
--- 1_7_7.623(w)/game/restart Wed, 03 Sep 2003 22:31:21 -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)
***************
*** 117,142 ****
  	 echo "Using save/$INDB$SUFFIX.old."
  	 cp save/$INDB$SUFFIX.old data/$INDB$SUFFIX
        else
! 	echo "No save/$INDB$SUFFIX.old found."
! 	if [ -r data/minimal.db ]; then
! 	   echo "Using data/minimal.db."
! 	   cat data/minimal.db | $COMPRESSOR > data/$INDB$SUFFIX
! 	else
! 	 if [ -r data/minimal.db.Z ]; then
! 	    echo "Using data/minimal.db.Z."
! 	    zcat data/minimal.db.Z | $COMPRESSOR > data/$INDB$SUFFIX
! 	 else
! 	    echo "No minimal.db.Z found."
! 	    if [ -r data/minimal.db.gz ]; then
! 	      echo "Using data/minimal.db.gz."
! 	      gzip -d -c data/minimal.db.gz | $COMPRESSOR > data/$INDB$SUFFIX
! 	    else
! 	      echo "No minimal.db.gz found."
! 	      echo "I can't find any usable database."
! 	    fi
! 	 fi
! 	fi
!       fi
     fi
  fi
  
--- 117,124 ----
  	 echo "Using save/$INDB$SUFFIX.old."
  	 cp save/$INDB$SUFFIX.old data/$INDB$SUFFIX
        else
! 	echo "No database found. Mush will start with a minimal world."
!      fi
     fi
  fi
  
*** 1_7_7.561/src/SWITCHES Wed, 28 May 2003 10:06:29 -0500 dunemush (pennmush/b/22_SWITCHES 1.12.1.3.1.6 600)
--- 1_7_7.623(w)/src/SWITCHES Wed, 10 Sep 2003 14:47:30 -0500 dunemush (pennmush/b/22_SWITCHES 1.12.1.3.1.7 600)
***************
*** 54,59 ****
--- 54,60 ----
  HEADER
  HERE
  HIDE
+ IGNORE
  ILIST
  INVENTORY
  IPRINT
*** 1_7_7.561/src/wiz.c Tue, 19 Aug 2003 12:07:25 -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.16 660)
--- 1_7_7.623(w)/src/wiz.c Wed, 10 Sep 2003 14:47:29 -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)
***************
*** 1686,1692 ****
      return;
    }
    if (!(Do_Quotas(executor) || See_All(executor)
! 	|| (who == executor))) {
      notify(executor, T("You can't see someone else's quota!"));
      safe_str("#-1", buff, bp);
      return;
--- 1686,1692 ----
      return;
    }
    if (!(Do_Quotas(executor) || See_All(executor)
! 	|| controls(executor, who))) {
      notify(executor, T("You can't see someone else's quota!"));
      safe_str("#-1", buff, bp);
      return;
***************
*** 2006,2011 ****
--- 2006,2014 ----
      if (paranoid_checkpt < 1)
        paranoid_checkpt = 1;
    }
+ #ifdef HAS_OPENSSL
+   close_ssl_connections();
+ #endif
    fork_and_dump(0);
  #ifndef PROFILING
  #ifndef WIN32
***************
*** 2015,2023 ****
     */
    ignore_signal(SIGPROF);
  #endif
- #ifdef HAS_OPENSSL
-   close_ssl_connections();
- #endif
  #endif
    dump_reboot_db();
  #ifdef INFO_SLAVE
--- 2018,2023 ----
*** 1_7_7.561/src/utils.c Tue, 06 May 2003 17:27:48 -0500 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.12 660)
--- 1_7_7.623(w)/src/utils.c Wed, 10 Sep 2003 14:47:29 -0500 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.14 660)
***************
*** 45,50 ****
--- 45,51 ----
  #include "flags.h"
  #include "dbdefs.h"
  #include "attrib.h"
+ #include "lock.h"
  #include "confmagic.h"
  
  dbref find_entrance(dbref door);
***************
*** 579,584 ****
--- 580,593 ----
    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)
      return lci;
*** 1_7_7.561/src/timer.c Mon, 18 Aug 2003 21:28:01 -0500 dunemush (pennmush/b/29_timer.c 1.29.1.7.1.12 660)
--- 1_7_7.623(w)/src/timer.c Wed, 10 Sep 2003 14:47:29 -0500 dunemush (pennmush/b/29_timer.c 1.29.1.7.1.13 660)
***************
*** 301,306 ****
--- 301,309 ----
    reload_sig_handler(SIGPROF, signal_cpu_limit);
  }
  #elif defined(WIN32)
+ #if _MSC_VER <= 1100 && !defined(UINT_PTR)
+ #define UINT_PTR UINT
+ #endif
  UINT_PTR timer_id;
  VOID CALLBACK
  win32_timer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
*** 1_7_7.561/src/switchinc.c Mon, 23 Jun 2003 11:10:04 -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 660)
--- 1_7_7.623(w)/src/switchinc.c Wed, 10 Sep 2003 14:47:29 -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)
***************
*** 56,61 ****
--- 56,62 ----
    {"HEADER", SWITCH_HEADER},
    {"HERE", SWITCH_HERE},
    {"HIDE", SWITCH_HIDE},
+   {"IGNORE", SWITCH_IGNORE},
    {"ILIST", SWITCH_ILIST},
    {"INVENTORY", SWITCH_INVENTORY},
    {"IPRINT", SWITCH_IPRINT},
*** 1_7_7.561/src/speech.c Tue, 06 May 2003 17:27:48 -0500 dunemush (pennmush/b/35_speech.c 1.21.1.2.1.3.1.5.1.1.1.7.1.3.1.1.1.8.1.1.1.1.1.1.1.10.1.2.1.13.2.4.1.1.3.1.1.5 660)
--- 1_7_7.623(w)/src/speech.c Wed, 10 Sep 2003 14:47:29 -0500 dunemush (pennmush/b/35_speech.c 1.21.1.2.1.3.1.5.1.1.1.7.1.3.1.1.1.8.1.1.1.1.1.1.1.10.1.2.1.13.2.4.1.1.3.1.1.5.1.1 660)
***************
*** 303,309 ****
  
    if (oneloc) {
      /* Only one room to oemit to. */
!     notify_anything(orator, na_exceptN, pass, ns_esnotify, 0, message);
      do_audible_stuff(pass[1], &pass[2], pass[0], message);
      return;
    } else if (pass[0] == 0) {
--- 303,310 ----
  
    if (oneloc) {
      /* Only one room to oemit to. */
!     notify_anything(orator, na_exceptN, pass, ns_esnotify, NA_INTER_HEAR,
! 		    message);
      do_audible_stuff(pass[1], &pass[2], pass[0], message);
      return;
    } else if (pass[0] == 0) {
***************
*** 314,325 ****
       */
      qsort((void *) locs, pass[0], sizeof(locs[0]), i_comp);
      pass[1] = locs[0];
!     notify_anything(orator, na_exceptN, pass, ns_esnotify, 0, message);
      do_audible_stuff(pass[1], &pass[2], pass[0], message);
      for (i = 1; i < pass[0]; i++) {
        if (locs[i] != locs[i - 1]) {
  	pass[1] = locs[i];
! 	notify_anything(orator, na_exceptN, pass, ns_esnotify, 0, message);
  	do_audible_stuff(pass[1], &pass[2], pass[0], message);
        }
      }
--- 315,328 ----
       */
      qsort((void *) locs, pass[0], sizeof(locs[0]), i_comp);
      pass[1] = locs[0];
!     notify_anything(orator, na_exceptN, pass, ns_esnotify, NA_INTER_HEAR,
! 		    message);
      do_audible_stuff(pass[1], &pass[2], pass[0], message);
      for (i = 1; i < pass[0]; i++) {
        if (locs[i] != locs[i - 1]) {
  	pass[1] = locs[i];
! 	notify_anything(orator, na_exceptN, pass, ns_esnotify, NA_INTER_HEAR,
! 			message);
  	do_audible_stuff(pass[1], &pass[2], pass[0], message);
        }
      }
***************
*** 382,390 ****
      current = next_in_list(start);
      who = match_result(player, current, TYPE_PLAYER, MAT_NEAR_THINGS |
  		       MAT_CONTAINER);
!     if (!GoodObject(who)) {
        safe_chr(' ', tbuf, &tp);
        safe_str_space(current, tbuf, &tp);
      } else {
        /* A good whisper */
        good[gcount++] = who;
--- 385,395 ----
      current = next_in_list(start);
      who = match_result(player, current, TYPE_PLAYER, MAT_NEAR_THINGS |
  		       MAT_CONTAINER);
!     if (!GoodObject(who) || !can_interact(player, who, INTERACT_HEAR)) {
        safe_chr(' ', tbuf, &tp);
        safe_str_space(current, tbuf, &tp);
+       if (GoodObject(who))
+ 	notify_format(player, T("%s can't hear you."), Name(who));
      } else {
        /* A good whisper */
        good[gcount++] = who;
***************
*** 1120,1130 ****
     */
  
    if (IsExit(thing)) {
!     notify_anything(orator, na_next, &Contents(loc), NULL, 0, tbuf1);
    } else {
      pass[0] = Contents(loc);
      pass[1] = thing;
!     notify_anything(orator, na_nextbut, pass, NULL, 0, tbuf1);
    }
  }
  
--- 1125,1136 ----
     */
  
    if (IsExit(thing)) {
!     notify_anything(orator, na_next, &Contents(loc), NULL, NA_INTER_HEAR,
! 		    tbuf1);
    } else {
      pass[0] = Contents(loc);
      pass[1] = thing;
!     notify_anything(orator, na_nextbut, pass, NULL, NA_INTER_HEAR, tbuf1);
    }
  }
  
***************
*** 1233,1239 ****
    pass[1] = exc1;
    pass[2] = exc2;
  
!   notify_anything(orator, na_except2, pass, ns_esnotify, 0, msg);
  
    do_audible_stuff(loc, &pass[1], 2, msg);
  }
--- 1239,1245 ----
    pass[1] = exc1;
    pass[2] = exc2;
  
!   notify_anything(orator, na_except2, pass, ns_esnotify, NA_INTER_HEAR, msg);
  
    do_audible_stuff(loc, &pass[1], 2, msg);
  }
***************
*** 1271,1277 ****
    }
  
    /* notify everybody */
!   notify_anything(player, na_loc, &loc, ns_esnotify, 0, tbuf1);
  
    do_audible_stuff(loc, NULL, 0, tbuf1);
  }
--- 1277,1283 ----
    }
  
    /* notify everybody */
!   notify_anything(player, na_loc, &loc, ns_esnotify, NA_INTER_HEAR, tbuf1);
  
    do_audible_stuff(loc, NULL, 0, tbuf1);
  }
***************
*** 1304,1310 ****
  	rmno = unparse_object(player, room);
  	notify_format(player, T("You remit, \"%s\" in %s"), msg, rmno);
        }
!       notify_anything(player, na_loc, &room, ns_esnotify, 0, msg);
        do_audible_stuff(room, NULL, 0, msg);
      }
    }
--- 1310,1316 ----
  	rmno = unparse_object(player, room);
  	notify_format(player, T("You remit, \"%s\" in %s"), msg, rmno);
        }
!       notify_anything(player, na_loc, &room, ns_esnotify, NA_INTER_HEAR, msg);
        do_audible_stuff(room, NULL, 0, msg);
      }
    }
***************
*** 1369,1375 ****
    } else {
      if (!silent && (Location(player) != room))
        notify_format(player, T("You lemit: \"%s\""), tbuf1);
!     notify_anything(player, na_loc, &room, ns_esnotify, 0, tbuf1);
    }
  }
  
--- 1375,1381 ----
    } else {
      if (!silent && (Location(player) != room))
        notify_format(player, T("You lemit: \"%s\""), tbuf1);
!     notify_anything(player, na_loc, &room, ns_esnotify, NA_INTER_HEAR, tbuf1);
    }
  }
  
***************
*** 1445,1449 ****
    pass[2] = zone;
    pass[3] = player;
    pass[4] = player;
!   notify_anything(player, na_zemit, pass, ns_esnotify, 0, arg2);
  }
--- 1451,1455 ----
    pass[2] = zone;
    pass[3] = player;
    pass[4] = player;
!   notify_anything(player, na_zemit, pass, ns_esnotify, NA_INTER_HEAR, arg2);
  }
*** 1_7_7.561/src/set.c Mon, 11 Aug 2003 14:04:21 -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.8 660)
--- 1_7_7.623(w)/src/set.c Wed, 10 Sep 2003 14:47:29 -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)
***************
*** 122,128 ****
  	}
        }
        if (strcasecmp(newname, Name(thing))
! 	  && !ok_player_name(newname)) {
  	/* strcasecmp allows changing foo to Foo, etc. */
  	notify(player, T("You can't give a player that name."));
  	return;
--- 122,128 ----
  	}
        }
        if (strcasecmp(newname, Name(thing))
! 	  && !ok_player_name(newname, thing)) {
  	/* strcasecmp allows changing foo to Foo, etc. */
  	notify(player, T("You can't give a player that name."));
  	return;
*** 1_7_7.561/src/predicat.c Mon, 11 Aug 2003 14:17:00 -0500 dunemush (pennmush/b/44_predicat.c 1.1.1.34.1.1.1.3.1.4.2.26 660)
--- 1_7_7.623(w)/src/predicat.c Wed, 10 Sep 2003 14:47:29 -0500 dunemush (pennmush/b/44_predicat.c 1.1.1.34.1.1.1.3.1.4.2.27 660)
***************
*** 697,703 ****
  }
  
  /** Is a name a valid player name?
!  * Player names must be valid object names, but also not forbidden,
   * subject to a different length limit, and subject to more stringent
   * restrictions on valid characters. Finally, it can't be the same as
   * an existing player name or alias.
--- 697,704 ----
  }
  
  /** Is a name a valid player name?
!  * Player names must be valid object names, but also not forbidden (unless
!  * the player is a wizard). They are
   * subject to a different length limit, and subject to more stringent
   * restrictions on valid characters. Finally, it can't be the same as
   * an existing player name or alias.
***************
*** 706,717 ****
   * \retval 0 name is not valid for players.
   */
  int
! ok_player_name(const char *name)
  {
    const unsigned char *scan, *good;
  
!   if (!ok_name(name) || forbidden_name(name) ||
!       strlen(name) >= (size_t) PLAYER_NAME_LIMIT)
      return 0;
  
    good = (unsigned char *) (PLAYER_NAME_SPACES ? " `$_-.,'" : "`$_-.,'");
--- 707,719 ----
   * \retval 0 name is not valid for players.
   */
  int
! ok_player_name(const char *name, dbref player)
  {
    const unsigned char *scan, *good;
  
!   if (!ok_name(name)
!       || (forbidden_name(name) && !(GoodObject(player) && Wizard(player)))
!       || strlen(name) >= (size_t) PLAYER_NAME_LIMIT)
      return 0;
  
    good = (unsigned char *) (PLAYER_NAME_SPACES ? " `$_-.,'" : "`$_-.,'");
*** 1_7_7.561/src/player.c Tue, 19 Aug 2003 12:07:25 -0500 dunemush (pennmush/b/47_player.c 1.15.1.1.1.1.1.4.1.6.1.1.1.4 660)
--- 1_7_7.623(w)/src/player.c Wed, 10 Sep 2003 14:47:28 -0500 dunemush (pennmush/b/47_player.c 1.15.1.1.1.1.1.4.1.6.1.1.1.5 660)
***************
*** 203,209 ****
  create_player(const char *name, const char *password, const char *host,
  	      const char *ip)
  {
!   if (!ok_player_name(name)) {
      do_log(LT_CONN, 0, 0, T("Failed creation (bad name) from %s"), host);
      return NOTHING;
    }
--- 203,209 ----
  create_player(const char *name, const char *password, const char *host,
  	      const char *ip)
  {
!   if (!ok_player_name(name, NOTHING)) {
      do_log(LT_CONN, 0, 0, T("Failed creation (bad name) from %s"), host);
      return NOTHING;
    }
***************
*** 254,260 ****
    dbref player;
    FILE *fp;
  
!   if (!ok_player_name(name)) {
      do_log(LT_CONN, 0, 0, T("Failed registration (bad name) from %s"), host);
      return NOTHING;
    }
--- 254,260 ----
    dbref player;
    FILE *fp;
  
!   if (!ok_player_name(name, NOTHING)) {
      do_log(LT_CONN, 0, 0, T("Failed registration (bad name) from %s"), host);
      return NOTHING;
    }
*** 1_7_7.561/src/parse.c Mon, 11 Aug 2003 16:10:20 -0500 dunemush (pennmush/b/48_parse.c 1.23.1.10.1.2.1.1.1.1.1.2.1.2.1.19 660)
--- 1_7_7.623(w)/src/parse.c Wed, 10 Sep 2003 14:47:27 -0500 dunemush (pennmush/b/48_parse.c 1.23.1.10.1.2.1.1.1.1.1.2.1.2.1.22 660)
***************
*** 465,471 ****
  
  
    if (eflags != PE_NOTHING) {
!     debugging = Debug(executor) && Connected(Owner(executor));
      if (debugging) {
        int j;
        char *debugp;
--- 465,472 ----
  
  
    if (eflags != PE_NOTHING) {
!     debugging = Debug(executor) && (Connected(Owner(executor))
! 				    || atr_get(executor, "DEBUGFORWARDLIST"));
      if (debugging) {
        int j;
        char *debugp;
***************
*** 835,845 ****
--- 836,852 ----
        (*str)++;
        if (!(eflags & PE_EVALUATE) || !(eflags & PE_FUNCTION_CHECK)) {
  	safe_chr('(', buff, bp);
+ 	if (**str == ' ') {
+ 	  safe_chr(**str, buff, bp);
+ 	  (*str)++;
+ 	}
  	if (process_expression(buff, bp, str,
  			       executor, caller, enactor,
  			       eflags & ~PE_STRIP_BRACES, PT_PAREN, pe_info))
  	  retval = 1;
  	if (**str == ')') {
+ 	  if (eflags & PE_COMPRESS_SPACES && (*str)[-1] == ' ')
+ 	    safe_chr(' ', buff, bp);
  	  safe_chr(')', buff, bp);
  	  (*str)++;
  	}
***************
*** 1148,1154 ****
  	    dbuf[0] = '\0';
  	    safe_format(dbuf, &dbp, "%s :", pe_info->debug_strings->string);
  	    *dbp = '\0';
! 	    raw_notify(Owner(executor), dbuf);
  	    pe_info->debug_strings = pe_info->debug_strings->next;
  	    mush_free((Malloc_t) pe_info->debug_strings->prev,
  		      "process_expression.debug_node");
--- 1155,1164 ----
  	    dbuf[0] = '\0';
  	    safe_format(dbuf, &dbp, "%s :", pe_info->debug_strings->string);
  	    *dbp = '\0';
! 	    if (Connected(Owner(executor)))
! 	      raw_notify(Owner(executor), dbuf);
! 	    notify_list(executor, executor, "DEBUGFORWARDLIST", dbuf,
! 			NA_NOLISTEN | NA_NOPREFIX);
  	    pe_info->debug_strings = pe_info->debug_strings->next;
  	    mush_free((Malloc_t) pe_info->debug_strings->prev,
  		      "process_expression.debug_node");
***************
*** 1161,1167 ****
  	dbuf[0] = '\0';
  	safe_format(dbuf, &dbp, "%s => %s", debugstr, startpos);
  	*dbp = '\0';
! 	raw_notify(Owner(executor), dbuf);
        } else {
  	Debug_Info *node;
  	node = pe_info->debug_strings;
--- 1171,1180 ----
  	dbuf[0] = '\0';
  	safe_format(dbuf, &dbp, "%s => %s", debugstr, startpos);
  	*dbp = '\0';
! 	if (Connected(Owner(executor)))
! 	  raw_notify(Owner(executor), dbuf);
! 	notify_list(executor, executor, "DEBUGFORWARDLIST", dbuf,
! 		    NA_NOLISTEN | NA_NOPREFIX);
        } else {
  	Debug_Info *node;
  	node = pe_info->debug_strings;
*** 1_7_7.561/src/look.c Mon, 11 Aug 2003 13:09:23 -0500 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.11 660)
--- 1_7_7.623(w)/src/look.c Wed, 10 Sep 2003 14:47:27 -0500 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.12 660)
***************
*** 437,443 ****
    /* don't give the unparse if looking through Transparent exit */
    if (style == LOOK_NORMAL || style == LOOK_AUTO) {
      PUSE;
!     tag("XCH_PAGE CLEAR=\"LINKS IMAGES PLUGINS\"");
      if (SUPPORT_PUEBLO && style == LOOK_AUTO) {
        a = atr_get(loc, "VRML_URL");
        if (a) {
--- 437,443 ----
    /* don't give the unparse if looking through Transparent exit */
    if (style == LOOK_NORMAL || style == LOOK_AUTO) {
      PUSE;
!     tag("XCH_PAGE CLEAR=\"LINKS PLUGINS\"");
      if (SUPPORT_PUEBLO && style == LOOK_AUTO) {
        a = atr_get(loc, "VRML_URL");
        if (a) {
*** 1_7_7.561/src/lock.c Mon, 11 Aug 2003 13:48:34 -0500 dunemush (pennmush/c/6_lock.c 1.17.1.13.1.1.1.1.1.6 660)
--- 1_7_7.623(w)/src/lock.c Wed, 10 Sep 2003 14:47:27 -0500 dunemush (pennmush/c/6_lock.c 1.17.1.13.1.1.1.1.1.7 660)
***************
*** 79,84 ****
--- 79,85 ----
  const lock_type Control_Lock = "Control"; /**< Name of control lock */
  const lock_type Dropto_Lock = "Dropto";	  /**< Name of dropto lock */
  const lock_type Destroy_Lock = "Destroy"; /**< Name of destroy lock */
+ const lock_type Interact_Lock = "Interact";
  /* Define new lock types here. */
  
  /** Table of lock names and permissions */
***************
*** 105,110 ****
--- 106,112 ----
    {"Control", TRUE_BOOLEXP, GOD, LF_PRIVATE | LF_OWNER, NULL},
    {"Dropto", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL},
    {"Destroy", TRUE_BOOLEXP, GOD, LF_PRIVATE | LF_OWNER, NULL},
+   {"Interact", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL},
    /* Add new lock types just before this line. */
    {NULL, TRUE_BOOLEXP, GOD, 0, NULL}
  };
*** 1_7_7.561/src/game.c Tue, 19 Aug 2003 12:07:25 -0500 dunemush (pennmush/c/10_game.c 1.50.1.8.1.1.1.1.2.1.1.1.2.1.1.4.1.1.1.1.1.1.1.1.1.1.2.1.1.2.1.1.1.1.1.1.1.2.1.1.1.2.1.1.1.1.1.1.1.1.1.5.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12 660)
--- 1_7_7.623(w)/src/game.c Wed, 10 Sep 2003 14:47:26 -0500 dunemush (pennmush/c/10_game.c 1.50.1.8.1.1.1.1.2.1.1.1.2.1.1.4.1.1.1.1.1.1.1.1.1.1.2.1.1.2.1.1.1.1.1.1.1.2.1.1.1.2.1.1.1.1.1.1.1.1.1.5.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.3 660)
***************
*** 142,147 ****
--- 142,149 ----
  void do_timestring(char *buff, char **bp, const char *format,
  		   unsigned long secs);
  
+ void create_minimal_db(void);	/* From db.c */
+ 
  dbref orator = NOTHING;	 /**< Last dbref to issue a speech command */
  
  #ifdef COMP_STATS
***************
*** 761,767 ****
  init_game_dbs(void)
  {
    FILE *f;
! 
    const char *infile, *outfile;
  #ifdef USE_MAILER
    const char *mailfile;
--- 763,769 ----
  init_game_dbs(void)
  {
    FILE *f;
!   int c;
    const char *infile, *outfile;
  #ifdef USE_MAILER
    const char *mailfile;
***************
*** 780,793 ****
  #ifdef USE_MAILER
    mailfile = options.mail_db;
  #endif
  
    /* read small text files into cache */
    fcache_init();
  
    f = db_open(infile);
  
!   if (!f)
!     return -1;
  
    /* ok, read it in */
    do_rawlog(LT_ERR, "ANALYZING: %s", infile);
--- 782,810 ----
  #ifdef USE_MAILER
    mailfile = options.mail_db;
  #endif
+   strcpy(dumpfile, outfile);
  
    /* read small text files into cache */
    fcache_init();
  
    f = db_open(infile);
  
!   if (!f) {
!     do_rawlog(LT_ERR, "Couldn't open %s! Creating minimal world.", infile);
!     init_compress(NULL);
!     create_minimal_db();
!     return 0;
!   }
! 
!   c = getc(f);
!   if (c == EOF) {
!     do_rawlog(LT_ERR, "Couldn't read %s! Creating minimal world.", infile);
!     init_compress(NULL);
!     create_minimal_db();
!     return 0;
!   }
! 
!   ungetc(c, f);
  
    /* ok, read it in */
    do_rawlog(LT_ERR, "ANALYZING: %s", infile);
***************
*** 892,900 ****
    if (panicdb)
      db_close(f);
  
-   /* set up dumper */
-   strcpy(dumpfile, outfile);
- 
    return 0;
  }
  
--- 909,914 ----
***************
*** 1522,1527 ****
--- 1536,1542 ----
    char *ptr;
    dbref thing;
    int num;
+   char save_ccom[BUFFER_LEN];
  
    ptr = atrname;
    if (!GoodObject(Location(player))) {
***************
*** 1532,1537 ****
--- 1547,1554 ----
      notify(player, T("What command do you want to scan for?"));
      return;
    }
+   strcpy(save_ccom, ccom);
+   memmove(ccom, (char *) ccom + 5, BUFFER_LEN - 5);
    if (flag & CHECK_NEIGHBORS) {
      notify(player, T("Matches on contents of this room:"));
      DOLIST(thing, Contents(Location(player))) {
***************
*** 1638,1643 ****
--- 1655,1661 ----
        }
      }
    }
+   strcpy(ccom, save_ccom);
  }
  
  #define DOL_MAP 1      /**< The map command */
*** 1_7_7.561/src/funstr.c Mon, 11 Aug 2003 19:49:47 -0500 dunemush (pennmush/c/13_funstr.c 1.28.1.1.1.2.1.4.1.6.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.3.1.5.1.3.1.2.1.1.1.1.1.1.1.1.1.10 660)
--- 1_7_7.623(w)/src/funstr.c Wed, 10 Sep 2003 14:47:26 -0500 dunemush (pennmush/c/13_funstr.c 1.28.1.1.1.2.1.4.1.6.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.3.1.5.1.3.1.2.1.1.1.1.1.1.1.1.1.11 660)
***************
*** 636,643 ****
  
    /* walk strings, copy from the appropriate string */
    for (str = args[0], rep = args[1]; *str && *rep; str++, rep++) {
!     safe_chr((*str == c) ? *rep : *str, buff, bp);
    }
  }
  
  /* ARGSUSED */
--- 636,644 ----
  
    /* walk strings, copy from the appropriate string */
    for (str = args[0], rep = args[1]; *str && *rep; str++, rep++) {
!     *str = (*str == c) ? *rep : *str;
    }
+   safe_str(args[0], buff, bp);
  }
  
  /* ARGSUSED */
*** 1_7_7.561/src/funmisc.c Mon, 16 Jun 2003 23:53:35 -0500 dunemush (pennmush/c/14_funmisc.c 1.30.1.1.1.19 660)
--- 1_7_7.623(w)/src/funmisc.c Wed, 10 Sep 2003 14:47:26 -0500 dunemush (pennmush/c/14_funmisc.c 1.30.1.1.1.22 660)
***************
*** 34,39 ****
--- 34,40 ----
  extern time_t start_time, first_start_time;
  extern int reboot_count;
  extern FUN flist[];
+ extern char ccom[BUFFER_LEN];
  static char *soundex(char *str);
  extern char cf_motd_msg[BUFFER_LEN], cf_wizmotd_msg[BUFFER_LEN],
    cf_downmotd_msg[BUFFER_LEN], cf_fullmotd_msg[BUFFER_LEN];
***************
*** 43,49 ****
  FUNCTION(fun_valid)
  {
    /* Checks to see if a given <something> is valid as a parameter of a
!    * given type (such as an object name.
     */
  
    if (!args[0] || !*args[0])
--- 44,50 ----
  FUNCTION(fun_valid)
  {
    /* Checks to see if a given <something> is valid as a parameter of a
!    * given type (such as an object name.)
     */
  
    if (!args[0] || !*args[0])
***************
*** 53,59 ****
    else if (!strcasecmp(args[0], "attrname"))
      safe_boolean(good_atr_name(upcasestr(args[1])), buff, bp);
    else if (!strcasecmp(args[0], "playername"))
!     safe_boolean(ok_player_name(args[1]), buff, bp);
    else
      safe_str("#-1", buff, bp);
  }
--- 54,60 ----
    else if (!strcasecmp(args[0], "attrname"))
      safe_boolean(good_atr_name(upcasestr(args[1])), buff, bp);
    else if (!strcasecmp(args[0], "playername"))
!     safe_boolean(ok_player_name(args[1], executor), buff, bp);
    else
      safe_str("#-1", buff, bp);
  }
***************
*** 496,501 ****
--- 497,503 ----
  FUNCTION(fun_scan)
  {
    dbref thing;
+   char save_ccom[BUFFER_LEN];
  
    thing = match_thing(executor, args[0]);
    if (!GoodObject(thing)) {
***************
*** 507,511 ****
--- 509,517 ----
      safe_str("#-1", buff, bp);
      return;
    }
+   strcpy(save_ccom, ccom);
+   strncpy(ccom, args[1], BUFFER_LEN);
+   ccom[BUFFER_LEN - 1] = '\0';
    safe_str(scan_list(thing, args[1]), buff, bp);
+   strcpy(ccom, save_ccom);
  }
*** 1_7_7.561/src/fundb.c Mon, 18 Aug 2003 20:59:29 -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.17 660)
--- 1_7_7.623(w)/src/fundb.c Wed, 10 Sep 2003 14:47:26 -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)
***************
*** 1016,1021 ****
--- 1016,1025 ----
    case 'T':
      safe_boolean(IsThing(it), buff, bp);
      break;
+   case 'g':
+   case 'G':
+     safe_boolean(IsGarbage(it), buff, bp);
+     break;
    default:
      safe_str(T("#-1 NO SUCH TYPE"), buff, bp);
      break;
***************
*** 1821,1827 ****
      }
    }
    if (!Search_All(executor)) {
!     if (who != ANY_OWNER && who != executor) {
        safe_str(T(e_perm), buff, bp);
        return;
      }
--- 1825,1831 ----
      }
    }
    if (!Search_All(executor)) {
!     if (who != ANY_OWNER && !controls(executor, who)) {
        safe_str(T(e_perm), buff, bp);
        return;
      }
*** 1_7_7.561/src/flags.c Mon, 18 Aug 2003 20:59:29 -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.53 660)
--- 1_7_7.623(w)/src/flags.c Wed, 10 Sep 2003 14:47:26 -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)
***************
*** 104,110 ****
    {"ANSI", 'A', TYPE_PLAYER, PLAYER_ANSI, F_ANY, F_ANY},
    {"COLOR", 'C', TYPE_PLAYER, PLAYER_COLOR, F_ANY, F_ANY},
    {"MONITOR", 'M', TYPE_PLAYER | TYPE_ROOM | TYPE_THING, 0, F_ANY, F_ANY},
!   {"NOSPOOF", 'N', TYPE_PLAYER, PLAYER_NOSPOOF, F_ANY | F_ODARK,
     F_ANY | F_ODARK},
    {"SHARED", 'Z', TYPE_PLAYER, PLAYER_ZONE, F_ANY, F_ANY},
    {"CONNECTED", 'c', TYPE_PLAYER, PLAYER_CONNECT, F_INTERNAL | F_MDARK,
--- 104,110 ----
    {"ANSI", 'A', TYPE_PLAYER, PLAYER_ANSI, F_ANY, F_ANY},
    {"COLOR", 'C', TYPE_PLAYER, PLAYER_COLOR, F_ANY, F_ANY},
    {"MONITOR", 'M', TYPE_PLAYER | TYPE_ROOM | TYPE_THING, 0, F_ANY, F_ANY},
!   {"NOSPOOF", '"', TYPE_PLAYER, PLAYER_NOSPOOF, F_ANY | F_ODARK,
     F_ANY | F_ODARK},
    {"SHARED", 'Z', TYPE_PLAYER, PLAYER_ZONE, F_ANY, F_ANY},
    {"CONNECTED", 'c', TYPE_PLAYER, PLAYER_CONNECT, F_INTERNAL | F_MDARK,
***************
*** 125,131 ****
  #endif
    {"SUSPECT", 's', TYPE_PLAYER, PLAYER_SUSPECT, F_WIZARD | F_MDARK,
     F_WIZARD | F_MDARK},
!   {"PARANOID", 'p', TYPE_PLAYER, PLAYER_PARANOID, F_ANY | F_ODARK,
     F_ANY | F_ODARK},
    {"NOACCENTS", '~', TYPE_PLAYER, PLAYER_NOACCENTS, F_ANY, F_ANY},
    {"DESTROY_OK", 'd', TYPE_THING, THING_DEST_OK, F_ANY, F_ANY},
--- 125,131 ----
  #endif
    {"SUSPECT", 's', TYPE_PLAYER, PLAYER_SUSPECT, F_WIZARD | F_MDARK,
     F_WIZARD | F_MDARK},
!   {"PARANOID", '\0', TYPE_PLAYER, PLAYER_PARANOID, F_ANY | F_ODARK,
     F_ANY | F_ODARK},
    {"NOACCENTS", '~', TYPE_PLAYER, PLAYER_NOACCENTS, F_ANY, F_ANY},
    {"DESTROY_OK", 'd', TYPE_THING, THING_DEST_OK, F_ANY, F_ANY},
***************
*** 340,349 ****
  static FLAG *
  new_flag(void)
  {
!   /* We don't use mush_malloc, because these sometimes get freed
!    * by ptab_free, which doesn't know how to handle the memcheck
!    */
!   FLAG *f = (FLAG *) malloc(sizeof(FLAG));
    if (!f)
      panic("Unable to allocate memory for a new flag!\n");
    return f;
--- 340,346 ----
  static FLAG *
  new_flag(void)
  {
!   FLAG *f = (FLAG *) mush_malloc(sizeof(FLAG), "flag");
    if (!f)
      panic("Unable to allocate memory for a new flag!\n");
    return f;
***************
*** 365,371 ****
  clone_flag(FLAG *f)
  {
    FLAG *clone = new_flag();
!   clone->name = strdup(f->name);
    clone->letter = f->letter;
    clone->type = f->type;
    clone->bitpos = f->bitpos;
--- 362,368 ----
  clone_flag(FLAG *f)
  {
    FLAG *clone = new_flag();
!   clone->name = mush_strdup(f->name, "flag name");
    clone->letter = f->letter;
    clone->type = f->type;
    clone->bitpos = f->bitpos;
***************
*** 471,479 ****
  {
    FLAG *f;
    char *c;
!   c = strdup(getstring_noalloc(in));
    if (!strcmp(c, "FLAG ALIASES")) {
!     free((Malloc_t) c);
      return NULL;		/* We're done */
    }
    f = new_flag();
--- 468,476 ----
  {
    FLAG *f;
    char *c;
!   c = mush_strdup(getstring_noalloc(in), "flag name");
    if (!strcmp(c, "FLAG ALIASES")) {
!     mush_free(c, "flag name");
      return NULL;		/* We're done */
    }
    f = new_flag();
***************
*** 493,501 ****
    FLAG *f;
    char *c;
    /* Real name first */
!   c = strdup(getstring_noalloc(in));
    if (!strcmp(c, "END OF FLAGS")) {
!     free((Malloc_t) c);
      return NULL;		/* We're done */
    }
    f = match_flag(c);
--- 490,498 ----
    FLAG *f;
    char *c;
    /* Real name first */
!   c = mush_strdup(getstring_noalloc(in), "flag alias");
    if (!strcmp(c, "END OF FLAGS")) {
!     mush_free(c, "flag alias");
      return NULL;		/* We're done */
    }
    f = match_flag(c);
***************
*** 505,516 ****
  	      T
  	      ("FLAG READ: flag alias %s matches no known flag. Skipping aliases."),
  	      c);
!     free((Malloc_t) c);
      do {
        c = (char *) getstring_noalloc(in);
      } while (strcmp(c, "END OF FLAGS"));
      return NULL;
!   }
    /* Get the alias name */
    strcpy(alias, getstring_noalloc(in));
    return f;
--- 502,515 ----
  	      T
  	      ("FLAG READ: flag alias %s matches no known flag. Skipping aliases."),
  	      c);
!     mush_free(c, "flag alias");
      do {
        c = (char *) getstring_noalloc(in);
      } while (strcmp(c, "END OF FLAGS"));
      return NULL;
!   } else
!     mush_free(c, "flag alias");
! 
    /* Get the alias name */
    strcpy(alias, getstring_noalloc(in));
    return f;
***************
*** 671,676 ****
--- 670,683 ----
    add_flag("ORPHAN", 'i', NOTYPE, F_ANY, F_ANY);
    if ((f = match_flag("TERSE")))
      f->type |= TYPE_THING;
+   if ((f = match_flag("NOSPOOF"))) {
+     f->type = NOTYPE;
+     f->letter = '"';
+   }
+   if ((f = match_flag("PARANOID"))) {
+     f->type = NOTYPE;
+     f->letter = '\0';
+   }
    local_flags();
  }
  
***************
*** 1003,1009 ****
    }
    if (!str)
      return bitmask;		/* We're done, then */
!   copy = strdup(str);
    s = trim_space_sep(copy, ' ');
    while (s) {
      sp = split_token(&s, ' ');
--- 1010,1016 ----
    }
    if (!str)
      return bitmask;		/* We're done, then */
!   copy = mush_strdup(str, "flagstring");
    s = trim_space_sep(copy, ' ');
    while (s) {
      sp = split_token(&s, ' ');
***************
*** 1012,1018 ****
        continue;
      set_flag_bitmask(bitmask, f->bitpos);
    }
!   free(copy);
    return bitmask;
  }
  
--- 1019,1025 ----
        continue;
      set_flag_bitmask(bitmask, f->bitpos);
    }
!   mush_free(copy, "flagstring");
    return bitmask;
  }
  
***************
*** 1483,1489 ****
        /* Otherwise, we don't need to do anything. */
      }
    }
!   return (ret);
  }
  
  /** Check if an object has one or all of a list of flag names.
--- 1490,1496 ----
        /* Otherwise, we don't need to do anything. */
      }
    }
!   return ret;
  }
  
  /** Check if an object has one or all of a list of flag names.
***************
*** 1513,1519 ****
      do_rawlog(LT_ERR, T("FLAG: Unable to locate flagspace %s"), ns);
      return 0;
    }
!   copy = strdup(fstr);
    sp = trim_space_sep(copy, ' ');
    while (sp) {
      s = split_token(&sp, ' ');
--- 1520,1526 ----
      do_rawlog(LT_ERR, T("FLAG: Unable to locate flagspace %s"), ns);
      return 0;
    }
!   copy = mush_strdup(fstr, "flaglistlong");
    sp = trim_space_sep(copy, ' ');
    while (sp) {
      s = split_token(&sp, ' ');
***************
*** 1527,1545 ****
        negate = 0;		/* It's important to clear this at appropriate times;
  				 * else !D c means (!D && !c), instead of (!D && c). */
      }
!     if (!*s)
        /* We got a '!' that wasn't followed by a string.
         * Fail the check. */
!       return (type == 1) ? 0 : ret;
      /* Find the flag. */
      if (!(fp = flag_hash_lookup(n, s, Typeof(it)))) {
        /* Either we got a '!' that wasn't followed by a letter, or
         * we couldn't find that flag. For AND, since we've failed
         * a check, we can return false. Otherwise we just go on.
         */
!       if (type == 1)
! 	return 0;
!       else
  	continue;
      } else {
        /* does the object have this flag? There's a special case
--- 1534,1556 ----
        negate = 0;		/* It's important to clear this at appropriate times;
  				 * else !D c means (!D && !c), instead of (!D && c). */
      }
!     if (!*s) {
        /* We got a '!' that wasn't followed by a string.
         * Fail the check. */
!       if (type == 1)
! 	ret = 0;
!       break;
!     }
      /* Find the flag. */
      if (!(fp = flag_hash_lookup(n, s, Typeof(it)))) {
        /* Either we got a '!' that wasn't followed by a letter, or
         * we couldn't find that flag. For AND, since we've failed
         * a check, we can return false. Otherwise we just go on.
         */
!       if (type == 1) {
! 	ret = 0;
! 	break;
!       } else
  	continue;
      } else {
        /* does the object have this flag? There's a special case
***************
*** 1562,1568 ****
  	 * it, or we don't have a flag and we want it. Since it's
  	 * AND, we return false.
  	 */
! 	return 0;
        } else if ((type == 0) && ((!negate && temp) || (negate && !temp))) {
  	/* We've found something we want, in an OR. We OR a
  	 * true with the current value.
--- 1573,1580 ----
  	 * it, or we don't have a flag and we want it. Since it's
  	 * AND, we return false.
  	 */
! 	ret = 0;
! 	break;
        } else if ((type == 0) && ((!negate && temp) || (negate && !temp))) {
  	/* We've found something we want, in an OR. We OR a
  	 * true with the current value.
***************
*** 1572,1578 ****
        /* Otherwise, we don't need to do anything. */
      }
    }
!   return (ret);
  }
  
  
--- 1584,1591 ----
        /* Otherwise, we don't need to do anything. */
      }
    }
!   mush_free(copy, "flaglistlong");
!   return ret;
  }
  
  
***************
*** 1620,1626 ****
      return;
    n = hashfind("FLAG", &htab_flagspaces);
    f = new_flag();
!   f->name = strdup(strupper(name));
    f->letter = letter;
    f->type = type;
    f->perms = perms;
--- 1633,1639 ----
      return;
    n = hashfind("FLAG", &htab_flagspaces);
    f = new_flag();
!   f->name = mush_strdup(strupper(name), "flag name");
    f->letter = letter;
    f->type = type;
    f->perms = perms;
***************
*** 1987,1994 ****
    /* Remove the flag from the ptab */
    ptab_delete(n->tab, f->name);
    notify_format(player, T("Flag %s deleted."), f->name);
!   /* Free the flag. Don't use mush_free, see new_flag() */
!   free((Malloc_t) f);
  }
  
  /** Enable a disabled flag.
--- 2000,2008 ----
    /* Remove the flag from the ptab */
    ptab_delete(n->tab, f->name);
    notify_format(player, T("Flag %s deleted."), f->name);
!   /* Free the flag. */
!   mush_free((char *) f->name, "flag name");
!   mush_free(f, "flag");
  }
  
  /** Enable a disabled flag.
*** 1_7_7.561/src/filecopy.c Sun, 01 Dec 2002 21:14:41 -0600 dunemush (pennmush/c/21_filecopy.c 1.77 660)
--- 1_7_7.623(w)/src/filecopy.c Wed, 10 Sep 2003 14:47:26 -0500 dunemush (pennmush/c/21_filecopy.c 1.80 660)
***************
*** 1,321 ****
! /* Win32 services routines */
! 
! /* Author: Nick Gammon */
! 
! #ifdef WIN32
! 
! #include "copyrite.h"
! #include "config.h"
! 
! #include <windows.h>		/* for find first */
! 
! #include <stdlib.h>
! #include <process.h>
! #include <direct.h>
! 
! #include "conf.h"
! #include "mushdb.h"
! #include "match.h"
! #include "externs.h"
! #include "mymalloc.h"
! #include "log.h"
! #include "confmagic.h"
! 
! /* This is bad, but only for WIN32, which is bad anyway... */
! #define EMBEDDED_MKINDX
! 
! static char buff[1024];
! 
! BOOL
! ConcatenateFiles(const char *path, const char *outputfile)
  {
!   HANDLE filscan;
!   WIN32_FIND_DATA fildata;
!   BOOL filflag;
!   DWORD status;
!   FILE *fo = NULL;
!   FILE *f = NULL;
!   size_t bytes_in, bytes_out;
!   long total_bytes = 0;
!   int total_files = 0;
!   char directory[MAX_PATH];
!   char fullname[MAX_PATH];
! 
!   char *p;
! 
!   /* If outputfile is an empty string, forget it. */
!   if (!outputfile || !*outputfile)
!     return FALSE;
! 
! /* extract the directory from the path name */
! 
!   strcpy(directory, path);
!   p = strrchr(directory, '\\');
!   if (p)
!     p[1] = 0;
    else {
!     p = strrchr(directory, '/');
!     if (p)
!       p[1] = 0;
!   }
! 
! /* Open output file */
! 
!   fo = fopen(outputfile, "wb");
! 
!   if (!fo) {
!     do_rawlog(LT_ERR, T("Unable to open file: %s"), outputfile);
!     return FALSE;
!   }
!   do_rawlog(LT_ERR, T("Creating file: %s"), outputfile);
! 
! /* Find first file matching the wildcard */
! 
!   filscan = FindFirstFile(path, &fildata);
!   if (filscan == INVALID_HANDLE_VALUE) {
!     status = GetLastError();
! 
!     fclose(fo);
! 
!     do_rawlog(LT_ERR, "**** No files matching: \"%s\" found.", path);
! 
!     if (status == ERROR_NO_MORE_FILES)
!       return TRUE;
      else
!       return FALSE;
!   }
! /*
!    Now enter the concatenation loop.
!  */
! 
    do {
!     if (!(fildata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
! 
!       do_rawlog(LT_ERR, "%s: %s, %ld %s",
! 		T("    Copying file"),
! 		fildata.cFileName,
! 		fildata.nFileSizeLow,
! 		fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"));
! 
!       strcpy(fullname, directory);
!       strcat(fullname, fildata.cFileName);
! 
! /* Open the input file */
! 
!       f = fopen(fullname, "rb");
! 
!       if (!f)
! 	do_rawlog(LT_ERR, T("    ** Unable to open file: %s"), fullname);
        else {
! 
! 	total_files++;
! 
! 	/* do the copy loop */
! 
! 	while (!feof(f)) {
! 	  bytes_in = fread(buff, 1, sizeof(buff), f);
! 	  if (bytes_in <= 0)
! 	    break;
! 
! 	  bytes_out = fwrite(buff, 1, bytes_in, fo);
! 	  total_bytes += bytes_out;
! 	  if (bytes_in != bytes_out) {
! 	    do_rawlog(LT_ERR, T("Unable to write to file: %s"), outputfile);
! 	    fclose(f);
! 	    break;
! 	  }
! 	}			/* end of copy loop */
! 
! 
! 	fclose(f);
!       }				/* end of being able to open file */
! 
!     }
!     /* end of not being a directory */
!     /* get next file matching the wildcard */
!     filflag = FindNextFile(filscan, &fildata);
!   } while (filflag);
! 
!   status = GetLastError();
! 
!   FindClose(filscan);
! 
!   fclose(fo);
! 
!   do_rawlog(LT_ERR, T("Copied %i %s, %ld %s"),
! 	    total_files,
! 	    total_files == 1 ? T("file") : T("files"),
! 	    total_bytes, total_bytes == 1 ? T("byte") : T("bytes"));
! 
!   if (status == ERROR_NO_MORE_FILES)
!     return TRUE;
    else
!     return FALSE;
! 
! }
! 
! int
! CheckDatabase(const char *path, FILETIME * modified, long *filesize)
  {
!   HANDLE filscan;
!   WIN32_FIND_DATA fildata;
!   SYSTEMTIME st;
!   static char *months[] = {
!     ">!<",
!     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
!     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
!   FILE *f;
!   size_t bytes;
! 
!   filscan = FindFirstFile(path, &fildata);
!   if (filscan == INVALID_HANDLE_VALUE) {
!     do_rawlog(LT_ERR, "File \"%s\" not found.", path);
!     return FALSE;
!   }
!   *modified = fildata.ftLastWriteTime;
!   *filesize = fildata.nFileSizeLow;
! 
!   FindClose(filscan);
! 
!   FileTimeToSystemTime(&fildata.ftLastWriteTime, &st);
! 
!   if (st.wMonth < 1 || st.wMonth > 12)
!     st.wMonth = 0;
! 
!   do_rawlog(LT_ERR,
! 	    T
! 	    ("File \"%s\" found, size %ld %s, modified on %02d %s %04d %02d:%02d:%02d"),
! 	    path, fildata.nFileSizeLow,
! 	    fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"), st.wDay,
! 	    months[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
! 
!   if (fildata.nFileSizeHigh == 0 && fildata.nFileSizeLow < 80) {
!     do_rawlog(LT_ERR, T("File is too small to be a MUSH database."));
!     return FALSE;
!   }
! /* check file for validity */
! 
!   f = fopen(path, "rb");
! 
!   if (!f) {
!     do_rawlog(LT_ERR, T("Unable to open file %s"), path);
!     return FALSE;
!   }
!   if (fseek(f, -80, SEEK_END) != 0) {
!     do_rawlog(LT_ERR, T("Unable to check file %s"), path);
!     fclose(f);
!     return FALSE;
!   }
!   bytes = fread(buff, 1, 80, f);
! 
!   fclose(f);
! 
!   if (bytes != 80) {
!     do_rawlog(LT_ERR, T("Unable to read last part of file %s"), path);
!     return FALSE;
!   }
!   if (strstr(buff, "***END OF DUMP***") == 0) {
!     do_rawlog(LT_ERR, T("Database not terminated correctly, file %s"), path);
!     return FALSE;
!   }
!   return TRUE;
! 
! }				/* end of  CheckDatabase */
! 
! void
! Win32MUSH_setup(void)
  {
  
!   int indb_OK, outdb_OK, panicdb_OK;
! 
!   FILETIME indb_time, outdb_time, panicdb_time;
! 
!   long indb_size, outdb_size, panicdb_size;
! 
!   char FileName[256];
! 
!   if (GetModuleFileName(NULL, FileName, 256) != 0) {
!     if (!strcasecmp(rindex(FileName, '\\') + 1, "pennmush.exe")) {
!       if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) {
! 	do_rawlog(LT_ERR, "Successfully copied executable, starting copy.");
! 	execl("pennmush_run.exe", "pennmush_run.exe", "/run", NULL);
!       }
!     }
!   }
! 
!   ConcatenateFiles("txt\\hlp\\*.hlp", "txt\\help.txt");
!   ConcatenateFiles("txt\\nws\\*.nws", "txt\\news.txt");
!   ConcatenateFiles("txt\\evt\\*.evt", "txt\\events.txt");
!   ConcatenateFiles("txt\\rul\\*.rul", "txt\\rules.txt");
!   ConcatenateFiles("txt\\idx\\*.idx", "txt\\index.txt");
! 
!   indb_OK = CheckDatabase(options.input_db, &indb_time, &indb_size);
!   outdb_OK = CheckDatabase(options.output_db, &outdb_time, &outdb_size);
!   panicdb_OK = CheckDatabase(options.crash_db, &panicdb_time, &panicdb_size);
! 
!   if (indb_OK) {		/* Look at outdb */
!     if (outdb_OK) {		/* Look at panicdb */
!       if (panicdb_OK) {		/* outdb or panicdb or indb */
! 	if (CompareFileTime(&panicdb_time, &outdb_time) > 0) {	/* panicdb or indb */
! 
! 	  if (CompareFileTime(&panicdb_time, &indb_time) > 0) {	/* panicdb */
! 
! 	    ConcatenateFiles(options.crash_db, options.input_db);
! 	  } else {		/* indb */
! 	  }
! 	} else {		/* outdb or indb */
! 	  if (CompareFileTime(&outdb_time, &indb_time) > 0) {	/* outdb */
! 
! 	    ConcatenateFiles(options.output_db, options.input_db);
! 	  } else {		/* indb */
! 	  }
! 	}
!       } else {			/* outdb or indb */
! 	if (CompareFileTime(&outdb_time, &indb_time) > 0) {	/* outdb */
! 
! 	  ConcatenateFiles(options.output_db, options.input_db);
! 	} else {		/* indb */
! 	}
!       }
!     } else {			/* outdb not OK */
!       if (panicdb_OK) {		/* panicdb or indb */
! 	if (CompareFileTime(&panicdb_time, &indb_time) > 0) {	/* panicdb */
! 
! 	  ConcatenateFiles(options.crash_db, options.input_db);
! 	} else {		/* indb */
! 	}
!       } else {			/* indb */
!       }
!     }
!   } else {			/* indb not OK */
!     if (outdb_OK) {		/* look at panicdb */
!       if (panicdb_OK) {		/* out or panic */
! 	if (CompareFileTime(&panicdb_time, &outdb_time) > 0) {	/* panicdb */
! 
! 	  ConcatenateFiles(options.crash_db, options.input_db);
! 	} else {		/* outdb */
! 
! 	  ConcatenateFiles(options.output_db, options.input_db);
! 	}
!       } else {			/* outdb */
! 	ConcatenateFiles(options.output_db, options.input_db);
!       }
!     } else {			/* outdb not OK */
!       if (panicdb_OK) {		/* panicdb */
! 	ConcatenateFiles(options.crash_db, options.input_db);
!       } else {			/* NOTHING */
! 	exit(-1);
!       }
!     }
!   }
! /* Final failsafe - input database SHOULD still be OK. */
!   do_rawlog(LT_ERR, T("Verifying selected database."));
!   if (!CheckDatabase(options.input_db, &indb_time, &indb_size)) {
!     do_rawlog(LT_ERR, T("File corrupted during selection process."));
!     exit(-1);
!   } else {
!     do_rawlog(LT_ERR, T("Input database verified. Proceeding to analysis."));
!   }
! }
! #endif				/* WIN32 */
--- 1,275 ----
! /* Win32 services routines */  
!   
! /* Author: Nick Gammon */ 
!   
! #ifdef WIN32
!   
! #include "copyrite.h"
! #include "config.h"
!   
! #include <windows.h>            /* for find first */
!   
! #include <stdlib.h>
! #include <process.h>
! #include <direct.h>
!   
! #include "conf.h"
! #include "mushdb.h"
! #include "match.h"
! #include "externs.h"
! #include "mymalloc.h"
! #include "log.h"
! #include "confmagic.h"
!   
! /* This is bad, but only for WIN32, which is bad anyway... */ 
! #define EMBEDDED_MKINDX
! 
static char buff[1024];
! 

BOOL 
 ConcatenateFiles(const char *path, const char *outputfile) 
  {
!   
HANDLE filscan;
!   
WIN32_FIND_DATA fildata;
!   
BOOL filflag;
!   
DWORD status;
!   
FILE * fo = NULL;
!   
FILE * f = NULL;
!   
size_t bytes_in, bytes_out;
!   
long total_bytes = 0;
!   
int total_files = 0;
!   
char directory[MAX_PATH];
!   
char fullname[MAX_PATH];
!   

char *p;
!   
!     /* If outputfile is an empty string, forget it. */ 
!     if (!outputfile || !*outputfile)
!     
return FALSE;
!   
! /* extract the directory from the path name */ 
!     
strcpy(directory, path);
!   
p = strrchr(directory, '\\');
!   
if (p)
!     
p[1] = 0;
!   
    else {
!     
p = strrchr(directory, '/');
!     
if (p)
!       
p[1] = 0;
!   
}
!   
! /* Open output file */ 
!     
fo = fopen(outputfile, "wb");
!   

if (!fo) {
!     
do_rawlog(LT_ERR, T("Unable to open file: %s"), outputfile);
!     
return FALSE;
!   
}
!   
do_rawlog(LT_ERR, T("Creating file: %s"), outputfile);
!   
! /* Find first file matching the wildcard */ 
!     
filscan = FindFirstFile(path, &fildata);
!   
if (filscan == INVALID_HANDLE_VALUE) {
!     
status = GetLastError();
!     

fclose(fo);
!     

do_rawlog(LT_ERR, "**** No files matching: \"%s\" found.", path);
!     

if (status == ERROR_NO_MORE_FILES)
!       
return TRUE;
!     
      else
!       
return FALSE;
!   
}
!   
! /*
!    Now enter the concatenation loop.
!  */ 
!     
    do {
!     
if (!(fildata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
!       

do_rawlog(LT_ERR, "%s: %s, %ld %s", 
T("    Copying file"),
! 		  
fildata.cFileName, 
fildata.nFileSizeLow,
! 		  
fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"));
!       

strcpy(fullname, directory);
!       
strcat(fullname, fildata.cFileName);
!       
! /* Open the input file */ 
! 	
f = fopen(fullname, "rb");
!       

if (!f)
! 	
do_rawlog(LT_ERR, T("    ** Unable to open file: %s"), fullname);
!       
        else {
! 	

total_files++;
! 	
! 	  /* do the copy loop */ 
! 	  
while (!feof(f)) {
! 	  
bytes_in = fread(buff, 1, sizeof(buff), f);
! 	  
if (bytes_in <= 0)
! 	    
break;
! 	  

bytes_out = fwrite(buff, 1, bytes_in, fo);
! 	  
total_bytes += bytes_out;
! 	  
if (bytes_in != bytes_out) {
! 	    
do_rawlog(LT_ERR, T("Unable to write to file: %s"), outputfile);
! 	    
fclose(f);
! 	    
break;
! 	  
}
! 	
}			/* end of copy loop */
! 	


fclose(f);
!       
}			/* end of being able to open file */
!     

}
!     
!       /* end of not being a directory */ 
!       /* get next file matching the wildcard */ 
!       filflag = FindNextFile(filscan, &fildata);
!   
} while (filflag);
!   

status = GetLastError();
!   

FindClose(filscan);
!   

fclose(fo);
!   

do_rawlog(LT_ERR, T("Copied %i %s, %ld %s"), 
total_files,
! 	      
total_files == 1 ? T("file") : T("files"), 
total_bytes,
! 	      total_bytes == 1 ? T("byte") : T("bytes"));
!   

if (status == ERROR_NO_MORE_FILES)
!     
return TRUE;
!   
    else
!     
return FALSE;
! 

}
! 

int 
! CheckDatabase(const char *path, FILETIME * modified, long *filesize) 
  {
!   
HANDLE filscan;
!   
WIN32_FIND_DATA fildata;
!   
SYSTEMTIME st;
!   
static char *months[] =
!     { 
">!<", 
"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
"Jul", "Aug", "Sep",
!     "Oct", "Nov", "Dec" 
    };
!   
FILE * f;
!   
size_t bytes;
!   

filscan = FindFirstFile(path, &fildata);
!   
if (filscan == INVALID_HANDLE_VALUE) {
!     
do_rawlog(LT_ERR, "File \"%s\" not found.", path);
!     
return FALSE;
!   
}
!   
*modified = fildata.ftLastWriteTime;
!   
*filesize = fildata.nFileSizeLow;
!   

FindClose(filscan);
!   

FileTimeToSystemTime(&fildata.ftLastWriteTime, &st);
!   

if (st.wMonth < 1 || st.wMonth > 12)
!     
st.wMonth = 0;
!   

do_rawlog(LT_ERR, 
T 
! 	      ("File \"%s\" found, size %ld %s, modified on %02d %s %04d %02d:%02d:%02d"),
! 	      
path, fildata.nFileSizeLow,
! 	      
fildata.nFileSizeLow == 1 ? T("byte") : T("bytes"), st.wDay,
! 	      
months[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
!   

if (fildata.nFileSizeHigh == 0 && fildata.nFileSizeLow < 80) {
!     
do_rawlog(LT_ERR, T("File is too small to be a MUSH database."));
!     
return FALSE;
!   
}
!   
! /* check file for validity */ 
!     
f = fopen(path, "rb");
!   

if (!f) {
!     
do_rawlog(LT_ERR, T("Unable to open file %s"), path);
!     
return FALSE;
!   
}
!   
if (fseek(f, -80, SEEK_END) != 0) {
!     
do_rawlog(LT_ERR, T("Unable to check file %s"), path);
!     
fclose(f);
!     
return FALSE;
!   
}
!   
bytes = fread(buff, 1, 80, f);
!   

fclose(f);
!   

if (bytes != 80) {
!     
do_rawlog(LT_ERR, T("Unable to read last part of file %s"), path);
!     
return FALSE;
!   
}
!   
if (strstr(buff, "***END OF DUMP***") == 0) {
!     
do_rawlog(LT_ERR, T("Database not terminated correctly, file %s"), path);
!     
return FALSE;
!   
}
!   
return TRUE;
! 

}				/* end of  CheckDatabase */
! 

void 
! Win32MUSH_setup(void) 
  {
+   

int indb_OK, outdb_OK, panicdb_OK;
+   

FILETIME indb_time, outdb_time, panicdb_time;
+   

long indb_size, outdb_size, panicdb_size;
+   

char FileName[256];
+   
+ #ifndef _DEBUG
+     
if (GetModuleFileName(NULL, FileName, 256) != 0) {
+     
if (!strcasecmp(rindex(FileName, '\\') + 1, "pennmush.exe")) {
+       
if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) {
+ 	
do_rawlog(LT_ERR, "Successfully copied executable, starting copy.");
+ 	
execl("pennmush_run.exe", "pennmush_run.exe", "/run", NULL);
+       
}
+     
}
+   
}
+   
+ #endif				/* 
 */
+     
ConcatenateFiles("txt\\hlp\\*.hlp", "txt\\help.txt");
+   
ConcatenateFiles("txt\\nws\\*.nws", "txt\\news.txt");
+   
ConcatenateFiles("txt\\evt\\*.evt", "txt\\events.txt");
+   
ConcatenateFiles("txt\\rul\\*.rul", "txt\\rules.txt");
+   
ConcatenateFiles("txt\\idx\\*.idx", "txt\\index.txt");
+   

indb_OK = CheckDatabase(options.input_db, &indb_time, &indb_size);
+   
outdb_OK = CheckDatabase(options.output_db, &outdb_time, &outdb_size);
+   
panicdb_OK = CheckDatabase(options.crash_db, &panicdb_time, &panicdb_size);
+   

if (indb_OK) {		/* Look at outdb */
+     
if (outdb_OK) {		/* Look at panicdb */
+       
if (panicdb_OK) {	/* outdb or panicdb or indb */
+ 	
if (CompareFileTime(&panicdb_time, &outdb_time) > 0) {	/* panicdb or indb */
+ 	  

if (CompareFileTime(&panicdb_time, &indb_time) > 0) {	/* panicdb */
+ 	    

ConcatenateFiles(options.crash_db, options.input_db);
+ 	  
} else {		/* indb */
+ 	  
}
+ 	
} else {		/* outdb or indb */
+ 	  
if (CompareFileTime(&outdb_time, &indb_time) > 0) {	/* outdb */
+ 	    

ConcatenateFiles(options.output_db, options.input_db);
+ 	  
} else {		/* indb */
+ 	  
}
+ 	
}
+       
} else {			/* outdb or indb */
+ 	
if (CompareFileTime(&outdb_time, &indb_time) > 0) {	/* outdb */
+ 	  

ConcatenateFiles(options.output_db, options.input_db);
+ 	
} else {		/* indb */
+ 	
}
+       
}
+     
} else {			/* outdb not OK */
+       
if (panicdb_OK) {	/* panicdb or indb */
+ 	
if (CompareFileTime(&panicdb_time, &indb_time) > 0) {	/* panicdb */
+ 	  

ConcatenateFiles(options.crash_db, options.input_db);
+ 	
} else {		/* indb */
+ 	
}
+       
} else {			/* indb */
+       
}
+     
}
+   
} else {			/* indb not OK */
+     
if (outdb_OK) {		/* look at panicdb */
+       
if (panicdb_OK) {	/* out or panic */
+ 	
if (CompareFileTime(&panicdb_time, &outdb_time) > 0) {	/* panicdb */
+ 	  

ConcatenateFiles(options.crash_db, options.input_db);
+ 	
} else {		/* outdb */
+ 	  

ConcatenateFiles(options.output_db, options.input_db);
+ 	
}
+       
} else {			/* outdb */
+ 	
ConcatenateFiles(options.output_db, options.input_db);
+       
}
+     
} else {			/* outdb not OK */
+       
if (panicdb_OK) {	/* panicdb */
+ 	
ConcatenateFiles(options.crash_db, options.input_db);
+       
} else {			/* NOTHING */
+ 	
exit(-1);
+       
}
+     
}
+   
}
+   
+ /* Final failsafe - input database SHOULD still be OK. */ 
+     do_rawlog(LT_ERR, T("Verifying selected database."));
+   
if (!CheckDatabase(options.input_db, &indb_time, &indb_size)) {
+     
do_rawlog(LT_ERR, T("File corrupted during selection process."));
+     
exit(-1);
+   
} else {
+     
do_rawlog(LT_ERR, T("Input database verified. Proceeding to analysis."));
+   
}
+ 
}
  
! 
! #endif	/* WIN32 */
*** 1_7_7.561/src/extchat.c Mon, 11 Aug 2003 13:48:34 -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 660)
--- 1_7_7.623(w)/src/extchat.c Wed, 10 Sep 2003 14:47:26 -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)
***************
*** 974,980 ****
  		    T("CHAT: You join %s to channel <%s>."), Name(victim),
  		    ChanName(chan));
        if (!Channel_Quiet(chan) && !DarkLegal(victim))
! 	channel_broadcast(chan, victim, 1,
  			  T("<%s> %s has joined this channel."), ChanName(chan),
  			  Name(victim));
        ChanNumUsers(chan)++;
--- 974,980 ----
  		    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)++;
***************
*** 996,1002 ****
      }
      if (remove_user_by_dbref(victim, chan)) {
        if (!Channel_Quiet(chan) && !DarkLegal(victim))
! 	channel_broadcast(chan, victim, 1,
  			  T("<%s> %s has left this channel."), ChanName(chan),
  			  Name(victim));
        notify_format(victim,
--- 996,1002 ----
      }
      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,
***************
*** 1063,1069 ****
    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, 1,
  			T("<%s> %s has joined this channel."), ChanName(chan),
  			Name(player));
      ChanNumUsers(chan)++;
--- 1063,1069 ----
    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)++;
***************
*** 1098,1104 ****
    }
    if (remove_user_by_dbref(player, chan)) {
      if (!Channel_Quiet(chan) && !DarkLegal(player))
!       channel_broadcast(chan, player, 1,
  			T("<%s> %s has left this channel."), ChanName(chan),
  			Name(player));
      notify_format(player, T("CHAT: You leave channel <%s>."), ChanName(chan));
--- 1098,1104 ----
    }
    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));
***************
*** 1331,1339 ****
      return;
    }
    if (noisy)
!     channel_broadcast(chan, player, 2, "<%s> %s", ChanName(chan), msg);
    else
!     channel_broadcast(chan, player, 2, "%s", msg);
    if (!canhear)
      notify_format(player, T("Cemit to channel %s: %s"), ChanName(chan), msg);
    ChanNumMsgs(chan)++;
--- 1331,1339 ----
      return;
    }
    if (noisy)
!     channel_broadcast(chan, player, CB_NOSPOOF, "<%s> %s", ChanName(chan), msg);
    else
!     channel_broadcast(chan, player, CB_NOSPOOF, "%s", msg);
    if (!canhear)
      notify_format(player, T("Cemit to channel %s: %s"), ChanName(chan), msg);
    ChanNumMsgs(chan)++;
***************
*** 1479,1485 ****
      remove_channel(chan);
      strcpy(ChanName(chan), perms);
      insert_channel(&chan);
!     channel_broadcast(chan, player, 1,
  		      "<%s> %s has renamed channel %s to %s.",
  		      ChanName(chan), Name(player), old, ChanName(chan));
      notify(player, T("Channel renamed."));
--- 1479,1485 ----
      remove_channel(chan);
      strcpy(ChanName(chan), perms);
      insert_channel(&chan);
!     channel_broadcast(chan, player, 0,
  		      "<%s> %s has renamed channel %s to %s.",
  		      ChanName(chan), Name(player), old, ChanName(chan));
      notify(player, T("Channel renamed."));
***************
*** 2453,2459 ****
      if (u) {
        if (!Channel_Quiet(c) && (Channel_Admin(c) || Channel_Wizard(c)
  				|| (!Chanuser_Hide(u) && !Dark(player))))
! 	 channel_broadcast(c, player, 1, "<%s> %s", ChanName(c), msg);
        CUtype(u) &= ~CU_GAG;
      }
    }
--- 2453,2460 ----
      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;
      }
    }
***************
*** 2725,2731 ****
  /** Broadcast a message to a channel.
   * \param channel pointer to channel to broadcast to.
   * \param player message speaker.
!  * \param flags broadcast flag mask (0x1 = checkquiet, 0x2 = nospoof)
   * \param fmt message format string.
   */
  void WIN32_CDECL
--- 2726,2732 ----
  /** Broadcast a message to a channel.
   * \param channel pointer to channel to broadcast to.
   * \param player message speaker.
!  * \param flags broadcast flag mask (see CB_* constants in extchat.h)
   * \param fmt message format string.
   */
  void WIN32_CDECL
***************
*** 2755,2763 ****
    tbuf1[BUFFER_LEN - 1] = '\0';
  
    nac.u = ChanUsers(channel);
!   nac.checkquiet = (flags & CU_QUIET) ? 1 : 0;
    notify_anything(player, na_channel, &nac,
! 		  (flags & CU_HIDE) ? ns_esnotify : NULL, 0, tbuf1);
    channel_push_buffer(channel, tbuf1);
  }
  
--- 2756,2766 ----
    tbuf1[BUFFER_LEN - 1] = '\0';
  
    nac.u = ChanUsers(channel);
!   nac.checkquiet = (flags & CB_CHECKQUIET) ? 1 : 0;
    notify_anything(player, na_channel, &nac,
! 		  (flags & CB_NOSPOOF) ? ns_esnotify : NULL,
! 		  (flags & CB_PRESENCE) ? NA_INTER_PRESENCE : NA_INTER_HEAR,
! 		  tbuf1);
    channel_push_buffer(channel, tbuf1);
  }
  
*** 1_7_7.561/src/db.c Mon, 18 Aug 2003 20:59:29 -0500 dunemush (pennmush/c/25_db.c 1.26.1.1.1.1.1.6.1.1.1.4 660)
--- 1_7_7.623(w)/src/db.c Wed, 10 Sep 2003 14:47:26 -0500 dunemush (pennmush/c/25_db.c 1.26.1.1.1.1.1.6.1.1.1.6 660)
***************
*** 35,40 ****
--- 35,43 ----
  #include "strtree.h"
  #include "parse.h"
  #include "htab.h"
+ #ifdef USE_MAILER
+ #include "extmail.h"
+ #endif
  #include "confmagic.h"
  
  #ifdef WIN32
***************
*** 92,97 ****
--- 95,102 ----
  
  void init_names(void);
  
+ void create_minimal_db(void);
+ 
  extern struct db_stat_info current_state;
  
  /** Initialize the name strtree.
***************
*** 1286,1288 ****
--- 1291,1346 ----
      set_objdata(thing, p, NULL);
    }
  }
+ 
+ /** Create a basic 3-object (Start Room, God, Master Room) database. */
+ void
+ create_minimal_db(void)
+ {
+   dbref start_room, god, master_room;
+ 
+   int desc_flags = AF_VISUAL | AF_NOPROG | AF_PREFIXMATCH;
+ 
+   start_room = new_object();	/* #0 */
+   god = new_object();		/* #1 */
+   master_room = new_object();	/* #2 */
+ 
+   set_name(start_room, "Room Zero");
+   Type(start_room) = TYPE_ROOM;
+   Flags(start_room) = string_to_bits("FLAG", "LINK_OK");
+   atr_new_add(start_room, "DESCRIBE", "You are in Room Zero.", GOD, desc_flags,
+ 	      1);
+   CreTime(start_room) = ModTime(start_room) = mudtime;
+   current_state.rooms++;
+ 
+   set_name(god, "One");
+   Type(god) = TYPE_PLAYER;
+   Flags(god) = string_to_bits("FLAG", "WIZARD");
+   Location(god) = start_room;
+   Home(god) = start_room;
+   Owner(god) = god;
+   CreTime(god) = mudtime;
+   ModTime(god) = (time_t) 0;
+   add_lock(god, god, Basic_Lock, parse_boolexp(god, "=me", Basic_Lock), -1);
+   add_lock(god, god, Enter_Lock, parse_boolexp(god, "=me", Enter_Lock), -1);
+   add_lock(god, god, Use_Lock, parse_boolexp(god, "=me", Use_Lock), -1);
+   atr_new_add(god, "DESCRIBE", "You see Number One.", god, desc_flags, 1);
+ #ifdef USE_MAILER
+   atr_new_add(god, "MAILCURF", "0", god, AF_LOCKED | AF_NOPROG | AF_WIZARD, 1);
+   add_folder_name(god, 0, "inbox");
+ #endif
+   PUSH(god, Contents(start_room));
+   add_player(god, NULL);
+   s_Pennies(god, START_BONUS);
+   local_data_create(god);
+   current_state.players++;
+ 
+   set_name(master_room, "Master Room");
+   Type(master_room) = TYPE_ROOM;
+   Flags(master_room) = string_to_bits("FLAG", "FLOATING");
+   Owner(master_room) = god;
+   CreTime(master_room) = ModTime(master_room) = mudtime;
+   atr_new_add(master_room, "DESCRIBE",
+ 	      "This is the master room. Any exit in here is considered global. The same is true for objects with $-commands placed here.",
+ 	      god, desc_flags, 1);
+   current_state.rooms++;
+ }
*** 1_7_7.561/src/conf.c Sun, 17 Aug 2003 08:30:54 -0500 dunemush (pennmush/c/31_conf.c 1.41.2.3.1.3.1.2.1.15.1.1.1.1.1.1.1.6 660)
--- 1_7_7.623(w)/src/conf.c Wed, 10 Sep 2003 14:47:25 -0500 dunemush (pennmush/c/31_conf.c 1.41.2.3.1.3.1.2.1.15.1.1.1.1.1.1.1.7 660)
***************
*** 906,912 ****
        return 0;
      }
    } else if (restrictions) {
!     return 1;
    }
    /* search conf table for the option; if found, add it, if not found,
     * complain about it. Forbid use of @config to set options without
--- 906,912 ----
        return 0;
      }
    } else if (restrictions) {
!     return 0;
    }
    /* search conf table for the option; if found, add it, if not found,
     * complain about it. Forbid use of @config to set options without
*** 1_7_7.561/src/comp_h.c Mon, 28 Apr 2003 00:35:06 -0500 dunemush (pennmush/c/34_comp_h.c 1.17 660)
--- 1_7_7.623(w)/src/comp_h.c Wed, 10 Sep 2003 14:47:25 -0500 dunemush (pennmush/c/34_comp_h.c 1.19 660)
***************
*** 355,366 ****
  #endif
  
    /* Part 2: count frequencies */
!   total = 0;
!   while (!feof(f) && (!SAMPLE_SIZE || (total++ < SAMPLE_SIZE))) {
!     c = fgetc(f);
!     table[c].freq++;
    }
- 
  #ifdef STANDALONE
    for (indx = 0; indx < TABLE_SIZE; indx++) {
      printf(isprint(indx) ? "Frequency for '%c': %d\n"
--- 355,367 ----
  #endif
  
    /* Part 2: count frequencies */
!   if (f) {
!     total = 0;
!     while (!feof(f) && (!SAMPLE_SIZE || (total++ < SAMPLE_SIZE))) {
!       c = fgetc(f);
!       table[c].freq++;
!     }
    }
  #ifdef STANDALONE
    for (indx = 0; indx < TABLE_SIZE; indx++) {
      printf(isprint(indx) ? "Frequency for '%c': %d\n"
***************
*** 386,392 ****
    /* The DEL character is returned once for no apparent reason (I think
     * it is returned at EOF), so remove that one count...
     */
!   table[255].freq--;
  
    /* Newlines really aren't all that common in the attributes, so
     * chop the value substantially.
--- 387,394 ----
    /* The DEL character is returned once for no apparent reason (I think
     * it is returned at EOF), so remove that one count...
     */
!   if (table[255].freq)
!     table[255].freq--;
  
    /* Newlines really aren't all that common in the attributes, so
     * chop the value substantially.
*** 1_7_7.561/src/command.c Mon, 18 Aug 2003 20:59:29 -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.11 660)
--- 1_7_7.623(w)/src/command.c Wed, 10 Sep 2003 14:47:25 -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)
***************
*** 48,60 ****
  static int command_check(dbref player, COMMAND_INFO *cmd);
  static int switch_find(COMMAND_INFO *cmd, char *sw);
  static void strccat(char *buff, char **bp, const char *from);
  extern int global_fun_invocations;	/**< Counter for function invocations */
  extern int global_fun_recursions;	/**< Counter for function recursion */
  
! void run_hook(dbref player, dbref cause, struct hook_data *hook,
! 	      char *saveregs[], int save);
! void do_hook(dbref player, char *command, char *obj, char *attrname,
! 	     int hook_type);
  
  /** The list of standard commands. Additional commands can be added
   * at runtime with add_command().
--- 48,60 ----
  static int command_check(dbref player, COMMAND_INFO *cmd);
  static int switch_find(COMMAND_INFO *cmd, char *sw);
  static void strccat(char *buff, char **bp, const char *from);
+ static int has_hook(struct hook_data *hook);
  extern int global_fun_invocations;	/**< Counter for function invocations */
  extern int global_fun_recursions;	/**< Counter for function recursion */
  
! int run_hook(dbref player, dbref cause, struct hook_data *hook,
! 	     char *saveregs[], int save);
! extern char ccom[];
  
  /** The list of standard commands. Additional commands can be added
   * at runtime with add_command().
***************
*** 150,156 ****
     CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE | CMD_T_NOGAGGED, 0, 0},
    {"@HALT", "ALL", cmd_halt, CMD_T_ANY | CMD_T_EQSPLIT, 0, 0},
    {"@HIDE", "NO OFF YES ON", cmd_hide, CMD_T_ANY, 0, 0},
!   {"@HOOK", "AFTER BEFORE", cmd_hook, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS,
     "WIZARD", 0},
    {"@KICK", NULL, cmd_kick, CMD_T_ANY, "WIZARD", 0},
  
--- 150,157 ----
     CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE | CMD_T_NOGAGGED, 0, 0},
    {"@HALT", "ALL", cmd_halt, CMD_T_ANY | CMD_T_EQSPLIT, 0, 0},
    {"@HIDE", "NO OFF YES ON", cmd_hide, CMD_T_ANY, 0, 0},
!   {"@HOOK", "AFTER BEFORE IGNORE OVERRIDE", cmd_hook,
!    CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS,
     "WIZARD", 0},
    {"@KICK", NULL, cmd_kick, CMD_T_ANY, "WIZARD", 0},
  
***************
*** 429,434 ****
--- 430,439 ----
    cmd->hooks.before.attrname = NULL;
    cmd->hooks.after.obj = NOTHING;
    cmd->hooks.after.attrname = NULL;
+   cmd->hooks.ignore.obj = NOTHING;
+   cmd->hooks.ignore.attrname = NULL;
+   cmd->hooks.override.obj = NOTHING;
+   cmd->hooks.override.attrname = NULL;
    return cmd;
  }
  
***************
*** 813,823 ****
    char *ap, *swp;
    const char *attrib, *replacer;
    COMMAND_INFO *cmd;
!   char *p, *t, *c;
    char b;
    int switchnum;
    switch_mask sw;
    int noeval;
  
    rhs_present = 0;
  
--- 818,831 ----
    char *ap, *swp;
    const char *attrib, *replacer;
    COMMAND_INFO *cmd;
!   char *p, *t, *c, *c2;
!   char command2[BUFFER_LEN];
    char b;
    int switchnum;
    switch_mask sw;
    int noeval;
+   int noevtoken = 0;
+   char *retval;
  
    rhs_present = 0;
  
***************
*** 836,841 ****
--- 844,855 ----
    /* All those one character commands.. Sigh */
  
    global_fun_invocations = global_fun_recursions = 0;
+   if (*p == NOEVAL_TOKEN) {
+     noevtoken = 1;
+     p = string + 1;
+     string = p;
+     memmove(ccom, (char *) ccom + 1, BUFFER_LEN - 1);
+   }
    switch (*p) {
    case '#':
      if (!Gagged(player) && Mobile(player))
***************
*** 895,901 ****
      while (*p == ' ')
        p++;
      process_expression(command, &c, (const char **) &p, player, cause, cause,
! 		       (PE_DEFAULT & ~PE_FUNCTION_CHECK) | PE_COMMAND_BRACES,
  		       PT_SPACE, NULL);
      *c = '\0';
      strcpy(commandraw, command);
--- 909,916 ----
      while (*p == ' ')
        p++;
      process_expression(command, &c, (const char **) &p, player, cause, cause,
! 		       noevtoken ? PE_NOTHING :
! 		       ((PE_DEFAULT & ~PE_FUNCTION_CHECK) | PE_COMMAND_BRACES),
  		       PT_SPACE, NULL);
      *c = '\0';
      strcpy(commandraw, command);
***************
*** 925,968 ****
      cmd = command_find(replacer);
      p++;
    }
    /* Test if this either isn't a command, or is a disabled one
     * If so, return Fully Parsed string for further processing.
     */
  
    if (!cmd || (cmd->type & CMD_T_DISABLED)) {
-     if (!cmd) {
-       c = commandraw + strlen(commandraw);
-     } else {
-       if (replacer) {
- 	/* These commands don't allow switches, and need a space
- 	 * added after their canonical name
- 	 */
- 	c = commandraw;
- 	safe_str(cmd->name, commandraw, &c);
- 	safe_chr(' ', commandraw, &c);
-       } else if (*c == '/') {
- 	/* Oh... DAMN */
- 	c = commandraw;
- 	strcpy(switches, commandraw);
- 	safe_str(cmd->name, commandraw, &c);
- 	t = strchr(switches, '/');
- 	safe_str(t, commandraw, &c);
-       } else {
- 	c = commandraw;
- 	safe_str(cmd->name, commandraw, &c);
-       }
-     }
      if (*p) {
        if (*p == ' ') {
! 	safe_chr(' ', commandraw, &c);
  	p++;
        }
!       process_expression(commandraw, &c, (const char **) &p, player, cause,
! 			 cause,
! 			 (PE_DEFAULT & ~PE_FUNCTION_CHECK) | PE_COMMAND_BRACES,
! 			 PT_DEFAULT, NULL);
      }
!     *c = '\0';
      mush_free((Malloc_t) command, "string");
      mush_free((Malloc_t) swtch, "string");
      mush_free((Malloc_t) ls, "string");
--- 940,990 ----
      cmd = command_find(replacer);
      p++;
    }
+ 
+   /* Set up commandraw for future use. This will contain the canonicalization
+    * of the command name and may later have the parsed rest of the input
+    * appended at the position pointed to by c2.
+    */
+   c2 = c;
+   if (!cmd) {
+     c2 = commandraw + strlen(commandraw);
+   } else {
+     if (replacer) {
+       /* These commands don't allow switches, and need a space
+        * added after their canonical name
+        */
+       c2 = commandraw;
+       safe_str(cmd->name, commandraw, &c2);
+       safe_chr(' ', commandraw, &c2);
+     } else if (*c2 == '/') {
+       /* Oh... DAMN */
+       c2 = commandraw;
+       strcpy(switches, commandraw);
+       safe_str(cmd->name, commandraw, &c2);
+       t = strchr(switches, '/');
+       safe_str(t, commandraw, &c2);
+     } else {
+       c2 = commandraw;
+       safe_str(cmd->name, commandraw, &c2);
+     }
+   }
+ 
    /* Test if this either isn't a command, or is a disabled one
     * If so, return Fully Parsed string for further processing.
     */
  
    if (!cmd || (cmd->type & CMD_T_DISABLED)) {
      if (*p) {
        if (*p == ' ') {
! 	safe_chr(' ', commandraw, &c2);
  	p++;
        }
!       process_expression(commandraw, &c2, (const char **) &p, player, cause,
! 			 cause, noevtoken ? PE_NOTHING :
! 			 ((PE_DEFAULT & ~PE_FUNCTION_CHECK) |
! 			  PE_COMMAND_BRACES), PT_DEFAULT, NULL);
      }
!     *c2 = '\0';
      mush_free((Malloc_t) command, "string");
      mush_free((Malloc_t) swtch, "string");
      mush_free((Malloc_t) ls, "string");
***************
*** 1024,1029 ****
--- 1046,1052 ----
    else if (!*swp)
      swp = NULL;
  
+   strcpy(command2, p);
    if (*p == ' ')
      p++;
    ap = p;
***************
*** 1043,1049 ****
      command_argparse(player, cause, &p, rs, rsa, cmd, 1, 1);
      SW_SET(sw, SWITCH_NOEVAL);	/* Needed for ATTRIB_SET */
    } else {
!     noeval = SW_ISSET(sw, SWITCH_NOEVAL);
      if (cmd->type & CMD_T_EQSPLIT) {
        char *savep = p;
        command_argparse(player, cause, &p, ls, lsa, cmd, 0, noeval);
--- 1066,1072 ----
      command_argparse(player, cause, &p, rs, rsa, cmd, 1, 1);
      SW_SET(sw, SWITCH_NOEVAL);	/* Needed for ATTRIB_SET */
    } else {
!     noeval = SW_ISSET(sw, SWITCH_NOEVAL) || noevtoken;
      if (cmd->type & CMD_T_EQSPLIT) {
        char *savep = p;
        command_argparse(player, cause, &p, ls, lsa, cmd, 0, noeval);
***************
*** 1058,1074 ****
      }
    }
  
    if (cmd->func == NULL) {
      do_rawlog(LT_ERR, T("No command vector on command %s."), cmd->name);
    } else {
      char *saveregs[NUMQ] = { NULL };
!     run_hook(player, cause, &cmd->hooks.before, saveregs, 1);
!     cmd->func(cmd, player, cause, sw, string, swp, ap, ls, lsa, rs, rsa);
!     run_hook(player, cause, &cmd->hooks.after, saveregs, 0);
!     if (cmd->type & CMD_T_LOGARGS)
!       do_log(LT_CMD, player, cause, "%s", string);
!     else if (cmd->type & CMD_T_LOGNAME)
!       do_log(LT_CMD, player, cause, "%s", commandraw);
    }
  
    mush_free((Malloc_t) command, "string");
--- 1081,1128 ----
      }
    }
  
+ 
+   /* Finish setting up commandraw, if we may need it for hooks */
+   if (has_hook(&cmd->hooks.ignore) || has_hook(&cmd->hooks.override)) {
+     p = command2;
+     if (*p) {
+       if (*p == ' ') {
+ 	safe_chr(' ', commandraw, &c2);
+ 	p++;
+       }
+       process_expression(commandraw, &c2, (const char **) &p, player, cause,
+ 			 cause, noevtoken ? PE_NOTHING :
+ 			 ((PE_DEFAULT & ~PE_FUNCTION_CHECK) |
+ 			  PE_COMMAND_BRACES), PT_DEFAULT, NULL);
+     }
+     *c2 = '\0';
+   }
+ 
+   retval = NULL;
    if (cmd->func == NULL) {
      do_rawlog(LT_ERR, T("No command vector on command %s."), cmd->name);
+     return NULL;
    } else {
      char *saveregs[NUMQ] = { NULL };
!     /* If we have a hook/ignore that returns false, we don't do the command */
!     if (run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) {
!       /* If we have a hook/override, we use that instead */
!       if (!has_hook(&cmd->hooks.override) ||
! 	  !one_comm_match(cmd->hooks.override.obj, player,
! 			  cmd->hooks.override.attrname, commandraw)) {
! 	/* Otherwise, we do hook/before, the command, and hook/after */
! 	run_hook(player, cause, &cmd->hooks.before, saveregs, 1);
! 	cmd->func(cmd, player, cause, sw, string, swp, ap, ls, lsa, rs, rsa);
! 	run_hook(player, cause, &cmd->hooks.after, saveregs, 0);
!       }
!       /* Either way, we might log */
!       if (cmd->type & CMD_T_LOGARGS)
! 	do_log(LT_CMD, player, cause, "%s", string);
!       else if (cmd->type & CMD_T_LOGNAME)
! 	do_log(LT_CMD, player, cause, "%s", commandraw);
!     } else {
!       retval = commandraw;
!     }
    }
  
    mush_free((Malloc_t) command, "string");
***************
*** 1076,1082 ****
    mush_free((Malloc_t) ls, "string");
    mush_free((Malloc_t) rs, "string");
    mush_free((Malloc_t) switches, "string");
!   return NULL;
  }
  
  /** Add a restriction to a command.
--- 1130,1136 ----
    mush_free((Malloc_t) ls, "string");
    mush_free((Malloc_t) rs, "string");
    mush_free((Malloc_t) switches, "string");
!   return retval;
  }
  
  /** Add a restriction to a command.
***************
*** 1292,1297 ****
--- 1346,1358 ----
        if (GoodObject(command->hooks.after.obj))
  	notify_format(player, "@hook/after: #%d/%s", command->hooks.after.obj,
  		      command->hooks.after.attrname);
+       if (GoodObject(command->hooks.ignore.obj))
+ 	notify_format(player, "@hook/ignore: #%d/%s", command->hooks.ignore.obj,
+ 		      command->hooks.ignore.attrname);
+       if (GoodObject(command->hooks.override.obj))
+ 	notify_format(player, "@hook/override: #%d/%s",
+ 		      command->hooks.override.obj,
+ 		      command->hooks.override.attrname);
      }
    }
  }
***************
*** 1417,1431 ****
    return command_check(player, cmd);
  }
  
! /** Run a before or after command hook.
   * This function runs a hook before or after a command execution.
   * \param player the enactor.
   * \param cause dbref that caused command to execute.
   * \param hook pointer to the hook.
   * \param saveregs array to store a copy of the final q-registers.
   * \param save if true, use saveregs to store a ending q-registers.
   */
! void
  run_hook(dbref player, dbref cause, struct hook_data *hook, char *saveregs[],
  	 int save)
  {
--- 1478,1504 ----
    return command_check(player, cmd);
  }
  
! static int
! has_hook(struct hook_data *hook)
! {
!   if (!hook || !GoodObject(hook->obj) || IsGarbage(hook->obj)
!       || !hook->attrname)
!     return 0;
!   return 1;
! }
! 
! 
! /** Run a command hook.
   * This function runs a hook before or after a command execution.
   * \param player the enactor.
   * \param cause dbref that caused command to execute.
   * \param hook pointer to the hook.
   * \param saveregs array to store a copy of the final q-registers.
   * \param save if true, use saveregs to store a ending q-registers.
+  * \retval 1 Hook doesn't exist, or evaluates to a non-false value
+  * \retval 0 Hook exists and evaluates to a false value
   */
! int
  run_hook(dbref player, dbref cause, struct hook_data *hook, char *saveregs[],
  	 int save)
  {
***************
*** 1435,1452 ****
    char buff[BUFFER_LEN], *bp;
    char *origregs[NUMQ];
  
!   if (!hook || !GoodObject(hook->obj) || IsGarbage(hook->obj)
!       || !hook->attrname)
!     return;
  
    atr = atr_get(hook->obj, hook->attrname);
  
    if (!atr)
!     return;
  
    code = safe_atr_value(atr);
    if (!code)
!     return;
  #ifdef MEM_CHECK
    add_check("hook.code");
  #endif
--- 1508,1524 ----
    char buff[BUFFER_LEN], *bp;
    char *origregs[NUMQ];
  
!   if (!has_hook(hook))
!     return 1;
  
    atr = atr_get(hook->obj, hook->attrname);
  
    if (!atr)
!     return 1;
  
    code = safe_atr_value(atr);
    if (!code)
!     return 1;
  #ifdef MEM_CHECK
    add_check("hook.code");
  #endif
***************
*** 1459,1470 ****
--- 1531,1544 ----
  
    process_expression(buff, &bp, &cp, hook->obj, cause, player, PE_DEFAULT,
  		     PT_DEFAULT, NULL);
+   *bp = '\0';
  
    if (save)
      save_global_regs("hook.regs", saveregs);
    restore_global_regs("run_hook", origregs);
  
    mush_free(code, "hook.code");
+   return parse_boolean(buff);
  }
  
  /** Set up or remove a command hook.
***************
*** 1476,1487 ****
   * \param command command to hook.
   * \param obj name of object containing the hook attribute.
   * \param attrname of hook attribute on obj.
!  * \param hook_type 1 (before) or 2 (after).
   */
  void
! do_hook(dbref player, char *command, char *obj, char *attrname, int hook_type)
  {
    COMMAND_INFO *cmd;
  
    cmd = command_find(command);
    if (!cmd) {
--- 1550,1563 ----
   * \param command command to hook.
   * \param obj name of object containing the hook attribute.
   * \param attrname of hook attribute on obj.
!  * \param flag type of hook
   */
  void
! do_hook(dbref player, char *command, char *obj, char *attrname,
! 	enum hook_type flag)
  {
    COMMAND_INFO *cmd;
+   struct hook_data *h;
  
    cmd = command_find(command);
    if (!cmd) {
***************
*** 1493,1508 ****
      return;
    }
  
    if (!obj && !attrname) {
-     struct hook_data *h;
-     if (hook_type == 1)
-       h = &cmd->hooks.before;
-     else if (hook_type == 2)
-       h = &cmd->hooks.after;
-     else {
-       notify(player, T("Unknown hook type"));
-       return;
-     }
      notify_format(player, T("Hook removed from %s."), cmd->name);
      h->obj = NOTHING;
      mush_free(h->attrname, "hook.attr");
--- 1569,1588 ----
      return;
    }
  
+   if (flag == HOOK_BEFORE)
+     h = &cmd->hooks.before;
+   else if (flag == HOOK_AFTER)
+     h = &cmd->hooks.after;
+   else if (flag == HOOK_IGNORE)
+     h = &cmd->hooks.ignore;
+   else if (flag == HOOK_OVERRIDE)
+     h = &cmd->hooks.override;
+   else {
+     notify(player, T("Unknown hook type"));
+     return;
+   }
+ 
    if (!obj && !attrname) {
      notify_format(player, T("Hook removed from %s."), cmd->name);
      h->obj = NOTHING;
      mush_free(h->attrname, "hook.attr");
***************
*** 1511,1525 ****
      notify(player, T("You must give both an object and attribute."));
    } else {
      dbref objdb = match_thing(player, obj);
!     struct hook_data *h;
!     if (!GoodObject(objdb))
!       return;
!     if (hook_type == 1)
!       h = &cmd->hooks.before;
!     else if (hook_type == 2)
!       h = &cmd->hooks.after;
!     else {
!       notify(player, T("Unknown hook type"));
        return;
      }
      h->obj = objdb;
--- 1591,1598 ----
      notify(player, T("You must give both an object and attribute."));
    } else {
      dbref objdb = match_thing(player, obj);
!     if (!GoodObject(objdb)) {
!       notify(player, T("Invalid hook object."));
        return;
      }
      h->obj = objdb;
*** 1_7_7.561/src/cmds.c Mon, 18 Aug 2003 20:59:29 -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 660)
--- 1_7_7.623(w)/src/cmds.c Wed, 10 Sep 2003 14:47:25 -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)
***************
*** 52,59 ****
  
  /** Is there a right-hand side of the equal sign? From command.c */
  extern int rhs_present;
- void do_hook(dbref player, char *command, char *obj, char *attrname,
- 	     int hook_type);
  
  COMMAND (cmd_allhalt) {
    do_allhalt(player);
--- 52,57 ----
***************
*** 359,365 ****
  }
  
  COMMAND (cmd_hook) {
!   int hook_type = 0;
  
    if (!Wizard(player)) {
      notify(player, T("You need a fishing license to use that hook."));
--- 357,363 ----
  }
  
  COMMAND (cmd_hook) {
!   enum hook_type flags;
  
    if (!Wizard(player)) {
      notify(player, T("You need a fishing license to use that hook."));
***************
*** 367,380 ****
    }
  
    if (SW_ISSET(sw, SWITCH_AFTER))
!     hook_type = 2;
    else if (SW_ISSET(sw, SWITCH_BEFORE))
!     hook_type = 1;
    else {
      notify(player, T("You must give a switch for @hook"));
      return;
    }
!   do_hook(player, arg_left, args_right[1], args_right[2], hook_type);
  }
  
  COMMAND (cmd_kick) {
--- 365,382 ----
    }
  
    if (SW_ISSET(sw, SWITCH_AFTER))
!     flags = HOOK_AFTER;
    else if (SW_ISSET(sw, SWITCH_BEFORE))
!     flags = HOOK_BEFORE;
!   else if (SW_ISSET(sw, SWITCH_IGNORE))
!     flags = HOOK_IGNORE;
!   else if (SW_ISSET(sw, SWITCH_OVERRIDE))
!     flags = HOOK_OVERRIDE;
    else {
      notify(player, T("You must give a switch for @hook"));
      return;
    }
!   do_hook(player, arg_left, args_right[1], args_right[2], flags);
  }
  
  COMMAND (cmd_kick) {
*** 1_7_7.561/src/bsd.c Wed, 20 Aug 2003 00:25:24 -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.22 660)
--- 1_7_7.623(w)/src/bsd.c Wed, 10 Sep 2003 14:47:25 -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)
***************
*** 190,195 ****
--- 190,197 ----
  #define CONN_TELNET 0x2
  /** Send a telnet option to test client */
  #define CONN_TELNET_QUERY 0x4
+ /** Connection that should be close on load from reboot.db */
+ #define CONN_CLOSE_READY 0x8
  
  /** Is this descriptor connected to a telnet-compatible terminal? */
  #define TELNET_ABLE(d) ((d)->conn_flags & (CONN_TELNET | CONN_TELNET_QUERY))
***************
*** 401,406 ****
--- 403,409 ----
  static void set_userstring(unsigned char **userstring, const char *command);
  static void process_commands(void);
  static int do_command(DESC *d, char *command);
+ static void parse_puebloclient(DESC *d, char *command);
  static int dump_messages(DESC *d, dbref player, int new);
  static int check_connect(DESC *d, const char *msg);
  static void parse_connect(const char *msg, char *command, char *user,
***************
*** 1349,1355 ****
    }
    if (d->conn_flags & CONN_HTML) {
      if (fb[1].buff)
!       queue_write(d, fb[1].buff, fb[1].len);
      else
        queue_write(d, fb[0].buff, fb[0].len);
    } else
--- 1352,1358 ----
    }
    if (d->conn_flags & CONN_HTML) {
      if (fb[1].buff)
!       queue_newwrite(d, fb[1].buff, fb[1].len);
      else
        queue_write(d, fb[0].buff, fb[0].len);
    } else
***************
*** 1639,1646 ****
      d->next->prev = d->prev;
  
  #ifdef HAS_OPENSSL
!   if (sslsock && d->ssl)
      ssl_close_connection(d->ssl);
  #endif
  
  #ifdef NT_TCP
--- 1642,1651 ----
      d->next->prev = d->prev;
  
  #ifdef HAS_OPENSSL
!   if (sslsock && d->ssl) {
      ssl_close_connection(d->ssl);
+     d->ssl = NULL;
+   }
  #endif
  
  #ifdef NT_TCP
***************
*** 1700,1705 ****
--- 1705,1711 ----
    d->width = 78;
    d->height = 24;
    d->ttype = mush_strdup("unknown", "terminal description");
+   d->checksum[0] = '\0';
  #ifdef HAS_OPENSSL
    d->ssl = NULL;
    d->ssl_state = 0;
***************
*** 2492,2498 ****
    pend = d->raw_input + MAX_COMMAND_LEN - 1;
    for (q = (unsigned char *) tbuf1, qend = (unsigned char *) tbuf1 + got;
         q < qend; q++) {
!     if (*q == '\n') {
        *p = '\0';
        if (p > d->raw_input)
  	save_command(d, d->raw_input);
--- 2498,2514 ----
    pend = d->raw_input + MAX_COMMAND_LEN - 1;
    for (q = (unsigned char *) tbuf1, qend = (unsigned char *) tbuf1 + got;
         q < qend; q++) {
!     if (*q == '\r') {
!       /* A broken client (read: WinXP telnet) might send only CR, and not CRLF
!        * so it's nice of us to try to handle this.
!        */
!       *p = '\0';
!       if (p > d->raw_input)
! 	save_command(d, d->raw_input);
!       p = d->raw_input;
!       if (((q + 1) < qend) && (*(q + 1) == '\n'))
! 	q++;			/* For clients that work */
!     } else if (*q == '\n') {
        *p = '\0';
        if (p > d->raw_input)
  	save_command(d, d->raw_input);
***************
*** 2519,2526 ****
      d->raw_input = 0;
      d->raw_input_at = 0;
    }
- 
- 
  }
  
  /* ARGSUSED */
--- 2535,2540 ----
***************
*** 2706,2713 ****
--- 2720,2729 ----
      d->height = parse_integer(command + 12);
    } else if (SUPPORT_PUEBLO
  	     && !strncmp(command, PUEBLO_COMMAND, strlen(PUEBLO_COMMAND))) {
+     parse_puebloclient(d, command);
      if (!(d->conn_flags & CONN_HTML)) {
        queue_newwrite(d, (unsigned char *) PUEBLO_SEND, strlen(PUEBLO_SEND));
+       process_output(d);
        do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Switching to Pueblo mode."),
  	     d->descriptor, d->addr, d->ip);
        d->conn_flags |= CONN_HTML;
***************
*** 2738,2743 ****
--- 2754,2776 ----
    return 1;
  }
  
+ static void
+ parse_puebloclient(DESC *d, char *command)
+ {
+   const char *p, *end;
+   if ((p = string_match(command, "md5="))) {
+     /* Skip md5=" */
+     p += 5;
+     if ((end = strchr(p, '"'))) {
+       if ((end > p) && ((end - p) <= PUEBLO_CHECKSUM_LEN)) {
+ 	/* Got it! */
+ 	strncpy(d->checksum, p, end - p);
+ 	d->checksum[end - p] = '\0';
+       }
+     }
+   }
+ }
+ 
  static int
  dump_messages(DESC *d, dbref player, int isnew)
  {
***************
*** 4540,4562 ****
  void
  close_ssl_connections(void)
  {
!   DESC *d, *dnext;
  
    if (!sslsock)
      return;
  
    /* Close clients */
!   for (d = descriptor_list; d; d = dnext) {
!     dnext = d->next;
      if (d->ssl) {
        queue_string_eol(d, T(ssl_shutdown_message));
!       shutdownsock(d);
      }
    }
-   /* Make sure everyone sees their disconnect messages, too */
-   DESC_ITER_CONN(d) {
-     process_output(d);
-   }
    /* Close server socket */
    ssl_close_connection(ssl_master_socket);
    shutdown(sslsock, 2);
--- 4573,4593 ----
  void
  close_ssl_connections(void)
  {
!   DESC *d;
  
    if (!sslsock)
      return;
  
    /* Close clients */
!   DESC_ITER_CONN(d) {
      if (d->ssl) {
        queue_string_eol(d, T(ssl_shutdown_message));
!       process_output(d);
!       ssl_close_connection(d->ssl);
!       d->ssl = NULL;
!       d->conn_flags |= CONN_CLOSE_READY;
      }
    }
    /* Close server socket */
    ssl_close_connection(ssl_master_socket);
    shutdown(sslsock, 2);
***************
*** 4576,4582 ****
  {
    FILE *f;
    DESC *d;
!   long flags = RDBF_SCREENSIZE | RDBF_TTYPE;
    if (setjmp(db_err)) {
      flag_broadcast(0, 0, T("GAME: Error writing reboot database!"));
      exit(0);
--- 4607,4613 ----
  {
    FILE *f;
    DESC *d;
!   long flags = RDBF_SCREENSIZE | RDBF_TTYPE | RDBF_PUEBLO_CHECKSUM;
    if (setjmp(db_err)) {
      flag_broadcast(0, 0, T("GAME: Error writing reboot database!"));
      exit(0);
***************
*** 4624,4629 ****
--- 4655,4661 ----
        putref(f, d->width);
        putref(f, d->height);
        putstring(f, d->ttype);
+       putstring(f, d->checksum);
      }				/* for loop */
  
      putref(f, 0);
***************
*** 4641,4646 ****
--- 4673,4679 ----
  {
    FILE *f;
    DESC *d = NULL;
+   DESC *closed = NULL, *nextclosed;
    int val;
    const char *temp;
    char c;
***************
*** 4698,4703 ****
--- 4731,4740 ----
        d->ttype = mush_strdup(getstring_noalloc(f), "terminal description");
      else
        d->ttype = mush_strdup("unknown", "terminal description");
+     if (flags & RDBF_PUEBLO_CHECKSUM)
+       strcpy(d->checksum, getstring_noalloc(f));
+     else
+       d->checksum[0] = '\0';
      d->input_chars = 0;
      d->output_chars = 0;
      d->output_size = 0;
***************
*** 4715,4734 ****
      d->ssl = NULL;
      d->ssl_state = 0;
  #endif
!     if (descriptor_list)
!       descriptor_list->prev = d;
!     d->next = descriptor_list;
!     d->prev = NULL;
!     descriptor_list = d;
!     if (d->connected && d->player && GoodObject(d->player) &&
! 	IsPlayer(d->player))
!       set_flag_internal(d->player, "CONNECTED");
!     else if ((!d->player || !GoodObject(d->player)) && d->connected) {
!       d->connected = 0;
!       d->player = 0;
      }
    }				/* while loop */
  
    strcpy(poll_msg, getstring_noalloc(f));
    first_start_time = getref(f);
    reboot_count = getref(f) + 1;
--- 4752,4792 ----
      d->ssl = NULL;
      d->ssl_state = 0;
  #endif
!     if (d->conn_flags & CONN_CLOSE_READY) {
!       /* This isn't really an open descriptor, we're just tracking
!        * it so we can announce the disconnect properly. Do so, but
!        * don't link it into the descriptor list. Instead, keep a
!        * separate list.
!        */
!       if (closed)
! 	closed->prev = d;
!       d->next = closed;
!       d->prev = NULL;
!       closed = d;
!     } else {
!       if (descriptor_list)
! 	descriptor_list->prev = d;
!       d->next = descriptor_list;
!       d->prev = NULL;
!       descriptor_list = d;
!       if (d->connected && d->player && GoodObject(d->player) &&
! 	  IsPlayer(d->player))
! 	set_flag_internal(d->player, "CONNECTED");
!       else if ((!d->player || !GoodObject(d->player)) && d->connected) {
! 	d->connected = 0;
! 	d->player = 0;
!       }
      }
    }				/* while loop */
  
+   /* Now announce disconnects of everyone who's not really here */
+   while (closed) {
+     nextclosed = closed->next;
+     announce_disconnect(closed->player);
+     mush_free(closed, "descriptor");
+     closed = nextclosed;
+   }
+ 
    strcpy(poll_msg, getstring_noalloc(f));
    first_start_time = getref(f);
    reboot_count = getref(f) + 1;
*** 1_7_7.561/src/attrib.c Tue, 19 Aug 2003 17:32:23 -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.24 660)
--- 1_7_7.623(w)/src/attrib.c Wed, 10 Sep 2003 14:47:25 -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)
***************
*** 697,706 ****
  
    /* check for lots of easy ways out */
    if ((type != '$' && type != '^') || !GoodObject(thing) || Halted(thing)
!       || (type == '$'
! 	  && (NoCommand(thing) || !eval_lock(player, thing, Command_Lock)))
!       || (type == '^' && !eval_lock(player, thing, Listen_Lock))
!       || !eval_lock(player, thing, Use_Lock))
      return 0;
  
    if (type == '$') {
--- 697,703 ----
  
    /* check for lots of easy ways out */
    if ((type != '$' && type != '^') || !GoodObject(thing) || Halted(thing)
!       || (type == '$' && NoCommand(thing)))
      return 0;
  
    if (type == '$') {
***************
*** 758,763 ****
--- 755,766 ----
        }
      }
      if (match_found) {
+       if ((type == '$' && !eval_lock(player, thing, Command_Lock))
+ 	  || (type == '^' && !eval_lock(player, thing, Listen_Lock))
+ 	  || !eval_lock(player, thing, Use_Lock)) {
+ 	match--;
+ 	continue;
+       }
        if (atrname && abp) {
  	safe_chr(' ', atrname, abp);
  	safe_dbref(thing, atrname, abp);
***************
*** 817,822 ****
--- 820,831 ----
  	}
        }
        if (match_found) {
+ 	if ((type == '$' && !eval_lock(player, thing, Command_Lock))
+ 	    || (type == '^' && !eval_lock(player, thing, Listen_Lock))
+ 	    || !eval_lock(player, thing, Use_Lock)) {
+ 	  match--;
+ 	  continue;
+ 	}
  	if (atrname && abp) {
  	  safe_chr(' ', atrname, abp);
  	  safe_dbref(thing, atrname, abp);
***************
*** 832,837 ****
--- 841,907 ----
    return match;
  }
  
+ /** Match input against a specified object's specified $command 
+  * attribute. Matches may be glob or regex matches. Used in command hooks.
+  * depending on the attribute's flags. 
+  * \param thing object containing attributes to check.
+  * \param player the enactor, for privilege checks.
+  * \param atr the name of the attribute
+  * \param str the string to match
+  * \retval 1 attribute matched.
+  * \retval 0 attribute failed to match.
+  */
+ int
+ one_comm_match(dbref thing, dbref player, const char *atr, const char *str)
+ {
+   ATTR *ptr;
+   char tbuf1[BUFFER_LEN];
+   char tbuf2[BUFFER_LEN];
+   char *s;
+ 
+   /* check for lots of easy ways out */
+   if (!GoodObject(thing) || Halted(thing) || NoCommand(thing))
+     return 0;
+ 
+   if (!(ptr = atr_get(thing, atr)))
+     return 0;
+ 
+   if ((AL_FLAGS(ptr) & AF_NOPROG) || !(AL_FLAGS(ptr) & AF_COMMAND))
+     return 0;
+ 
+   strcpy(tbuf1, atr_value(ptr));
+   s = tbuf1;
+   do {
+     s = strchr(s + 1, ':');
+   } while (s && s[-1] == '\\');
+   if (!s)
+     return 0;
+   *s++ = '\0';
+ 
+   if (AL_FLAGS(ptr) & AF_REGEXP) {
+     /* Turn \: into : */
+     char *from, *to;
+     for (from = tbuf1, to = tbuf2; *from; from++, to++) {
+       if (*from == '\\' && *(from + 1) == ':')
+ 	from++;
+       *to = *from;
+     }
+     *to = '\0';
+   } else
+     strcpy(tbuf2, tbuf1);
+ 
+   if ((AL_FLAGS(ptr) & AF_REGEXP) ?
+       regexp_match_case(tbuf2 + 1, str, AL_FLAGS(ptr) & AF_CASE) :
+       wild_match_case(tbuf2 + 1, str, AL_FLAGS(ptr) & AF_CASE)) {
+     if (!eval_lock(player, thing, Command_Lock)
+ 	|| !eval_lock(player, thing, Use_Lock))
+       return 0;
+     parse_que(thing, s, player);
+     return 1;
+   }
+   return 0;
+ }
+ 
  /*======================================================================*/
  
  /** Set or clear an attribute on an object.
***************
*** 881,887 ****
      if (old) {
        /* Old alias - we're allowed to change to a different case */
        strcpy(tbuf1, atr_value(old));
!       if (s && (!*s || (strcasecmp(s, tbuf1) && !ok_player_name(s)))) {
  	notify(player, T("That is not a valid alias."));
  	return -1;
        }
--- 951,957 ----
      if (old) {
        /* Old alias - we're allowed to change to a different case */
        strcpy(tbuf1, atr_value(old));
!       if (s && (!*s || (strcasecmp(s, tbuf1) && !ok_player_name(s, player)))) {
  	notify(player, T("That is not a valid alias."));
  	return -1;
        }
***************
*** 889,900 ****
  	delete_player(thing, tbuf1);
      } else {
        /* No old alias */
!       if (s && *s && !ok_player_name(s)) {
  	notify(player, T("That is not a valid alias."));
  	return -1;
        }
      }
!   } else if (s && *s && !strcmp(name, "FORWARDLIST")) {
      /* You can only set this to dbrefs of things you're allowed to
       * forward to. If you get one wrong, we puke.
       */
--- 959,971 ----
  	delete_player(thing, tbuf1);
      } else {
        /* No old alias */
!       if (s && *s && !ok_player_name(s, player)) {
  	notify(player, T("That is not a valid alias."));
  	return -1;
        }
      }
!   } else if (s && *s && (!strcmp(name, "FORWARDLIST")
! 			 || !strcmp(name, "DEBUGFORWARDLIST"))) {
      /* You can only set this to dbrefs of things you're allowed to
       * forward to. If you get one wrong, we puke.
       */
***************
*** 904,915 ****
      fwdstr = trim_space_sep(tbuf1, ' ');
      while ((curr = split_token(&fwdstr, ' ')) != NULL) {
        if (!is_dbref(curr)) {
! 	notify(player, T("@forwardlist should contain only dbrefs."));
  	return -1;
        }
        fwd = parse_dbref(curr);
        if (!GoodObject(fwd) || IsGarbage(fwd)) {
! 	notify_format(player, T("Invalid dbref #%d in @forwardlist."), fwd);
  	return -1;
        }
        if (!Can_Forward(thing, fwd)) {
--- 975,986 ----
      fwdstr = trim_space_sep(tbuf1, ' ');
      while ((curr = split_token(&fwdstr, ' ')) != NULL) {
        if (!is_dbref(curr)) {
! 	notify_format(player, T("%s should contain only dbrefs."), name);
  	return -1;
        }
        fwd = parse_dbref(curr);
        if (!GoodObject(fwd) || IsGarbage(fwd)) {
! 	notify_format(player, T("Invalid dbref #%d in %s."), fwd, name);
  	return -1;
        }
        if (!Can_Forward(thing, fwd)) {
*** 1_7_7.561/hdrs/version.h Wed, 20 Aug 2003 01:05:31 -0500 dunemush (pennmush/c/47_version.h 1.32.1.2.1.7.1.9.1.1.1.17.1.23 660)
--- 1_7_7.623(w)/hdrs/version.h Wed, 10 Sep 2003 14:47:30 -0500 dunemush (pennmush/c/47_version.h 1.32.1.2.1.7.1.9.1.1.1.17.1.24 660)
***************
*** 1,3 ****
! #define VERSION "PennMUSH version 1.7.7 patchlevel 19 [08/19/2003]"
! #define SHORTVN "PennMUSH 1.7.7p19"
! #define NUMVERSION 001007007019
--- 1,3 ----
! #define VERSION "PennMUSH version 1.7.7 patchlevel 20 [09/04/2003]"
! #define SHORTVN "PennMUSH 1.7.7p20"
! #define NUM