This is patch01 to PennMUSH 1.8.3. After applying this patch, you will have version 1.8.3p1 To apply this patch, save it to a file in your top-level MUSH directory, and do the following: patch -p1 < 1.8.3-patch01 make clean 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. - Ervin/Noltar In this patch: Minor changes: * page command now processes page output through PAGEFORMAT attribute, allowing user-set page messages. [GM] * sql_host configuration option now permits alternate tcp port. Suggested by Mercutio. Patch by Javelin. * Refactoring of fun_stringsecs to help function etime_to_secs. Patch by Javelin. * %1 in @aconnect works like in @adisconnect. Patch by Javelin. Fixes: * restart script once again includes DATEMSK export for extended convtime support. Reported by KimikoMuffin. * Memory leak in 1.8.3p0 regedit fixed. * Fixes included from 1.8.2p3. * Document change in @chan/title behavior with commas. Prereq: 1.8.3p0 *** 1_8_3p0/Patchlevel Sat Jan 27 02:21:10 2007 --- 1_8_3p1/Patchlevel Sun Mar 11 20:38:09 2007 *************** *** 1,2 **** Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.8.3p0 --- 1,2 ---- Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.8.3p1 *** 1_8_3p0/CHANGES.182 Sat Jan 27 02:21:10 2007 --- 1_8_3p1/CHANGES.182 Sun Mar 11 20:38:09 2007 *************** *** 14,19 **** --- 14,42 ---- ========================================================================== + Version 1.8.2 patchlevel 3 March 11, 2007 + + Fixes: + * Unterminated buffer in sortkey() fixed. Reported by Balerion. + Patch by Javelin. + * Memory leaks in setunion() and revwords() fixed by Javelin. + * Crash bug in speak() fixed. Reported by Trinsec. Patch by Javelin. + * Crash bug in buy fixed. Reported by Amy. Patch by Javelin. + * If we should fail to clear a semaphore attribute for some + reason (e.g., it's the branch of an attribute tree), reset + the semaphore count on the attribute to 0. Patch by Javelin. + * iter() dealt badly with freeing buffers when CPU_LIMIT or + function_invocation_limit was hit. Found by Ashen-Shugar. [GM] + * @ps/all displayed the wrong queue entry count for mortals. + Reported by Cheetah. [SW] + * @hook/override of say would get an extra leading " if that was + used instead of the literal say command. Reported by Tuxedo Ian. + [SW] + * Fixed a bug where speech seemed to come from the wrong + object for nospoof information. Reported by Jules. [SW] + * The help entry for @poll failed to mention @poll/clear. + Reported by Cooee. [SW] + Version 1.8.2 patchlevel 2 January 27, 2007 Fixes: *** 1_8_3p0/CHANGES.183 Sat Jan 27 02:21:10 2007 --- 1_8_3p1/CHANGES.183 Sun Mar 11 20:38:09 2007 *************** *** 14,23 **** ========================================================================== Version 1.8.3 patchlevel 0 January 27, 2007 Major changes: ! * Rewrite of color handling. [GM] Minor changes: * Cleaned up the internals of @wipe. [SW] --- 14,41 ---- ========================================================================== + Version 1.8.3 patchlevel 1 March 11, 2007 + + Minor changes: + * page command now processes page output through PAGEFORMAT + attribute, allowing user-set page messages. [GM] + * sql_host configuration option now permits alternate tcp port. + Suggested by Mercutio. Patch by Javelin. + * Refactoring of fun_stringsecs to help function etime_to_secs. + Patch by Javelin. + * %1 in @aconnect works like in @adisconnect. Patch by Javelin. + + Fixes: + * restart script once again includes DATEMSK export for + extended convtime support. Reported by KimikoMuffin. + * Memory leak in 1.8.3p0 regedit fixed. + * Fixes included from 1.8.2p3. + * Document change in @chan/title behavior with commas. + Version 1.8.3 patchlevel 0 January 27, 2007 Major changes: ! * Rewrite of color handling. [GM] Minor changes: * Cleaned up the internals of @wipe. [SW] *** 1_8_3p0/Configure Sat Jan 27 02:21:10 2007 --- 1_8_3p1/Configure Sun Mar 11 20:38:09 2007 *************** *** 420,425 **** --- 420,427 ---- libc='' d_mysql='' libmysqlclient='' + d_postgresql='' + libpq='' glibpth='' libpth='' loclibpth='' *************** *** 4964,4969 **** --- 4966,5017 ---- fi + : see if we should include -lpq + echo " " + + d_postgresql="$undef" + + if $test "x$no_postgresql" = "x"; then + + libpq="-lpq" + + $cat > test_postgresql.c < + #include + #include + + int main(int argc, char **argv) { + const char *conninfo = "dbname = postgres"; + PGconn *conn; + conn = PQconnectdb(conninfo); + PQfinish(conn); + exit(0); + } + EOM + + if $cc $ccflags $ldflags -o test_postgresql test_postgresql.c $libs $libpq >/dev/null 2>&1 ; + then + echo 'You have postgresql...' >&4 + version=`./test_postgresql` + if $test $? -eq 0; then + d_postgresql="$define" + else + echo "...but my test program didn't run correctly." >&4 + libpq='' + fi + else + echo "You don't seem to have postgresql." >&4 + libpq='' + fi + $rm -f test_postgresql* core + + else + + echo "Skipping postgresql tests." >&4 + libpq='' + + fi + : see if rename exists set rename d_rename eval $inlibc *************** *** 7027,7032 **** --- 7075,7081 ---- d_openssl='$d_openssl' d_passnames='$d_passnames' d_portable='$d_portable' + d_postgresql='$d_postgresql' d_rand='$d_rand' d_random='$d_random' d_rename='$d_rename' *************** *** 7149,7154 **** --- 7198,7204 ---- less='$less' libc='$libc' libmysqlclient='$libmysqlclient' + libpq='$libpq' libpth='$libpth' libs='$libs' libssl='$libssl' *** 1_8_3p0/MANIFEST Sat Jan 27 02:21:10 2007 --- 1_8_3p1/MANIFEST Sun Mar 11 20:38:09 2007 *************** *** 184,189 **** --- 184,190 ---- src/log.c src/look.c src/malias.c + src/markup.c src/match.c src/memcheck.c src/move.c *** 1_8_3p0/Makefile.SH Sat Jan 27 02:21:10 2007 --- 1_8_3p1/Makefile.SH Sun Mar 11 20:38:09 2007 *************** *** 48,54 **** CC=$cc CCFLAGS=$optimize -I.. -I../hdrs $ccflags $warnings LDFLAGS=$ldflags ! CLIBS=$libs $cryptlib $libssl $libmysqlclient INSTALL=$install INSTALLDIR=$installdir CP=$cp --- 48,54 ---- CC=$cc CCFLAGS=$optimize -I.. -I../hdrs $ccflags $warnings LDFLAGS=$ldflags ! CLIBS=$libs $cryptlib $libssl $libmysqlclient $libpq INSTALL=$install INSTALLDIR=$installdir CP=$cp *** 1_8_3p0/README.SQL Sat Jan 27 02:21:10 2007 --- 1_8_3p1/README.SQL Sun Mar 11 20:38:09 2007 *************** *** 8,13 **** --- 8,14 ---- supported: * MySQL + * PostgresQL (from 1.8.3p2) This document explains how to use (or avoid) SQL with PennMUSH, and covers the following issues: *************** *** 16,22 **** II. Mush configuration overview III. SQL setup tips ! I. Compiling with MySQL The Configure script distributed with PennMUSH automatically detects the MySQL client library (libmysqlclient) and attempts to link --- 17,31 ---- II. Mush configuration overview III. SQL setup tips ! I. Compiling with/without SQL ! ! In general, Configure attempts to detect all support sql client ! libraries on the host, and will link with all of them, permitting ! you to select which platform you want at runtime. You can selectively ! prevent linking with client libraries that are present on your ! system, as well; this is described below. ! ! I.a. MySQL The Configure script distributed with PennMUSH automatically detects the MySQL client library (libmysqlclient) and attempts to link *************** *** 36,54 **** to your /etc/ld.so.conf and running ldconfig) are the easiest ways to fix this. II. Mush configuration overview mush.cnf includes these directives that configure the SQL support: sql_platform provides the name of the SQL database server software ! that will be used for connections. It current takes one of two ! values: "disabled" (no SQL) or "mysql". If not specified, it ! defaults to disabled. sql_host gives the name of the host running the SQL server. It defaults to 127.0.0.1, which makes a TCP connection to the local host. The keyword "localhost" instead makes a domain socket ! (Unix) or named pipe (Windows) connection. sql_database gives the name of the database that contains the MUSH's tables. This must be specified and there is no default. --- 45,85 ---- to your /etc/ld.so.conf and running ldconfig) are the easiest ways to fix this. + I.b. PostgresQL + + The Configure script distributed with PennMUSH automatically detects + the PostgresQL client library (libpq) and attempts to link + them into the executable, defining HAS_POSTGRESQL in config.h + + If you want to avoid linking these libraries on systems where they + are present, use the '-D no_postgresql' switch to Configure. + + If you installed PostgresQL from a binary package (e.g. rpm or apt), + you should be sure that your system also has the development + package (usually postgresql-dev, or libpq or similar) + + If you think you have posgresql libraries and header files but + Configure isn't finding them, they may be in an unusual location on + your system. Creating symbolic links from the header directory to + /usr/include/postgresql and from the libraries in /usr/lib (or adding + the postgresql library directory to your /etc/ld.so.conf and running + ldconfig) are the easiest ways to fix this. + II. Mush configuration overview mush.cnf includes these directives that configure the SQL support: sql_platform provides the name of the SQL database server software ! that will be used for connections. It current takes one of three ! values: "disabled" (no SQL), "mysql", or "postgresql". If not specified, ! it defaults to disabled. sql_host gives the name of the host running the SQL server. It defaults to 127.0.0.1, which makes a TCP connection to the local host. The keyword "localhost" instead makes a domain socket ! (Unix) or named pipe (Windows) connection under MySQL. ! You can also specify an alternate port by setting sql_host to ! hostname:port (e.g. 127.0.0.1:5444). sql_database gives the name of the database that contains the MUSH's tables. This must be specified and there is no default. *************** *** 116,118 **** --- 147,161 ---- Are you pretty sure you would like to implement this [yes/no]: yes + B. PostgresQL + + As the postgres user: + + % createuser -A -d -P mush + Enter password for new user: <=========== + CREATE USER + + % createdb -U mush mush + Password: <=========== + CREATE DATABASE + *** 1_8_3p0/config_h.SH Sat Jan 27 02:21:10 2007 --- 1_8_3p1/config_h.SH Sun Mar 11 20:38:09 2007 *************** *** 849,854 **** --- 849,859 ---- */ #$d_mysql HAS_MYSQL /**/ + /* HAS_POSTGRESQL: + * Defined if postgresql client libraries are available. + */ + #$d_postgresql HAS_POSTGRESQL /**/ + /* HAS_OPENSSL: * Defined if openssl 0.9.6+ is available. */ *** 1_8_3p0/game/mushcnf.dst Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/mushcnf.dst Sun Mar 11 20:40:17 2007 *************** *** 558,568 **** ### # What SQL server platform should we use? Options include: ! # mysql, disabled (the default) sql_platform disabled # What's the SQL hostname? Use '127.0.0.1' for a TCP connection ! # to the local host, and 'localhost' for a domain socket connection. sql_host 127.0.0.1 # What's the SQL database? You have to set this to a database that --- 558,570 ---- ### # What SQL server platform should we use? Options include: ! # mysql, postgresql, disabled (the default) sql_platform disabled # What's the SQL hostname? Use '127.0.0.1' for a TCP connection ! # to the local host on port 3306, ':' for a TCP ! # connection on another port (e.g. 127.0.0.1:3307), and ! # the word 'localhost' for a domain socket connection. sql_host 127.0.0.1 # What's the SQL database? You have to set this to a database that *** 1_8_3p0/game/restart Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/restart Sun Mar 11 20:38:09 2007 *************** *** 138,142 **** --- 138,143 ---- fi DATEMSK="${GAMEDIR}/getdate.template" + export DATEMSK LC_ALL=$LANG LANG=$LANG ./netmush $GAMEDIR/$CONF_FILE & *** 1_8_3p0/game/txt/hlp/pennchat.hlp Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/txt/hlp/pennchat.hlp Sun Mar 11 20:38:08 2007 *************** *** 99,104 **** --- 99,105 ---- @channel/title lets you set a title to appear before your name when you speak on the channel. If you leave the channel, your title is cleared; use @channel/gag instead (see help @channel3). + You should escape any commas in your title with backslashes. See "help @channel3" for more. & @channel3 *** 1_8_3p0/game/txt/hlp/penncmd.hlp Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/txt/hlp/penncmd.hlp Sun Mar 11 20:38:08 2007 *************** *** 148,153 **** --- 148,156 ---- when a player connects in that location or zone (or, in the case of the master room, anywhere). + One descriptor variable is passed to @aconnect: + %1 = number of player connections (1 if this is an initial connect) + See also: @adisconnect, ACTION LISTS & @adeath @adeath = *************** *** 2587,2593 **** --- 2590,2618 ---- @password = This changes your password. Please note that passwords ARE case-sensitive. + & @pageformat + @pageformat [=] + + Sets the message that is seen when receives a page. is + evaluated. + + %0 will be set to the page message. + %1 will be set to ':' ';' or '"' for pose, semipose and normal page, + respectively, + %2 will be set to the alias of the pager, if any. + %3 will be a space-separated list of recipient dbrefs. + + To obtain 'page_aliases' behavior: + > @pageformat me=[setq(0,%n[if(%2,%b(%2))],1,switch(%3,%!,,itemize(iter(%3, + name(##),%b,|),|)))][switch(%1,",%q0 pages[if(%q1,%b%q1)]: %0,:,From + afar[if(%q1,%b(to %q1))]\, %q0 %0,From afar[if(%q1,%b(to %q1))]\, %q0%0)] + + To obtain no 'page_aliases' behavior: + > @pageformat me=[setq(1,switch(%3,%!,,itemize(iter(%3,name(##),%b,|),|)))] + [switch(%1,",%n pages[if(%q1,%b%q1)]: %0,:,From afar + [if(%q1,%b(to %q1))]\, %n %0,From afar[if(%q1,%b(to %q1))]\, %n%0)] + See also: page, speak() & @payment @payment [=] *************** *** 2692,2701 **** See also @emit, @oemit, @remit, NOSPOOF, and SPOOFING. & @poll @poll ! This wizard-only command sets the "poll" - the Doing question. If ! "@poll" is used by itself, the question is reset to the default ! string "Doing". It can also be used by those with the poll @power. See also: @doing, WHO, DOING & @poor --- 2717,2729 ---- See also @emit, @oemit, @remit, NOSPOOF, and SPOOFING. & @poll + @poll @poll ! @poll/clear ! ! This command manipulate the message at the top of WHO/DOING. By itself, ! it displays the current poll. Wizards and those with the poll @power can ! set or clear the message. See also: @doing, WHO, DOING & @poor *************** *** 4016,4022 **** the player's name contains spaces, surround it with double-quotes. If you have already paged someone since connecting, just typing: ! page will send the message to the last person paged. You cannot page a player if they are set HAVEN or if you do not pass their @lock/page. --- 4044,4050 ---- the player's name contains spaces, surround it with double-quotes. If you have already paged someone since connecting, just typing: ! 'page ' or 'page =' will send the message to the last person paged. You cannot page a player if they are set HAVEN or if you do not pass their @lock/page. *************** *** 4042,4047 **** --- 4070,4079 ---- square brackets, in front of the message, in a fashion similar to the way NOSPOOF flags emits. + When a player is paged, their PAGEFORMAT attribute is checked, and if + exists, the page as viewed by the player is set to the results of + calling PAGEFORMAT. See help @pageformat + Page takes five switches: /list, /blind, /noeval, /override, and /port. The /list and /blind switches provide two different ways of handling pages to lists of players. With /list, each paged player sees the *************** *** 4053,4059 **** The /port switch is admin-only, and will page a port descriptor directly, including connections that have not yet logged into a player. ! See also: @lock, @alias, pose, :, ;, HAVEN, NOSPOOF, FLAGS & : & ; & pose --- 4085,4091 ---- The /port switch is admin-only, and will page a port descriptor directly, including connections that have not yet logged into a player. ! See also: @lock, @alias, @pageformat, pose, :, ;, HAVEN, NOSPOOF, FLAGS & : & ; & pose *************** *** 4203,4206 **** In addition, the following commands can only be used at the login screen: ! cd ch connect create \ No newline at end of file --- 4235,4238 ---- In addition, the following commands can only be used at the login screen: ! cd ch connect create *** 1_8_3p0/game/txt/hlp/pennv182.hlp Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/txt/hlp/pennv182.hlp Sun Mar 11 20:38:08 2007 *************** *** 1,3 **** --- 1,27 ---- + & 1.8.2p3 + Version 1.8.2 patchlevel 3 March 11, 2007 + + Fixes: + * Unterminated buffer in sortkey() fixed. Reported by Balerion. + Patch by Javelin. + * Memory leaks in setunion() and revwords() fixed by Javelin. + * Crash bug in speak() fixed. Reported by Trinsec. Patch by Javelin. + * Crash bug in buy fixed. Reported by Amy. Patch by Javelin. + * If we should fail to clear a semaphore attribute for some + reason (e.g., it's the branch of an attribute tree), reset + the semaphore count on the attribute to 0. Patch by Javelin. + * iter() dealt badly with freeing buffers when CPU_LIMIT or + function_invocation_limit was hit. Found by Ashen-Shugar. [GM] + * @ps/all displayed the wrong queue entry count for mortals. + Reported by Cheetah. [SW] + * @hook/override of say would get an extra leading " if that was + used instead of the literal say command. Reported by Tuxedo Ian. + [SW] + * Fixed a bug where speech seemed to come from the wrong + object for nospoof information. Reported by Jules. [SW] + * The help entry for @poll failed to mention @poll/clear. + Reported by Cooee. [SW] + & 1.8.2p2 Version 1.8.2 patchlevel 2 January 27, 2007 *************** *** 17,23 **** * Looking at an object used the looker, not the lookee, as the origin of the name for @ahear/@aahear/@amhear. [SW] * Fixed the distribution of random numbers with a huge range. Reported ! by Luke. & 1.8.2p1 Version 1.8.2 patchlevel 1 November 26, 2006 --- 41,48 ---- * Looking at an object used the looker, not the lookee, as the origin of the name for @ahear/@aahear/@amhear. [SW] * Fixed the distribution of random numbers with a huge range. Reported ! by Luke. ! & 1.8.2p1 Version 1.8.2 patchlevel 1 November 26, 2006 *** 1_8_3p0/game/txt/hlp/pennv183.hlp Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/txt/hlp/pennv183.hlp Sun Mar 11 20:38:08 2007 *************** *** 1,4 **** ! & 1.8.3p0 & changes This is a list of changes in this patchlevel which are probably of interest to players. More information about new commands and functions --- 1,4 ---- ! & 1.8.3p1 & changes This is a list of changes in this patchlevel which are probably of interest to players. More information about new commands and functions *************** *** 11,20 **** A list of the patchlevels associated with each release can be read in 'help patchlevels'. Version 1.8.3 patchlevel 0 January 27, 2007 Major changes: ! * Rewrite of color handling. [GM] Minor changes: * Cleaned up the internals of @wipe. [SW] --- 11,39 ---- A list of the patchlevels associated with each release can be read in 'help patchlevels'. + Version 1.8.3 patchlevel 1 March 11, 2007 + + Minor changes: + * page command now processes page output through PAGEFORMAT + attribute, allowing user-set page messages. [GM] + * sql_host configuration option now permits alternate tcp port. + Suggested by Mercutio. Patch by Javelin. + * Refactoring of fun_stringsecs to help function etime_to_secs. + Patch by Javelin. + * %1 in @aconnect works like in @adisconnect. Patch by Javelin. + + Fixes: + * restart script once again includes DATEMSK export for + extended convtime support. Reported by KimikoMuffin. + * Memory leak in 1.8.3p0 regedit fixed. + * Fixes included from 1.8.2p3. + * Document change in @chan/title behavior with commas. + + & 1.8.3p0 Version 1.8.3 patchlevel 0 January 27, 2007 Major changes: ! * Rewrite of color handling. [GM] Minor changes: * Cleaned up the internals of @wipe. [SW] *** 1_8_3p0/game/txt/hlp/pennvOLD.hlp Sat Jan 27 02:21:10 2007 --- 1_8_3p1/game/txt/hlp/pennvOLD.hlp Sun Mar 11 20:38:08 2007 *************** *** 4417,4424 **** For information on a specific patchlevel of one of the versions listed, type 'help p'. For example, 'help 1.7.2p3' ! 1.8.3: 0 ! 1.8.2: 0, 1 1.8.1: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 1.8.0: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 1.7.7: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, --- 4417,4424 ---- For information on a specific patchlevel of one of the versions listed, type 'help p'. For example, 'help 1.7.2p3' ! 1.8.3: 0, 1 ! 1.8.2: 0, 1, 2, 3 1.8.1: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 1.8.0: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 1.7.7: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, *** 1_8_3p0/hdrs/atr_tab.h Sat Jan 27 02:21:10 2007 --- 1_8_3p1/hdrs/atr_tab.h Sun Mar 11 20:38:09 2007 *************** *** 143,148 **** --- 143,149 ---- {"OZENTER", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, {"OZLEAVE", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, {"PAYMENT", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, + {"PAGEFORMAT", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, {"PRICELIST", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, {"PREFIX", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, {"RECEIVE", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, NULL}, *** 1_8_3p0/hdrs/conf.h Sat Jan 27 02:21:10 2007 --- 1_8_3p1/hdrs/conf.h Sun Mar 11 20:38:09 2007 *************** *** 265,277 **** char command_log[256]; /**< File to log suspect commands */ char trace_log[256]; /**< File to log trace data */ char checkpt_log[256]; /**< File to log checkpoint data */ - #ifdef HAS_MYSQL char sql_platform[256]; /**< Type of SQL server, or "disabled" */ char sql_host[256]; /**< Hostname of sql server */ char sql_username[256]; /**< Username for sql */ char sql_password[256]; /**< Password for sql */ char sql_database[256]; /**< Database for sql */ - #endif }; extern OPTTAB options; --- 265,275 ---- *************** *** 432,444 **** #define CMDLOG (options.command_log) #define TRACELOG (options.trace_log) #define CHECKLOG (options.checkpt_log) - #ifdef HAS_MYSQL #define SQL_PLATFORM (options.sql_platform) #define SQL_HOST (options.sql_host) #define SQL_DB (options.sql_database) #define SQL_USER (options.sql_username) #define SQL_PASS (options.sql_password) - #endif #define CHUNK_SWAP_FILE (options.chunk_swap_file) #define CHUNK_CACHE_MEMORY (options.chunk_cache_memory) --- 430,440 ---- *** 1_8_3p0/hdrs/externs.h Sat Jan 27 02:21:10 2007 --- 1_8_3p1/hdrs/externs.h Sun Mar 11 20:38:09 2007 *************** *** 257,262 **** --- 257,265 ---- extern void do_unlink(dbref player, const char *name); extern dbref do_clone(dbref player, char *name, char *newname, int preserve); + /* From funtime.c */ + extern int etime_to_secs(char *str1, int *secs); + /* From game.c */ extern void report(void); extern int Hearer(dbref thing); *************** *** 526,531 **** --- 529,537 ---- extern int call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, dbref executor, dbref enactor, PE_Info * pe_info); + extern int call_attrib(dbref thing, const char *attrname, + const char *wenv_args[], int wenv_argc, char *ret, + dbref enactor, PE_Info * pe_info); extern int member(dbref thing, dbref list); extern int recursive_member(dbref disallow, dbref from, int count); extern dbref remove_first(dbref first, dbref what); *** 1_8_3p0/hdrs/version.h Sat Jan 27 02:21:10 2007 --- 1_8_3p1/hdrs/version.h Sun Mar 11 20:38:09 2007 *************** *** 1,4 **** #define VERSION "1.8.3" ! #define PATCHLEVEL "0" ! #define PATCHDATE "[01/27/2007]" ! #define NUMVERSION 1008003000 --- 1,4 ---- #define VERSION "1.8.3" ! #define PATCHLEVEL "1" ! #define PATCHDATE "[03/11/2007]" ! #define NUMVERSION 1008003001 *** 1_8_3p0/src/attrib.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/attrib.c Sun Mar 11 20:38:07 2007 *************** *** 447,452 **** --- 447,459 ---- set_default_flags(atr, flags); num_new++; } + /* Only GOD can create an AF_NODUMP attribute (used for semaphores) + * or add a leaf to a tree with such an attribute + */ + if ((AL_FLAGS(atr) & AF_NODUMP) && (player != GOD)) { + missing_name[0] = '\0'; + return AE_ERROR; + } if (Cannot_Write_This_Attr(player, atr, 1)) { missing_name[0] = '\0'; return AE_ERROR; *** 1_8_3p0/src/bsd.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/bsd.c Sun Mar 11 20:38:07 2007 *************** *** 3346,3351 **** --- 3346,3352 ---- { dbref loc; char tbuf1[BUFFER_LEN]; + char *myenv[2]; dbref zone; dbref obj; int j; *************** *** 3415,3420 **** --- 3416,3429 ---- for (j = 0; j < NUMQ; j++) global_eval_context.rnxt[j] = NULL; strcpy(global_eval_context.ccom, ""); + /* And then load it up, as follows: + * %0 (unused, reserved for "reason for disconnect") + * %1 (number of connections after connect) + */ + myenv[0] = NULL; + myenv[1] = mush_strdup(unparse_integer(num), "myenv"); + for (j = 0; j < 2; j++) + global_eval_context.wnxt[j] = myenv[j]; /* do the person's personal connect action */ (void) queue_attribute(player, "ACONNECT", player); *************** *** 3446,3451 **** --- 3455,3466 ---- DOLIST(obj, Contents(MASTER_ROOM)) { (void) queue_attribute(obj, "ACONNECT", player); } + for (j = 0; j < 2; j++) + if (myenv[j]) + mush_free(myenv[j], "myenv"); + for (j = 0; j < 10; j++) + global_eval_context.wnxt[j] = NULL; + strcpy(global_eval_context.ccom, ""); } static void *************** *** 3786,3792 **** int first; int start, count; int powered = (*(called_as + 1) != 'M'); ! int objid = (index(called_as, 'D') != NULL); if (!is_strict_integer(args[0]) || !is_strict_integer(args[1])) { safe_str(T(e_int), buff, bp); --- 3801,3807 ---- int first; int start, count; int powered = (*(called_as + 1) != 'M'); ! int objid = (strchr(called_as, 'D') != NULL); if (!is_strict_integer(args[0]) || !is_strict_integer(args[1])) { safe_str(T(e_int), buff, bp); *************** *** 3844,3850 **** int first; dbref victim; int powered = ((*called_as == 'L') && Priv_Who(executor)); ! int objid = (index(called_as, 'D') != NULL); first = 1; --- 3859,3865 ---- int first; dbref victim; int powered = ((*called_as == 'L') && Priv_Who(executor)); ! int objid = (strchr(called_as, 'D') != NULL); first = 1; *** 1_8_3p0/src/command.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/command.c Sun Mar 11 20:38:07 2007 *************** *** 248,255 **** --- 248,259 ---- #ifdef HAS_MYSQL {"@SQL", NULL, cmd_sql, CMD_T_ANY, "WIZARD", "SQL_OK"}, #else + #ifdef HAS_POSTGRESQL + {"@SQL", NULL, cmd_sql, CMD_T_ANY, "WIZARD", "SQL_OK"}, + #else {"@SQL", NULL, cmd_unimplemented, CMD_T_ANY, "WIZARD", "SQL_OK"}, #endif + #endif {"@SITELOCK", "BAN CHECK REGISTER REMOVE NAME", cmd_sitelock, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, "WIZARD", 0}, {"@STATS", "CHUNKS FREESPACE PAGING REGIONS TABLES", cmd_stats, *************** *** 912,919 **** --- 916,926 ---- return NULL; case SAY_TOKEN: replacer = "SAY"; + #if 0 + /* Messes up hooks when chat_strip_quote is yes. See bug #6677 */ if (CHAT_STRIP_QUOTE) p--; /* Since 'say' strips out the '"' */ + #endif break; case POSE_TOKEN: replacer = "POSE"; *** 1_8_3p0/src/conf.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/conf.c Sun Mar 11 20:38:07 2007 *************** *** 192,198 **** , {"pueblo", cf_bool, &options.support_pueblo, 2, 0, "net"} , - #ifdef HAS_MYSQL {"sql_platform", cf_str, options.sql_platform, sizeof options.sql_platform, 0, "net"} , --- 192,197 ---- *************** *** 207,214 **** {"sql_database", cf_str, options.sql_database, sizeof options.sql_database, 0, NULL} , - #endif - {"forking_dump", cf_bool, &options.forking_dump, 2, 0, "dump"} , {"dump_message", cf_str, options.dump_message, sizeof options.dump_message, 0, --- 206,211 ---- *************** *** 1187,1199 **** options.ssl_require_client_cert = 0; #endif options.mem_check = 0; - #ifdef HAS_MYSQL strcpy(options.sql_platform, "disabled"); strcpy(options.sql_database, ""); strcpy(options.sql_username, ""); strcpy(options.sql_password, ""); strcpy(options.sql_host, "127.0.0.1"); - #endif } /* Limit how many files we can nest */ --- 1184,1194 ---- *************** *** 1607,1612 **** --- 1602,1610 ---- #ifdef HAS_MYSQL notify(player, T(" The MUSH was compiled with MySQL support.")); #endif + #ifdef HAS_POSTGRESQL + notify(player, T(" The MUSH was compiled with Postgresql support.")); + #endif #ifdef INFO_SLAVE notify(player, T(" DNS and ident lookups are handled by a slave process.")); *** 1_8_3p0/src/cque.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/cque.c Sun Mar 11 20:38:07 2007 *************** *** 123,132 **** if (a) num = parse_integer(atr_value(a)); num += am; ! if (num) { ! sprintf(buff, "%d", num); ! (void) atr_add(player, name, buff, GOD, flags); ! } else { (void) atr_clr(player, name, GOD); } return (num); --- 123,135 ---- if (a) num = parse_integer(atr_value(a)); num += am; ! /* We set the attribute's value to 0 even if we're going to clear ! * it later, because clearing it may fail (perhaps someone's also ! * foolishly using it as a branch in an attribute tree) ! */ ! sprintf(buff, "%d", num); ! (void) atr_add(player, name, buff, GOD, flags); ! if (!num) { (void) atr_clr(player, name, GOD); } return (num); *************** *** 903,930 **** if (!GoodObject(tmp->player)) (*del)++; else if (q_all || (Owner(tmp->player) == victim)) { ! (*self)++; ! if (!q_quiet && (LookQueue(player) ! || Owns(tmp->player, player))) { switch (q_type) { case 1: /* wait queue */ ! notify_format(player, "[%ld]%s:%s", tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); break; case 2: /* semaphore queue */ if (tmp->left != 0) { ! notify_format(player, "[#%d/%s/%ld]%s:%s", tmp->sem, tmp->semattr, tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); } else { ! notify_format(player, "[#%d/%s]%s:%s", tmp->sem, tmp->semattr, unparse_object(player, tmp->player), tmp->comm); } break; default: /* player or object queue */ ! notify_format(player, "%s:%s", unparse_object(player, ! tmp->player), tmp->comm); } } --- 906,935 ---- if (!GoodObject(tmp->player)) (*del)++; else if (q_all || (Owner(tmp->player) == victim)) { ! if ((LookQueue(player) ! || Owns(tmp->player, player))) { ! (*self)++; ! if (q_quiet) ! continue; switch (q_type) { case 1: /* wait queue */ ! notify_format(player, "[%ld]%s: %s", tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); break; case 2: /* semaphore queue */ if (tmp->left != 0) { ! notify_format(player, "[#%d/%s/%ld]%s: %s", tmp->sem, tmp->semattr, tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); } else { ! notify_format(player, "[#%d/%s]%s: %s", tmp->sem, tmp->semattr, unparse_object(player, tmp->player), tmp->comm); } break; default: /* player or object queue */ ! notify_format(player, "%s: %s", unparse_object(player, ! tmp->player), tmp->comm); } } *** 1_8_3p0/src/filecopy.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/filecopy.c Sun Mar 11 20:38:07 2007 *************** *** 206,212 **** #ifndef _DEBUG 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."); #ifdef WIN32SERVICES --- 206,212 ---- #ifndef _DEBUG char FileName[256]; if (GetModuleFileName(NULL, FileName, 256) != 0) { ! if (!strcasecmp(strrchr(FileName, '\\') + 1, "pennmush.exe")) { if (CopyFile("pennmush.exe", "pennmush_run.exe", FALSE)) { do_rawlog(LT_ERR, "Successfully copied executable, starting copy."); #ifdef WIN32SERVICES *** 1_8_3p0/src/funlist.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/funlist.c Sun Mar 11 20:38:07 2007 *************** *** 1211,1223 **** char sep; char outsep[BUFFER_LEN]; int i; - char tbuff[BUFFER_LEN]; - char *tp; - char const *cp; char result[BUFFER_LEN]; ! char *rp; ! ATTR *attrib; ! dbref thing; /* sortkey(attr,list,sort_type,delim,osep) */ --- 1211,1219 ---- char sep; char outsep[BUFFER_LEN]; int i; char result[BUFFER_LEN]; ! ufun_attrib ufun; ! char *wenv[1]; /* sortkey(attr,list,sort_type,delim,osep) */ *************** *** 1233,1264 **** } else strcpy(outsep, args[4]); ! /* Find object and attribute to get sortby function from. */ ! parse_anon_attrib(executor, args[0], &thing, &attrib); ! if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) { ! free_anon_attrib(attrib); ! return; ! } ! if (!CanEvalAttr(executor, thing, attrib)) { ! free_anon_attrib(attrib); return; - } - tp = tbuff; - safe_str(atr_value(attrib), tbuff, &tp); - *tp = '\0'; - nptrs = list2arr_ansi(ptrs, MAX_SORTSIZE, args[1], sep); /* Now we make a list of keys */ for (i = 0; i < nptrs; i++) { ! global_eval_context.wenv[0] = (char *) ptrs[i]; ! rp = result; ! cp = tbuff; ! process_expression(result, &rp, &cp, ! thing, executor, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info); ! *rp = '\0'; keys[i] = mush_strdup(result, "sortkey"); } --- 1229,1245 ---- } else strcpy(outsep, args[4]); ! /* find our object and attribute */ ! if (!fetch_ufun_attrib(args[0], executor, &ufun, 1)) return; nptrs = list2arr_ansi(ptrs, MAX_SORTSIZE, args[1], sep); /* Now we make a list of keys */ for (i = 0; i < nptrs; i++) { ! /* Build our %0 args */ ! wenv[0] = (char *) ptrs[i]; ! call_ufun(&ufun, wenv, 2, result, executor, enactor, pe_info); keys[i] = mush_strdup(result, "sortkey"); } *************** *** 1461,1467 **** { char sep; char **a1, **a2; ! int n1, n2, x1, x2, val; int lastx1, lastx2, found; char *sort_type = ALPHANUM_LIST; int osepl = 0; --- 1442,1448 ---- { char sep; char **a1, **a2; ! int n1, n2, x1, x2, val, orign1, orign2; int lastx1, lastx2, found; char *sort_type = ALPHANUM_LIST; int osepl = 0; *************** *** 1480,1487 **** mush_panic("Unable to allocate memory in fun_setunion"); /* make arrays out of the lists */ ! n1 = list2arr_ansi(a1, MAX_SORTSIZE, args[0], sep); ! n2 = list2arr_ansi(a2, MAX_SORTSIZE, args[1], sep); if (nargs < 4) { osepd[0] = sep; --- 1461,1468 ---- mush_panic("Unable to allocate memory in fun_setunion"); /* make arrays out of the lists */ ! orign1 = n1 = list2arr_ansi(a1, MAX_SORTSIZE, args[0], sep); ! orign2 = n2 = list2arr_ansi(a2, MAX_SORTSIZE, args[1], sep); if (nargs < 4) { osepd[0] = sep; *************** *** 1589,1596 **** } } } ! freearr(a1, n1); ! freearr(a2, n2); mush_free((Malloc_t) a1, "ptrarray"); mush_free((Malloc_t) a2, "ptrarray"); } --- 1570,1577 ---- } } } ! freearr(a1, orign1); ! freearr(a2, orign2); mush_free((Malloc_t) a1, "ptrarray"); mush_free((Malloc_t) a2, "ptrarray"); } *************** *** 2605,2611 **** FUNCTION(fun_revwords) { char **words; ! int count; char sep; char *osep, osepd[2] = { '\0', '\0' }; --- 2586,2592 ---- FUNCTION(fun_revwords) { char **words; ! int count, origcount; char sep; char *osep, osepd[2] = { '\0', '\0' }; *************** *** 2621,2627 **** words = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "wordlist"); ! count = list2arr_ansi(words, BUFFER_LEN, args[0], sep); if (count == 0) { mush_free((Malloc_t) words, "wordlist"); return; --- 2602,2608 ---- words = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "wordlist"); ! origcount = count = list2arr_ansi(words, BUFFER_LEN, args[0], sep); if (count == 0) { mush_free((Malloc_t) words, "wordlist"); return; *************** *** 2632,2638 **** safe_str(osep, buff, bp); safe_str(words[--count], buff, bp); } ! freearr(words, count); mush_free((Malloc_t) words, "wordlist"); } --- 2613,2619 ---- safe_str(osep, buff, bp); safe_str(words[--count], buff, bp); } ! freearr(words, origcount); mush_free((Malloc_t) words, "wordlist"); } *************** *** 2782,2791 **** tbuf2 = replace_string2(standard_tokens, replace, args[1]); sp = tbuf2; if (process_expression(buff, bp, &sp, executor, caller, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info)) break; ! if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; oldbp = *bp; mush_free((Malloc_t) tbuf2, "replace_string.buff"); --- 2763,2776 ---- tbuf2 = replace_string2(standard_tokens, replace, args[1]); sp = tbuf2; if (process_expression(buff, bp, &sp, executor, caller, enactor, ! PE_DEFAULT, PT_DEFAULT, pe_info)) { ! mush_free((Malloc_t) tbuf2, "replace_string.buff"); break; ! } ! if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount) { ! mush_free((Malloc_t) tbuf2, "replace_string.buff"); break; + } funccount = pe_info->fun_invocations; oldbp = *bp; mush_free((Malloc_t) tbuf2, "replace_string.buff"); *************** *** 3221,3231 **** *postp = '\0'; /* Ansi-less regedits */ ! for (i=1 ; i < nargs - 1; i+= 2) { /* If this string has ANSI, switch to using ansi only */ ! if (strchr(postbuf,TAG_START)) break; ! memcpy(prebuf,postbuf,BUFFER_LEN); prelen = strlen(prebuf); postp = postbuf; --- 3206,3217 ---- *postp = '\0'; /* Ansi-less regedits */ ! for (i = 1; i < nargs - 1; i += 2) { /* If this string has ANSI, switch to using ansi only */ ! if (strchr(postbuf, TAG_START)) ! break; ! memcpy(prebuf, postbuf, BUFFER_LEN); prelen = strlen(prebuf); postp = postbuf; *************** *** 3236,3246 **** tbp = tbuf; r = args[i]; process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, ! PT_DEFAULT, pe_info); *tbp = '\0'; if ((re = pcre_compile(remove_markup(tbuf, &searchlen), ! flags, &errptr, &erroffset, tables)) == NULL) { /* Matching error. */ safe_str(T("#-1 REGEXP ERROR: "), buff, bp); safe_str(errptr, buff, bp); --- 3222,3232 ---- tbp = tbuf; r = args[i]; process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, ! PT_DEFAULT, pe_info); *tbp = '\0'; if ((re = pcre_compile(remove_markup(tbuf, &searchlen), ! flags, &errptr, &erroffset, tables)) == NULL) { /* Matching error. */ safe_str(T("#-1 REGEXP ERROR: "), buff, bp); safe_str(errptr, buff, bp); *************** *** 3255,3269 **** if (all) { study = pcre_study(re, 0, &errptr); if (errptr != NULL) { ! mush_free((Malloc_t) re, "pcre"); ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; } if (study != NULL) ! /* study */ ! add_check("pcre.extra"); } search = 0; --- 3241,3255 ---- if (all) { study = pcre_study(re, 0, &errptr); if (errptr != NULL) { ! mush_free((Malloc_t) re, "pcre"); ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; } if (study != NULL) ! /* study */ ! add_check("pcre.extra"); } search = 0; *************** *** 3276,3283 **** if (subpatterns < 0) { safe_str(prebuf, postbuf, &postp); mush_free((Malloc_t) re, "pcre"); if (study) ! mush_free((Malloc_t) study, "pcre.extra"); continue; } --- 3262,3270 ---- if (subpatterns < 0) { safe_str(prebuf, postbuf, &postp); mush_free((Malloc_t) re, "pcre"); + free_ansi_string(orig); if (study) ! mush_free((Malloc_t) study, "pcre.extra"); continue; } *************** *** 3297,3306 **** global_eval_context.re_offsets = offsets; global_eval_context.re_subpatterns = subpatterns; process_expression(postbuf, &postp, &obp, executor, caller, enactor, ! PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info); if ((*bp == (buff + BUFFER_LEN - 1)) ! && (pe_info->fun_invocations == funccount)) ! break; oldbp = postp; funccount = pe_info->fun_invocations; --- 3284,3293 ---- global_eval_context.re_offsets = offsets; global_eval_context.re_subpatterns = subpatterns; process_expression(postbuf, &postp, &obp, executor, caller, enactor, ! PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info); if ((*bp == (buff + BUFFER_LEN - 1)) ! && (pe_info->fun_invocations == funccount)) ! break; oldbp = postp; funccount = pe_info->fun_invocations; *************** *** 3309,3318 **** match_offset = offsets[1]; /* Make sure we advance at least 1 char */ if (offsets[0] == match_offset) ! match_offset++; } while (all && match_offset < prelen && ! (subpatterns = pcre_exec(re, study, prebuf, prelen, ! match_offset, 0, offsets, 99)) >= 0); safe_str(start, postbuf, &postp); *postp = '\0'; --- 3296,3305 ---- match_offset = offsets[1]; /* Make sure we advance at least 1 char */ if (offsets[0] == match_offset) ! match_offset++; } while (all && match_offset < prelen && ! (subpatterns = pcre_exec(re, study, prebuf, prelen, ! match_offset, 0, offsets, 99)) >= 0); safe_str(start, postbuf, &postp); *postp = '\0'; *************** *** 3335,3413 **** tbp = tbuf; r = args[i]; process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, ! PT_DEFAULT, pe_info); *tbp = '\0'; if ((re = pcre_compile(remove_markup(tbuf, &searchlen), ! flags, &errptr, &erroffset, tables)) == NULL) { ! /* Matching error. */ ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; } ! add_check("pcre"); /* re */ if (searchlen) ! searchlen--; /* If we're doing a lot, study the regexp to make sure it's good */ if (all) { ! study = pcre_study(re, 0, &errptr); ! if (errptr != NULL) { ! mush_free((Malloc_t) re, "pcre"); ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; ! } ! if (study != NULL) ! /* study */ ! add_check("pcre.extra"); } search = 0; /* Do all the searches and replaces we can */ do { ! subpatterns = ! pcre_exec(re, study, orig->text, orig->len, search, 0, offsets, 99); ! if (subpatterns >= 0) { ! /* We have a match */ ! /* Process the replacement */ ! r = args[i + 1]; ! global_eval_context.re_code = re; ! global_eval_context.re_from = orig; ! global_eval_context.re_offsets = offsets; ! global_eval_context.re_subpatterns = subpatterns; ! tbp = tbuf; ! process_expression(tbuf, &tbp, &r, executor, caller, enactor, ! PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info); ! *tbp = '\0'; ! if (offsets[0] >= search) { ! repl = parse_ansi_string(tbuf); ! ! /* Do the replacement */ ! ansi_string_replace(orig, offsets[0], offsets[1] - offsets[0], repl, ! 0, repl->len); ! ! /* Advance search */ ! if (search == offsets[1]) { ! search = offsets[0] + repl->len; ! search++; ! } else { ! search = offsets[0] + repl->len; ! } ! /* if (offsets[0] < 1) search++; */ ! ! free_ansi_string(repl); ! if (search >= orig->len) ! break; ! } else { ! break; ! } ! } } while (subpatterns >= 0 && all); mush_free((Malloc_t) re, "pcre"); if (study != NULL) ! mush_free((Malloc_t) study, "pcre.extra"); } safe_ansi_string(orig, 0, orig->len, buff, bp); free_ansi_string(orig); --- 3322,3400 ---- tbp = tbuf; r = args[i]; process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, ! PT_DEFAULT, pe_info); *tbp = '\0'; if ((re = pcre_compile(remove_markup(tbuf, &searchlen), ! flags, &errptr, &erroffset, tables)) == NULL) { ! /* Matching error. */ ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; } ! add_check("pcre"); /* re */ if (searchlen) ! searchlen--; /* If we're doing a lot, study the regexp to make sure it's good */ if (all) { ! study = pcre_study(re, 0, &errptr); ! if (errptr != NULL) { ! mush_free((Malloc_t) re, "pcre"); ! safe_str(T("#-1 REGEXP ERROR: "), buff, bp); ! safe_str(errptr, buff, bp); ! free_ansi_string(orig); ! return; ! } ! if (study != NULL) ! /* study */ ! add_check("pcre.extra"); } search = 0; /* Do all the searches and replaces we can */ do { ! subpatterns = ! pcre_exec(re, study, orig->text, orig->len, search, 0, offsets, 99); ! if (subpatterns >= 0) { ! /* We have a match */ ! /* Process the replacement */ ! r = args[i + 1]; ! global_eval_context.re_code = re; ! global_eval_context.re_from = orig; ! global_eval_context.re_offsets = offsets; ! global_eval_context.re_subpatterns = subpatterns; ! tbp = tbuf; ! process_expression(tbuf, &tbp, &r, executor, caller, enactor, ! PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info); ! *tbp = '\0'; ! if (offsets[0] >= search) { ! repl = parse_ansi_string(tbuf); ! ! /* Do the replacement */ ! ansi_string_replace(orig, offsets[0], offsets[1] - offsets[0], repl, ! 0, repl->len); ! ! /* Advance search */ ! if (search == offsets[1]) { ! search = offsets[0] + repl->len; ! search++; ! } else { ! search = offsets[0] + repl->len; ! } ! /* if (offsets[0] < 1) search++; */ ! ! free_ansi_string(repl); ! if (search >= orig->len) ! break; ! } else { ! break; ! } ! } } while (subpatterns >= 0 && all); mush_free((Malloc_t) re, "pcre"); if (study != NULL) ! mush_free((Malloc_t) study, "pcre.extra"); } safe_ansi_string(orig, 0, orig->len, buff, bp); free_ansi_string(orig); *** 1_8_3p0/src/funmisc.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/funmisc.c Sun Mar 11 20:38:07 2007 *************** *** 69,74 **** --- 69,75 ---- { int ns = string_prefix(called_as, "NS"); int flags = PEMIT_LIST; + dbref saved_orator = orator; if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); *************** *** 78,83 **** --- 79,85 ---- if (ns) flags |= PEMIT_SPOOF; do_pemit_list(executor, args[0], args[1], flags); + orator = saved_orator; } *** 1_8_3p0/src/funstr.c Sat Jan 27 05:24:13 2007 --- 1_8_3p1/src/funstr.c Sun Mar 11 20:38:07 2007 *************** *** 2029,2035 **** if (strlen(rbuff) > 0) { safe_format(buff, bp, "%s %s %s", Name(speaker), say_string, rbuff); return; ! } else { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) --- 2029,2035 ---- if (strlen(rbuff) > 0) { safe_format(buff, bp, "%s %s %s", Name(speaker), say_string, rbuff); return; ! } else if (null == 1) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) *************** *** 2079,2085 **** pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; ! if (strlen(rbuff) == 0) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) --- 2079,2085 ---- pe_info->fun_invocations == funccount) break; funccount = pe_info->fun_invocations; ! if ((null == 1) && (strlen(rbuff) == 0)) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) *** 1_8_3p0/src/funtime.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/funtime.c Sun Mar 11 20:38:07 2007 *************** *** 202,214 **** /* ARGSUSED */ FUNCTION(fun_stringsecs) { ! /* parse the result from timestring() back into a number of seconds */ ! int secs = 0; ! char *str1 = args[0]; char str2[BUFFER_LEN]; int i; while (str1 && *str1) { while (*str1 == ' ') str1++; --- 202,228 ---- /* ARGSUSED */ FUNCTION(fun_stringsecs) { ! int secs; ! if (etime_to_secs(args[0], &secs)) ! safe_integer(secs, buff, bp); ! else ! safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); ! } ! /** Convert an elapsed time string (3d 2h 1m 10s) to seconds. ! * \param str1 a time string. ! * \param secs pointer to an int to fill with number of seconds. ! * \retval 1 success. ! * \retval 0 failure. ! */ ! int ! etime_to_secs(char *str1, int *secs) ! { ! /* parse the result from timestring() back into a number of seconds */ char str2[BUFFER_LEN]; int i; + *secs = 0; while (str1 && *str1) { while (*str1 == ' ') str1++; *************** *** 219,257 **** i++; } if (i == 0) { ! safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); // no numbers ! return; } str2[i] = '\0'; if (!*str1) { ! secs += parse_integer(str2); // no more chars, just add seconds and stop break; } switch (*str1) { case 'd': case 'D': ! secs += (parse_integer(str2) * 86400); // days break; case 'h': case 'H': ! secs += (parse_integer(str2) * 3600); // hours break; case 'm': case 'M': ! secs += (parse_integer(str2) * 60); // minutes break; case 's': case 'S': case ' ': ! secs += parse_integer(str2); // seconds break; default: ! safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); ! return; } str1++; // move past the time char } ! safe_integer(secs, buff, bp); } /* ARGSUSED */ --- 233,269 ---- i++; } if (i == 0) { ! return 0; /* No numbers given */ } str2[i] = '\0'; if (!*str1) { ! *secs += parse_integer(str2); // no more chars, just add seconds and stop break; } switch (*str1) { case 'd': case 'D': ! *secs += (parse_integer(str2) * 86400); // days break; case 'h': case 'H': ! *secs += (parse_integer(str2) * 3600); // hours break; case 'm': case 'M': ! *secs += (parse_integer(str2) * 60); // minutes break; case 's': case 'S': case ' ': ! *secs += parse_integer(str2); // seconds break; default: ! return 0; } str1++; // move past the time char } ! return 1; } /* ARGSUSED */ *** 1_8_3p0/src/rob.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/rob.c Sun Mar 11 20:38:07 2007 *************** *** 158,164 **** do_buy(dbref player, char *item, char *from, int price) { dbref vendor; ! char *prices; char *plus; char *cost; char finditem[BUFFER_LEN]; --- 158,164 ---- do_buy(dbref player, char *item, char *from, int price) { dbref vendor; ! char prices[BUFFER_LEN]; char *plus; char *cost; char finditem[BUFFER_LEN]; *************** *** 226,235 **** a = atr_get(vendor, "PRICELIST"); if (!a) continue; ! /* atr_value uses a static buffer, so we'll take advantage of that */ ! prices = atr_value(a); upcasestr(prices); ! count = list2arr(r, BUFFER_LEN / 2, atr_value(a), ' '); if (!count) continue; for (i = 0; i < count; i++) { --- 226,235 ---- a = atr_get(vendor, "PRICELIST"); if (!a) continue; ! strncpy(prices, atr_value(a), BUFFER_LEN); ! prices[BUFFER_LEN - 1] = '\0'; upcasestr(prices); ! count = list2arr(r, BUFFER_LEN / 2, prices, ' '); if (!count) continue; for (i = 0; i < count; i++) { *** 1_8_3p0/src/speech.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/speech.c Sun Mar 11 20:38:07 2007 *************** *** 650,655 **** --- 650,656 ---- int key; char *tbuf, *tp; char *tbuf2, *tp2; + char *tbuf3, *tp3; dbref good[100]; int gcount = 0; char *msgbuf, *mb; *************** *** 663,668 **** --- 664,670 ---- int is_haven; ATTR *a; char *alias; + const char *pageformat_argv[4]; tp2 = tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string"); if (!tbuf2) *************** *** 872,878 **** message); /* Figure out the 'name' of the player */ ! if (PAGE_ALIASES && (alias = shortalias(player)) && *alias) current = tprintf("%s (%s)", Name(player), alias); else current = (char *) Name(player); --- 874,880 ---- message); /* Figure out the 'name' of the player */ ! if ((alias = shortalias(player)) && *alias && PAGE_ALIASES) current = tprintf("%s (%s)", Name(player), alias); else current = (char *) Name(player); *************** *** 905,921 **** *tp = '\0'; /* Tell each page recipient with tbuf */ for (i = 0; i < gcount; i++) { ! if (!IsPlayer(player) && Nospoof(good[i])) ! notify_format(good[i], "[#%d] %s", player, tbuf); ! else ! notify(good[i], tbuf); page_return(player, good[i], "Idle", "IDLE", NULL); } mush_free((Malloc_t) tbuf, "string"); mush_free((Malloc_t) tbuf2, "string"); if (msgbuf) mush_free((Malloc_t) msgbuf, "string"); if (hp) --- 907,948 ---- *tp = '\0'; /* Tell each page recipient with tbuf */ + pageformat_argv[0] = message; + pageformat_argv[1] = (key == 1) ? (*gap ? ":" : ";") : "\""; + pageformat_argv[2] = (alias && *alias) ? alias : ""; + tp2 = tbuf2; + if (multipage) { + for (i = 0; i < gcount; i++) { + if (i) + safe_chr(' ', tbuf2, &tp2); + safe_dbref(good[i], tbuf2, &tp2); + } + } + *tp2 = '\0'; + pageformat_argv[3] = tbuf2; + tbuf3 = mush_malloc(BUFFER_LEN, "string"); for (i = 0; i < gcount; i++) { ! *tbuf3 = '\0'; ! if (!call_attrib(good[i], "PAGEFORMAT", pageformat_argv, 4, tbuf3, ! player, NULL) && *tbuf3) { ! if (!IsPlayer(player) && Nospoof(good[i])) ! notify_format(good[i], "[#%d] %s", player, tbuf3); ! else ! notify(good[i], tbuf3); ! } else { ! if (!IsPlayer(player) && Nospoof(good[i])) ! notify_format(good[i], "[#%d] %s", player, tbuf); ! else ! notify(good[i], tbuf); ! } ! page_return(player, good[i], "Idle", "IDLE", NULL); } mush_free((Malloc_t) tbuf, "string"); mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf3, "string"); if (msgbuf) mush_free((Malloc_t) msgbuf, "string"); if (hp) *** 1_8_3p0/src/sql.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/sql.c Sun Mar 11 20:38:07 2007 *************** *** 3,8 **** --- 3,26 ---- * * \brief Code to support PennMUSH connection to SQL databases. * + * Each sql database we support must define its own set of the + * following functions: + * + * penn__sql_init + * penn__sql_connected + * penn__sql_errormsg + * penn__sql_shutdown + * penn__sql_query + * penn__free_sql_query + * + * We define generic functions (named as above, but without _) + * that determine the platform and call the appropriate platform-specific + * function. We also define the softcode interfaces: + * + * fun_sql_escape + * fun_sql + * fun_mapsql + * cmd_sql * */ *************** *** 20,25 **** --- 38,48 ---- #ifdef HAS_MYSQL #include #include + static MYSQL *mysql_connp = NULL; + #endif + #ifdef HAS_POSTGRESQL + #include + static PGconn *postgres_connp = NULL; #endif #include "externs.h" #include "log.h" *************** *** 32,169 **** #include "confmagic.h" #include "ansi.h" ! #ifdef HAS_MYSQL ! static MYSQL *mysql_struct = NULL; ! #define MYSQL_RETRY_TIMES 3 ! static MYSQL_RES *sql_query(char *query_str, int *affected_rows); ! static void free_sql_query(MYSQL_RES * qres); ! static int sql_init(void); ! void ! sql_shutdown(void) { ! if (!mysql_struct) ! return; ! mysql_close(mysql_struct); ! mysql_struct = NULL; } ! static int sql_init(void) { ! int retries = MYSQL_RETRY_TIMES; ! static time_t last_retry = 0; ! time_t curtime; ! ! /* Only retry at most once per minute. */ ! curtime = time(NULL); ! if (curtime < (last_retry + 60)) return 0; - last_retry = curtime; - - /* If we are already connected, drop and retry the connection, in - * case for some reason the server went away. - */ - if (mysql_struct) - sql_shutdown(); - - if (!strcasecmp(SQL_PLATFORM, "mysql")) { - while (retries && !mysql_struct) { - /* Try to connect to the database host. If we have specified - * localhost, use the Unix domain socket instead. - */ - mysql_struct = mysql_init(NULL); - - if (!mysql_real_connect - (mysql_struct, SQL_HOST, SQL_USER, SQL_PASS, SQL_DB, 3306, 0, 0)) { - do_rawlog(LT_ERR, "Failed mysql connection: %s\n", - mysql_error(mysql_struct)); - sql_shutdown(); - sleep(1); - } - retries--; - } } ! if (mysql_struct) ! return 1; ! else return 0; } ! static MYSQL_RES * ! sql_query(char *q_string, int *affected_rows) { ! MYSQL_RES *qres; ! int fail; - /* No affected rows by default */ - *affected_rows = -1; ! /* Make sure we have something to query, first. */ ! if (!q_string || !*q_string) ! return NULL; ! /* If we have no connection, and we don't have auto-reconnect on ! * (or we try to auto-reconnect and we fail), return NULL. ! */ ! if (!mysql_struct) { ! sql_init(); ! if (!mysql_struct) { ! return NULL; ! } } ! /* Send the query. If it returns non-zero, we have an error. */ ! fail = mysql_real_query(mysql_struct, q_string, strlen(q_string)); ! if (fail && (mysql_errno(mysql_struct) == CR_SERVER_GONE_ERROR)) { ! /* If it's CR_SERVER_GONE_ERROR, the server went away. ! * Try reconnecting. */ sql_init(); ! if (mysql_struct) ! fail = mysql_real_query(mysql_struct, q_string, strlen(q_string)); } ! /* If we still fail, it's an error. */ ! if (fail) { ! return NULL; } - /* Get the result */ - qres = mysql_use_result(mysql_struct); if (!qres) { ! if (!mysql_field_count(mysql_struct)) { ! /* We didn't expect data back, so see if we modified anything */ ! *affected_rows = mysql_affected_rows(mysql_struct); ! return NULL; } else { ! /* Oops, we should have had data! */ ! return NULL; } } - return qres; - } ! void ! free_sql_query(MYSQL_RES * qres) ! { ! MYSQL_ROW row_p; ! while ((row_p = mysql_fetch_row(qres)) != NULL) ; ! mysql_free_result(qres); } FUNCTION(fun_mapsql) { ! MYSQL_RES *qres; ! MYSQL_ROW row_p; ufun_attrib ufun; char *wenv[10]; char *osep = (char *) " "; int affected_rows; int rownum; char numbuff[20]; ! int numfields; char rbuff[BUFFER_LEN]; int funccount = 0; int do_fieldnames = 0; --- 55,391 ---- #include "confmagic.h" #include "ansi.h" ! /* Supporte platforms */ ! #define SQL_PLATFORM_DISABLED -1 ! #define SQL_PLATFORM_MYSQL 1 ! #define SQL_PLATFORM_POSTGRESQL 2 ! ! /* Number of times to try a connection */ ! #define SQL_RETRY_TIMES 3 ! ! #define sql_test_result(qres) \ ! if (!qres) { \ ! if (affected_rows >= 0) { \ ! notify_format(executor, "SQL: %d rows affected.", affected_rows); \ ! } else if (!sql_connected()) { \ ! notify(executor, "No SQL database connection."); \ ! } else { \ ! notify_format(executor, "SQL: Error: %s", sql_error()); \ ! safe_str("#-1", buff, bp); \ ! } \ ! return; \ ! } ! #ifdef HAS_MYSQL ! static MYSQL_RES *penn_mysql_sql_query(char *query_str, int *affected_rows); ! static void penn_mysql_free_sql_query(MYSQL_RES * qres); ! static int penn_mysql_sql_init(void); ! static void penn_mysql_sql_shutdown(void); ! static int penn_mysql_sql_connected(void); ! #endif ! #ifdef HAS_POSTGRESQL ! static PGresult *penn_pg_sql_query(char *q_string, int *affected_rows); ! static void penn_pg_free_sql_query(PGresult * qres); ! static int penn_pg_sql_init(void); ! static void penn_pg_sql_shutdown(void); ! static int penn_pg_sql_connected(void); ! #endif ! static int sql_platform(void); ! /* A helper function to translate SQL_PLATFORM into one of our ! * supported platform codes. We remember this value, so a reboot ! * is necessary to change it. ! */ ! static int ! sql_platform(void) { ! static int platform = 0; ! if (platform) ! return platform; ! platform = SQL_PLATFORM_DISABLED; ! #ifdef HAS_MYSQL ! if (!strcasecmp(SQL_PLATFORM, "mysql")) ! platform = SQL_PLATFORM_MYSQL; ! #endif ! #ifdef HAS_POSTGRESQL ! if (!strcasecmp(SQL_PLATFORM, "postgres")) ! platform = SQL_PLATFORM_POSTGRESQL; ! if (!strcasecmp(SQL_PLATFORM, "postgresql")) ! platform = SQL_PLATFORM_POSTGRESQL; ! #endif ! return platform; } ! /* Initialize a connection to an SQL database */ static int sql_init(void) { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! return penn_mysql_sql_init(); ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! return penn_pg_sql_init(); ! #endif ! default: return 0; } + } ! /* Check if a connection exists */ ! static int ! sql_connected(void) ! { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! return penn_mysql_sql_connected(); ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! return penn_pg_sql_connected(); ! #endif ! default: return 0; + } } ! /* Return an error string if needed */ ! static char * ! sql_error(void) { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! return (char *) mysql_error(mysql_connp); ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! return PQerrorMessage(postgres_connp); ! #endif ! default: ! return NULL; ! } ! } ! /** Shut down a connection to an SQL database */ ! void ! sql_shutdown(void) ! { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! penn_mysql_sql_shutdown(); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! penn_pg_sql_shutdown(); ! break; ! #endif ! default: ! return; ! } ! } ! static void ! free_sql_query(void *queryp) ! { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! penn_mysql_free_sql_query((MYSQL_RES *) queryp); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! penn_pg_free_sql_query((PGresult *) queryp); ! break; ! #endif ! default: ! return; } + } ! static void * ! sql_query(char *query_str, int *affected_rows) ! { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! return penn_mysql_sql_query(query_str, affected_rows); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! return penn_pg_sql_query(query_str, affected_rows); ! break; ! #endif ! default: ! return NULL; ! } ! } ! ! FUNCTION(fun_sql_escape) ! { ! char bigbuff[BUFFER_LEN * 2 + 1]; ! int chars_written; ! if (sql_platform() == SQL_PLATFORM_DISABLED) { ! safe_str(T(e_disabled), buff, bp); ! return; ! } ! if (!Sql_Ok(executor)) { ! safe_str(T(e_perm), buff, bp); ! return; ! } ! if (!args[0] || !*args[0]) ! return; ! if (!sql_connected()) { sql_init(); ! if (!sql_connected()) { ! notify(executor, "No SQL database connection."); ! safe_str("#-1", buff, bp); ! return; ! } } ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! chars_written = ! mysql_real_escape_string(mysql_connp, bigbuff, args[0], strlen(args[0])); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! chars_written = ! PQescapeStringConn(postgres_connp, bigbuff, args[0], strlen(args[0]), ! NULL); ! break; ! #endif ! default: ! safe_str(T(e_disabled), buff, bp); ! return; } + if (chars_written < BUFFER_LEN) + safe_str(bigbuff, buff, bp); + else + safe_str("#-1 TOO LONG", buff, bp); + } + + + COMMAND (cmd_sql) { + #ifdef HAS_MYSQL + MYSQL_FIELD *fields; + #endif + void *qres; + int affected_rows; + int rownum; + int numfields; + int numrows; + char *cell; + char *name; + char tbuf[BUFFER_LEN]; + char *tbp; + ansi_string *as; + int i; + + qres = sql_query(arg_left, &affected_rows); if (!qres) { ! if (affected_rows >= 0) { ! notify_format(player, "SQL: %d rows affected.", affected_rows); ! } else if (!sql_connected()) { ! notify(player, "No SQL database connection."); } else { ! notify_format(player, "SQL: Error: %s", sql_error()); } + return; } ! /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! numfields = mysql_num_fields(qres); ! numrows = mysql_num_rows(qres); ! fields = mysql_fetch_fields(qres); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! numfields = PQnfields(qres); ! numrows = PQntuples(qres); ! break; ! #endif ! default: ! return; ! } ! ! for (rownum = 0; rownum < numrows; rownum++) { ! #ifdef HAS_MYSQL ! MYSQL_ROW row_p; ! if (sql_platform() == SQL_PLATFORM_MYSQL) ! row_p = mysql_fetch_row(qres); ! #endif ! if (numfields > 0) { ! for (i = 0; i < numfields; i++) { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! cell = row_p[i]; ! name = fields[i].name; ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! cell = PQgetvalue(qres, rownum, i); ! name = PQfname(qres, i); ! break; ! #endif ! } ! if (cell && *cell) { ! if (strchr(cell, ESC_CHAR)) { ! /* Old style ANSI string */ ! tbp = tbuf; ! as = parse_ansi_string_real(cell, 1); ! safe_ansi_string(as, 0, as->len, tbuf, &tbp); ! *tbp = '\0'; ! free_ansi_string(as); ! cell = tbuf; ! } else if (strchr(cell, TAG_START)) { ! /* Either old or new style ANSI string, ! * We assume new style. */ ! tbp = tbuf; ! as = parse_ansi_string_real(cell, 2); ! safe_ansi_string(as, 0, as->len, tbuf, &tbp); ! *tbp = '\0'; ! free_ansi_string(as); ! cell = tbuf; ! } ! } ! notify_format(player, "Row %d, Field %s: %s", ! rownum, name, (cell && *cell) ? cell : "NULL"); ! } ! } else ! notify_format(player, "Row %d: NULL", rownum); ! } ! ! free_sql_query(qres); } FUNCTION(fun_mapsql) { ! void *qres; ufun_attrib ufun; char *wenv[10]; char *osep = (char *) " "; int affected_rows; int rownum; char numbuff[20]; ! int numfields, numrows; char rbuff[BUFFER_LEN]; int funccount = 0; int do_fieldnames = 0; *************** *** 172,179 **** --- 394,407 ---- char *tbp; char *cell; ansi_string *as; + #ifdef HAS_MYSQL MYSQL_FIELD *fields; + #endif + if (sql_platform() == SQL_PLATFORM_DISABLED) { + safe_str(T(e_disabled), buff, bp); + return; + } if (!Sql_Ok(executor)) { safe_str(T(e_perm), buff, bp); return; *************** *** 197,239 **** wenv[i] = NULL; qres = sql_query(args[1], &affected_rows); ! if (!qres) { ! if (affected_rows >= 0) { ! notify_format(executor, "SQL: %d rows affected.", affected_rows); ! } else if (!mysql_struct) { ! notify(executor, "No SQL database connection."); ! } else { ! notify_format(executor, "SQL: Error: %s", mysql_error(mysql_struct)); ! safe_str("#-1", buff, bp); ! } return; } - /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ - numfields = mysql_num_fields(qres); - if (do_fieldnames) { - fields = mysql_fetch_fields(qres); strncpy(numbuff, unparse_integer(0), 20); wenv[0] = numbuff; ! for (i = 0; i < numfields && i < 9; i++) { ! wenv[i + 1] = fields[i].name; } if (call_ufun(&ufun, wenv, i + 1, rbuff, executor, enactor, pe_info)) goto finished; safe_str(rbuff, buff, bp); } ! rownum = 0; ! while ((row_p = mysql_fetch_row(qres)) != NULL) { ! if (rownum++ > 0 || do_fieldnames) { safe_str(osep, buff, bp); } ! strncpy(numbuff, unparse_integer(rownum), 20); wenv[0] = numbuff; for (i = 0; (i < numfields) && (i < 9); i++) { ! cell = row_p[i]; if (strchr(cell, ESC_CHAR)) { /* Old style ANSI string */ tbp = buffs[i]; --- 425,503 ---- wenv[i] = NULL; qres = sql_query(args[1], &affected_rows); + sql_test_result(qres); ! /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! numfields = mysql_num_fields(qres); ! numrows = mysql_num_rows(qres); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! numfields = PQnfields(qres); ! numrows = PQntuples(qres); ! break; ! #endif ! default: return; } if (do_fieldnames) { strncpy(numbuff, unparse_integer(0), 20); wenv[0] = numbuff; ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! fields = mysql_fetch_fields(qres); ! for (i = 0; i < numfields && i < 9; i++) { ! wenv[i + 1] = fields[i].name; ! } ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! for (i = 0; i < numfields && i < 9; i++) { ! wenv[i + 1] = PQfname(qres, i); ! } ! break; ! #endif ! default: ! break; } if (call_ufun(&ufun, wenv, i + 1, rbuff, executor, enactor, pe_info)) goto finished; safe_str(rbuff, buff, bp); } ! for (rownum = 0; rownum < numrows; rownum++) { ! #ifdef HAS_MYSQL ! MYSQL_ROW row_p; ! if (sql_platform() == SQL_PLATFORM_MYSQL) ! row_p = mysql_fetch_row(qres); ! #endif ! if (rownum > 0 || do_fieldnames) { safe_str(osep, buff, bp); } ! strncpy(numbuff, unparse_integer(rownum + 1), 20); wenv[0] = numbuff; for (i = 0; (i < numfields) && (i < 9); i++) { ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! cell = row_p[i]; ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! cell = PQgetvalue(qres, rownum, i); ! break; ! #endif ! default: ! break; ! } if (strchr(cell, ESC_CHAR)) { /* Old style ANSI string */ tbp = buffs[i]; *************** *** 269,276 **** FUNCTION(fun_sql) { ! MYSQL_RES *qres; ! MYSQL_ROW row_p; char *rowsep = (char *) " "; char *fieldsep = (char *) " "; char tbuf[BUFFER_LEN], *tbp; --- 533,539 ---- FUNCTION(fun_sql) { ! void *qres; char *rowsep = (char *) " "; char *fieldsep = (char *) " "; char tbuf[BUFFER_LEN], *tbp; *************** *** 278,286 **** int affected_rows; int rownum; int i; ! int numfields; ansi_string *as; if (!Sql_Ok(executor)) { safe_str(T(e_perm), buff, bp); return; --- 541,553 ---- int affected_rows; int rownum; int i; ! int numfields, numrows; ansi_string *as; + if (sql_platform() == SQL_PLATFORM_DISABLED) { + safe_str(T(e_disabled), buff, bp); + return; + } if (!Sql_Ok(executor)) { safe_str(T(e_perm), buff, bp); return; *************** *** 298,330 **** qres = sql_query(args[0], &affected_rows); ! if (!qres) { ! if (affected_rows >= 0) { ! notify_format(executor, "SQL: %d rows affected.", affected_rows); ! } else if (!mysql_struct) { ! notify(executor, "No SQL database connection."); ! } else { ! notify_format(executor, "SQL: Error: %s", mysql_error(mysql_struct)); ! safe_str("#-1", buff, bp); ! } ! return; ! } /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ ! numfields = mysql_num_fields(qres); ! rownum = 0; ! while ((row_p = mysql_fetch_row(qres)) != NULL) { ! if (rownum++ > 0) { safe_str(rowsep, buff, bp); - } for (i = 0; i < numfields; i++) { if (i > 0) { if (safe_str(fieldsep, buff, bp)) goto finished; } ! if (row_p[i] && *row_p[i]) { cell = row_p[i]; if (strchr(cell, ESC_CHAR)) { /* Old style ANSI string */ tbp = tbuf; --- 565,618 ---- qres = sql_query(args[0], &affected_rows); ! sql_test_result(qres); /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: ! numfields = mysql_num_fields(qres); ! numrows = mysql_num_rows(qres); ! break; ! #endif ! #ifdef HAS_POSTGRESQL ! case SQL_PLATFORM_POSTGRESQL: ! numfields = PQnfields(qres); ! numrows = PQntuples(qres); ! break; ! #endif ! default: ! return; ! } ! for (rownum = 0; rownum < numrows; rownum++) { ! #ifdef HAS_MYSQL ! MYSQL_ROW row_p; ! if (sql_platform() == SQL_PLATFORM_MYSQL) ! row_p = mysql_fetch_row(qres); ! #endif ! if (rownum > 0) safe_str(rowsep, buff, bp); for (i = 0; i < numfields; i++) { if (i > 0) { if (safe_str(fieldsep, buff, bp)) goto finished; } ! switch (sql_platform()) { ! #ifdef HAS_MYSQL ! case SQL_PLATFORM_MYSQL: cell = row_p[i]; + break; + #endif + #ifdef HAS_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + cell = PQgetvalue(qres, rownum, i); + break; + #endif + default: + break; + } + if (cell && *cell) { if (strchr(cell, ESC_CHAR)) { /* Old style ANSI string */ tbp = tbuf; *************** *** 353,474 **** } - FUNCTION(fun_sql_escape) - { - char bigbuff[BUFFER_LEN * 2 + 1]; ! if (!Sql_Ok(executor)) { ! safe_str(T(e_perm), buff, bp); ! return; ! } ! if (!args[0] || !*args[0]) return; ! if (!mysql_struct) { ! sql_init(); ! if (!mysql_struct) { ! notify(executor, "No SQL database connection."); ! safe_str("#-1", buff, bp); ! return; } } - if (mysql_real_escape_string(mysql_struct, bigbuff, args[0], strlen(args[0])) - < BUFFER_LEN) - safe_str(bigbuff, buff, bp); - else - safe_str("#-1 TOO LONG", buff, bp); - } ! COMMAND (cmd_sql) { MYSQL_RES *qres; ! MYSQL_ROW row_p; ! int affected_rows; ! int rownum; ! int numfields; ! char *cell; ! MYSQL_FIELD *fields; ! char tbuf[BUFFER_LEN]; ! char *tbp; ! ansi_string *as; ! int i; ! qres = sql_query(arg_left, &affected_rows); ! if (!qres) { ! if (affected_rows >= 0) { ! notify_format(player, "SQL: %d rows affected.", affected_rows); ! } else if (!mysql_struct) { ! notify(player, "No SQL database connection."); ! } else { ! notify_format(player, "SQL: Error: %s", mysql_error(mysql_struct)); } - return; } ! /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ ! numfields = mysql_num_fields(qres); ! fields = mysql_fetch_fields(qres); ! rownum = 0; ! while ((row_p = mysql_fetch_row(qres)) != NULL) { ! rownum++; ! if (numfields > 0) { ! for (i = 0; i < numfields; i++) { ! cell = row_p[i]; ! if (cell && *cell) { ! if (strchr(cell, ESC_CHAR)) { ! /* Old style ANSI string */ ! tbp = tbuf; ! as = parse_ansi_string_real(cell, 1); ! safe_ansi_string(as, 0, as->len, tbuf, &tbp); ! *tbp = '\0'; ! free_ansi_string(as); ! cell = tbuf; ! } else if (strchr(cell, TAG_START)) { ! /* Either old or new style ANSI string, ! * We assume new style. */ ! tbp = tbuf; ! as = parse_ansi_string_real(cell, 2); ! safe_ansi_string(as, 0, as->len, tbuf, &tbp); ! *tbp = '\0'; ! free_ansi_string(as); ! cell = tbuf; ! } ! } ! notify_format(player, "Row %d, Field %s: %s", ! rownum, fields[i].name, (cell && *cell) ? cell : "NULL"); ! } ! } else ! notify_format(player, "Row %d: NULL", rownum); } ! free_sql_query(qres); } ! #else ! /* Oops, no SQL */ ! FUNCTION(fun_sql) { ! safe_str(T(e_disabled), buff, bp); } ! FUNCTION(fun_mapsql) { ! safe_str(T(e_disabled), buff, bp); } ! FUNCTION(fun_sql_escape) { ! safe_str(T(e_disabled), buff, bp); } ! void ! sql_shutdown(void) { ! return; } ! #endif --- 641,892 ---- } ! /* MYSQL-specific functions */ ! #ifdef HAS_MYSQL ! static void ! penn_mysql_sql_shutdown(void) ! { ! if (!mysql_connp) return; + mysql_close(mysql_connp); + mysql_connp = NULL; + } ! static int ! penn_mysql_sql_connected(void) ! { ! return mysql_connp ? 1 : 0; ! } ! ! ! static int ! penn_mysql_sql_init(void) ! { ! int retries = SQL_RETRY_TIMES; ! static time_t last_retry = 0; ! char sql_host[BUFFER_LEN], *p; ! int sql_port = 3306; ! time_t curtime; ! ! /* Only retry at most once per minute. */ ! curtime = time(NULL); ! if (curtime < (last_retry + 60)) ! return 0; ! last_retry = curtime; ! ! /* If we are already connected, drop and retry the connection, in ! * case for some reason the server went away. ! */ ! if (sql_connected()) ! sql_shutdown(); ! ! /* Parse SQL_HOST into sql_host and sql_port */ ! strncpy(sql_host, SQL_HOST, BUFFER_LEN); ! sql_host[BUFFER_LEN - 1] = '\0'; ! if ((p = strchr(sql_host, ':'))) { ! *p++ = '\0'; ! sql_port = atoi(p); ! if (!sql_port) ! sql_port = 3306; ! } ! ! while (retries && !mysql_connp) { ! /* Try to connect to the database host. If we have specified ! * localhost, use the Unix domain socket instead. ! */ ! mysql_connp = mysql_init(NULL); ! ! if (!mysql_real_connect ! (mysql_connp, sql_host, SQL_USER, SQL_PASS, SQL_DB, sql_port, 0, 0)) { ! do_rawlog(LT_ERR, "Failed mysql connection: %s\n", ! mysql_error(mysql_connp)); ! sql_shutdown(); ! sleep(1); } + retries--; } + return sql_connected(); + } ! static MYSQL_RES * ! penn_mysql_sql_query(char *q_string, int *affected_rows) ! { MYSQL_RES *qres; ! int fail; ! /* No affected rows by default */ ! *affected_rows = -1; ! /* Make sure we have something to query, first. */ ! if (!q_string || !*q_string) ! return NULL; ! ! /* If we have no connection, and we don't have auto-reconnect on ! * (or we try to auto-reconnect and we fail), return NULL. ! */ ! if (!sql_connected()) { ! sql_init(); ! if (!sql_connected()) { ! return NULL; } } ! /* Send the query. If it returns non-zero, we have an error. */ ! fail = mysql_real_query(mysql_connp, q_string, strlen(q_string)); ! if (fail && (mysql_errno(mysql_connp) == CR_SERVER_GONE_ERROR)) { ! /* If it's CR_SERVER_GONE_ERROR, the server went away. ! * Try reconnecting. */ ! sql_init(); ! if (mysql_connp) ! fail = mysql_real_query(mysql_connp, q_string, strlen(q_string)); ! } ! /* If we still fail, it's an error. */ ! if (fail) { ! return NULL; ! } ! /* Get the result */ ! qres = mysql_store_result(mysql_connp); ! if (!qres) { ! if (mysql_field_count(mysql_connp) == 0) { ! /* We didn't expect data back, so see if we modified anything */ ! *affected_rows = mysql_affected_rows(mysql_connp); ! return NULL; ! } else { ! /* Oops, we should have had data! */ ! return NULL; ! } } ! return qres; } ! static void ! penn_mysql_free_sql_query(MYSQL_RES * qres) ! { ! MYSQL_ROW row_p; ! while ((row_p = mysql_fetch_row(qres)) != NULL) ; ! mysql_free_result(qres); ! } ! #endif ! #ifdef HAS_POSTGRESQL ! static void ! penn_pg_sql_shutdown(void) { ! if (!sql_connected()) ! return; ! PQfinish(postgres_connp); ! postgres_connp = NULL; } ! static int ! penn_pg_sql_connected(void) { ! return postgres_connp ? 1 : 0; } ! ! static int ! penn_pg_sql_init(void) { ! int retries = SQL_RETRY_TIMES; ! static time_t last_retry = 0; ! char sql_host[BUFFER_LEN], *p; ! char sql_port[BUFFER_LEN]; ! time_t curtime; ! ! /* Only retry at most once per minute. */ ! curtime = time(NULL); ! if (curtime < (last_retry + 60)) ! return 0; ! last_retry = curtime; ! ! /* If we are already connected, drop and retry the connection, in ! * case for some reason the server went away. ! */ ! if (sql_connected()) ! sql_shutdown(); ! ! /* Parse SQL_HOST into sql_host and sql_port */ ! strncpy(sql_host, SQL_HOST, BUFFER_LEN); ! strcpy(sql_port, "5432"); ! sql_host[BUFFER_LEN - 1] = '\0'; ! if ((p = strchr(sql_host, ':'))) { ! *p++ = '\0'; ! if (*p) ! strcpy(sql_port, p); ! } ! ! while (retries && !postgres_connp) { ! /* Try to connect to the database host. */ ! char conninfo[BUFFER_LEN]; ! snprintf(conninfo, BUFFER_LEN, ! "host=%s port=%s dbname=%s user=%s password=%s", sql_host, ! sql_port, SQL_DB, SQL_USER, SQL_PASS); ! postgres_connp = PQconnectdb(conninfo); ! if (PQstatus(postgres_connp) != CONNECTION_OK) { ! do_rawlog(LT_ERR, "Failed postgresql connection to %s: %s\n", ! PQdb(postgres_connp), PQerrorMessage(postgres_connp)); ! sql_shutdown(); ! sleep(1); ! } ! retries--; ! } ! ! return sql_connected(); } ! static PGresult * ! penn_pg_sql_query(char *q_string, int *affected_rows) { ! PGresult *qres; ! ! /* No affected rows by default */ ! *affected_rows = -1; ! ! /* Make sure we have something to query, first. */ ! if (!q_string || !*q_string) ! return NULL; ! ! /* If we have no connection, and we don't have auto-reconnect on ! * (or we try to auto-reconnect and we fail), return NULL. ! */ ! if (!sql_connected()) { ! sql_init(); ! if (!sql_connected()) { ! return NULL; ! } ! } ! ! /* Send the query. If it returns non-zero, we have an error. */ ! qres = PQexec(postgres_connp, q_string); ! if (!qres || (PQresultStatus(qres) != PGRES_COMMAND_OK && ! PQresultStatus(qres) != PGRES_TUPLES_OK)) { ! /* Serious error, try one more time */ ! sql_init(); ! if (sql_connected()) ! qres = PQexec(postgres_connp, q_string); ! if (!qres || (PQresultStatus(qres) != PGRES_COMMAND_OK && ! PQresultStatus(qres) != PGRES_TUPLES_OK)) { ! return NULL; ! } ! } ! ! if (PQresultStatus(qres) == PGRES_COMMAND_OK) { ! *affected_rows = atoi(PQcmdTuples(qres)); ! return NULL; ! } ! ! return qres; } ! static void ! penn_pg_free_sql_query(PGresult * qres) ! { ! PQclear(qres); ! } ! #endif /* HAS_POSTGRESQL */ *** 1_8_3p0/src/utils.c Sat Jan 27 02:21:10 2007 --- 1_8_3p1/src/utils.c Sun Mar 11 20:38:07 2007 *************** *** 147,154 **** AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; - return; } } parse_attrib(player, str, thing, attrib); } --- 147,154 ---- AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; } + return; } parse_attrib(player, str, thing, attrib); } *************** *** 318,323 **** --- 318,438 ---- return pe_ret; } + /** Given a thing, attribute, enactor and arguments for %0-%9, + * call the ufun with appropriate permissions on values given for + * wenv_args. The value returned is stored in the buffer pointed to + * by ret, if given. + * \param thing The thing that has the attribute to be called + * \param attrname The name of the attribute to call. + * \param wenv_args An array of string values for global_eval_context.wenv + * \param wenv_argc The number of wenv args to use. + * \param ret If desired, a pointer to a buffer in which the results + * of the process_expression are stored in. + * \param enactor The enactor. + * \param pe_info The pe_info passed to the FUNCTION + * \retval 0 success + * \retval 1 process_expression failed. (CPU time limit) + */ + int + call_attrib(dbref thing, const char *attrname, const char *wenv_args[], + int wenv_argc, char *ret, dbref enactor, PE_Info * pe_info) + { + char atrbuf[BUFFER_LEN]; + char rbuff[BUFFER_LEN]; + char *rp; + char *old_wenv[10]; + int old_args = 0; + int i; + int pe_ret; + char const *ap; + ATTR *attrib; + char *saver[NUMQ]; + + int old_re_subpatterns; + int *old_re_offsets; + ansi_string *old_re_from; + + /* Make sure we have a valid object to call first */ + if (!GoodObject(thing) || IsGarbage(thing)) + return 1; + + if (attrname == NULL || !*attrname) + return 1; + + /* Fetch the attrib contents */ + attrib = (ATTR *) atr_get(thing, attrname); + if (attrib == NULL) + return 1; + + strncpy(atrbuf, atr_value(attrib), BUFFER_LEN - 1); + atrbuf[BUFFER_LEN - 1] = '\0'; + if (!*atrbuf) + return 1; + + save_global_regs("localize", saver); + + /* Store regepx info */ + old_re_subpatterns = global_eval_context.re_subpatterns; + old_re_offsets = global_eval_context.re_offsets; + old_re_from = global_eval_context.re_from; + + /* If the user doesn't care about the return of the expression, + * then use our own rbuff. + */ + if (!ret) + ret = rbuff; + rp = ret; + + /* Set up %0-%9 */ + for (i = 0; i < wenv_argc; i++) { + old_wenv[i] = global_eval_context.wenv[i]; + global_eval_context.wenv[i] = (char *) wenv_args[i]; + } + for (; i < 10; i++) { + old_wenv[i] = global_eval_context.wenv[i]; + global_eval_context.wenv[i] = NULL; + } + /* Clear all q-regs */ + for (i = 0; i < NUMQ; i++) { + global_eval_context.renv[i][0] = '\0'; + } + + /* Set all the regexp patterns to NULL so they are not + * propogated */ + global_eval_context.re_subpatterns = -1; + global_eval_context.re_offsets = NULL; + global_eval_context.re_from = NULL; + + /* And now, make the call! =) */ + if (pe_info) { + old_args = pe_info->arg_count; + pe_info->arg_count = wenv_argc; + } + + ap = atrbuf; + pe_ret = process_expression(ret, &rp, &ap, thing, thing, + enactor, PE_DEFAULT, PT_DEFAULT, pe_info); + *rp = '\0'; + + /* Restore the old wenv */ + for (i = 0; i < 10; i++) { + global_eval_context.wenv[i] = old_wenv[i]; + } + + if (pe_info) { + pe_info->arg_count = old_args; + } + + /* Restore regexp patterns */ + global_eval_context.re_offsets = old_re_offsets; + global_eval_context.re_subpatterns = old_re_subpatterns; + global_eval_context.re_from = old_re_from; + + restore_global_regs("localize", saver); + + return pe_ret; + } + /** Given an exit, find the room that is its source through brute force. * This is used in pathological cases where the exit's own source * element is invalid. *** 1_8_3p0/utils/mkvershlp.pl Sat Jan 27 02:21:10 2007 --- 1_8_3p1/utils/mkvershlp.pl Sun Mar 11 20:38:09 2007 *************** *** 1,4 **** ! #!/usr/local/bin/perl # # Generate game/txt/hlp/ files from the CHANGES file(s). # Should be run by Makefile from top-level directory --- 1,4 ---- ! #!/usr/bin/perl # # Generate game/txt/hlp/ files from the CHANGES file(s). # Should be run by Makefile from top-level directory *** 1_8_3p0/win32/cmds.h Sat Jan 27 02:21:10 2007 --- 1_8_3p1/win32/cmds.h Sun Mar 11 21:21:30 2007 *************** *** 134,141 **** COMMAND_PROTO(cmd_version); COMMAND_PROTO(cmd_wait); COMMAND_PROTO(cmd_wall); - COMMAND_PROTO(cmd_warnings); COMMAND_PROTO(cmd_warn_on_missing); COMMAND_PROTO(cmd_wcheck); COMMAND_PROTO(cmd_whereis); COMMAND_PROTO(cmd_whisper); --- 134,141 ---- COMMAND_PROTO(cmd_version); COMMAND_PROTO(cmd_wait); COMMAND_PROTO(cmd_wall); COMMAND_PROTO(cmd_warn_on_missing); + COMMAND_PROTO(cmd_warnings); COMMAND_PROTO(cmd_wcheck); COMMAND_PROTO(cmd_whereis); COMMAND_PROTO(cmd_whisper);