/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* _/ _/ *
* _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ *
***************************************************************************
* Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), *
* Additional credits are in the help file CODECREDITS *
* All Rights Reserved. *
***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include "merc.h"
#include "interp.h"
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*
* Renamed so it can play itself system independent.
* Samson 10-12-03
*/
size_t mudstrlcpy( char *dst, const char *src, size_t siz )
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
/*
* Copy as many bytes as will fit
*/
if( n != 0 && --n != 0 )
{
do
{
if( ( *d++ = *s++ ) == 0 )
break;
}
while( --n != 0 );
}
/*
* Not enough room in dst, add NUL and traverse rest of src
*/
if( n == 0 )
{
if( siz != 0 )
*d = '\0'; /* NUL-terminate dst */
while( *s++ )
;
}
return ( s - src - 1 ); /* count does not include NUL */
}
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(initial dst) + strlen(src); if retval >= siz,
* truncation occurred.
*
* Renamed so it can play itself system independent.
* Samson 10-12-03
*/
size_t mudstrlcat( char *dst, const char *src, size_t siz )
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
size_t dlen;
/*
* Find the end of dst and adjust bytes left but don't go past end
*/
while( n-- != 0 && *d != '\0' )
d++;
dlen = d - dst;
n = siz - dlen;
if( n == 0 )
return ( dlen + strlen( s ) );
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return ( dlen + ( s - src ) ); /* count does not include NUL */
}
/*Originaly, i heard on gamedev that someone was looking for a way to stop xprintf
*from overflowing, ofcourse, people fail to think of functions like strlcpy, which
*is essentaily a safe xprintf, atleast as it has been described to me. I however
*chose to write my own system. This allows me to capture the function, and line
*of the overflowing string in question. Thus allowing me to essentaily find out
*where the mud overflows, and stop it from happening. Great little tool.
*All i ask is that you leave this header in place. -- Darien of Sandstorm:Mages Sanctuary
*/
void safe_printf( const char *file, const char *function, int line, int size, char *str, char *fmt, ... )
{
char buf[MAS];
va_list args;
va_start( args, fmt );
vsprintf( buf, fmt, args );
va_end( args );
/*
* Max Alloc Size is allot!
*/
if( size > MAS )
{
log_string( LOG_BUG, "xprintf size greater then MAS!!!!\n\r" );
log_string( LOG_BUG, "Warning: Overflow has been caught by xprintf.\n\r" );
log_string( LOG_BUG, "Memcheck: xprintf:File %s, Function %s, Line %d.\n\r", file, function, line );
wiznet_printf( NULL, NULL, WIZ_MEMCHECK, 0, 0, "Memcheck: System memory corrupted by overflow through xprintf: File: %s Function: %s Line: %d", file, function, line );
return;
}
if( ( unsigned )size < strlen( buf ) + 1 )
{
log_string( LOG_BUG, "XPRINTF error: fmt %s.\n\r", fmt );
log_string( LOG_BUG, "Warning: Overflow has been caught by xprintf.\n\r" );
log_string( LOG_BUG, "Memcheck: xprintf: File %s, Function %s, Line %d.\n\r", file, function, line );
wiznet_printf( NULL, NULL, WIZ_MEMCHECK, 0, 0, "Memcheck: System memory corrupted by overflow through xprintf: File: %s Function: %s Line: %d", file, function, line );
}
else
{
mudstrlcpy( str, buf, size );
/*
* Just double checking.
*/
if( strlen( str ) > ( unsigned )size - 1 )
{
char egbug[MSL];
log_string( LOG_BUG, "XPRINTF error: fmt %s.\n\r", fmt );
log_string( LOG_BUG, "Warning: Overflow has been caught by xprintf.\n\r" );
log_string( LOG_BUG, "Memcheck: Xprintf: File %s, Function %s, Line %d.\n\r", file, function, line );
/*
* Yes, this is a potential loop bug if infact the xprintf does collapse in on itself..
*/
xprintf( egbug, "Memcheck: System memory corrupted by overflow through xprintf: File: %s Function: %s Line: %d",
file, function, line );
wiznet( egbug, NULL, NULL, WIZ_MEMCHECK, 0, 0 );
}
}
}
/* xcatf a formated string */
void safe_strcatf( const char *file, const char *function, int line, int size, char *prev, char *next, ... )
{
char buf[MAS];
va_list args;
va_start( args, next );
vsnprintf( buf, MAS, next, args );
va_end( args );
/*
* Max Alloc Size is allot!
*/
if( size > MAS )
{
char egbug[MSL];
log_string( LOG_BUG, "xcatf size greater then MAS!!!!\n\r" );
log_string( LOG_BUG, "ERROR: System Memory Corrupted by Overflow, through xcatf.\n\r" );
log_string( LOG_BUG, "Memcheck: xcatf:File %s, Function %s, Line %d.\n\r", file, function, line );
xprintf( egbug, "Memcheck: System memory corrupted by overflow through xcatf: File: %s Function: %s Line: %d", file,
function, line );
wiznet( egbug, NULL, NULL, WIZ_MEMCHECK, 0, 0 );
return;
}
if( ( unsigned )size < strlen( buf ) + 1 )
{
char egbug[MSL];
log_string( LOG_BUG, "XCATF error: fmt %s.\n\r", next );
log_string( LOG_BUG, "ERROR: System Memory Corrupted by Overflow, through xcatf.\n\r" );
log_string( LOG_BUG, "Memcheck: xcatf: File %s, Function %s, Line %d.\n\r", file, function, line );
/*
* Yes, this is a potential loop bug if infact the xcatf does collapse in on itself..
*/
xprintf( egbug, "Memcheck: System memory corrupted by overflow through xcatf: File: %s Function: %s Line: %d", file,
function, line );
wiznet( egbug, NULL, NULL, WIZ_MEMCHECK, 0, 0 );
return;
}
mudstrlcat( prev, buf, size );
/*
* Just double checking.
*/
if( strlen( prev ) > ( unsigned )size - 1 )
{
char egbug[MSL];
log_string( LOG_BUG, "XCATF error: fmt %s.\n\r", next );
log_string( LOG_BUG, "ERROR: System Memory Corrupted by Overflow, through xcatf.\n\r" );
log_string( LOG_BUG, "Memcheck: Xcatf: File %s, Function %s, Line %d.\n\r", file, function, line );
/*
* Yes, this is a potential loop bug if infact the xcatf does collapse in on itself..
*/
xprintf( egbug, "Memcheck: System memory corrupted by overflow through xcatf: File: %s Function: %s Line: %d", file,
function, line );
wiznet( egbug, NULL, NULL, WIZ_MEMCHECK, 0, 0 );
}
}
char *get_curdate( void )
{
static char buf[128];
struct tm *datetime;
datetime = localtime( ¤t_time );
strftime( buf, sizeof( buf ), "%m-%d-%Y", datetime );
return buf;
}
void log_string( int type, const char *fmt, ... )
{
DESCRIPTOR_DATA *d;
va_list args;
char *strtime;
char buf[45];
char bufew[2 * MSL];
char bufee[2 * MSL];
FILE *log_file;
buf[0] = '\0';
log_file = NULL;
// Get the wanted text
va_start( args, fmt );
vsprintf( bufew, fmt, args );
va_end( args );
if( type & LOG_CRIT )
{
xprintf( buf, "../log/%s.critical", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
for( d = descriptor_list; d != NULL; d = d->next )
if( d->connected == CON_PLAYING && IS_IMMORTAL( d->character ) )
printf_to_char( d->character, "Critical: %s\n\r", bufew );
xprintf( bufee, "Critical: %s", bufew );
}
if( type & LOG_ERR )
{
xprintf( buf, "../log/%s.error", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fprintf( stderr, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Error: %s", bufew );
}
if( type & LOG_BUG )
{
xprintf( buf, "../log/%s.bug", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Bug: %s", bufew );
log_string2( bufee );
}
if( type & LOG_SECURITY )
{
xprintf( buf, "../log/%s.security", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Security: %s", bufew );
}
if( type & LOG_CONNECT )
{
xprintf( buf, "../log/%s.connect", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Connect: %s", bufew );
}
if( type & LOG_GAME )
{
xprintf( buf, "../log/%s.game", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fprintf( stderr, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Game: %s", bufew );
}
if( type & LOG_COMMAND )
{
xprintf( buf, "../log/%s.comm", get_curdate( ) );
log_file = fopen( buf, "a" );
strtime = ctime( ¤t_time );
strtime[strlen( strtime ) - 1] = '\0';
fprintf( log_file, "%s :: %s\n", strtime, bash_color( bufew ) );
fflush( log_file );
fclose( log_file );
xprintf( bufee, "Command: %s", bufew );
}
wiznet(bufee,NULL,NULL, WIZ_DEBUG, 0, 7);
}
void do_wiznet( CHAR_DATA * ch, char *argument )
{
int flag;
int col = 0;
char buf[MAX_STRING_LENGTH];
if( argument[0] == '\0' )
/* Show wiznet options - just like channel command */
{
send_to_char( "\n\r#WWELCOME TO WIZNET!!!\n\r", ch );
send_to_char( "#0Option Status Option Status\n\r", ch );
send_to_char( "#B---------------------------------------------#n\n\r", ch );
/*
* list of all wiznet options
*/
buf[0] = '\0';
for( flag = 0; wiznet_table[flag].name != NULL; flag++ )
{
if( wiznet_table[flag].level <= get_trust( ch ) )
{
xprintf( buf, "#P%-14s#n %s\t", wiznet_table[flag].name,
IS_SET( ch->wiznet, wiznet_table[flag].flag ) ? "#GON#n" : "#ROFF#n" );
send_to_char( buf, ch );
col++;
if( col == 2 )
{
send_to_char( "\n\r", ch );
col = 0;
}
}
}
/* To avoid color bleeding */
send_to_char( "\n\r#n", ch );
return;
}
if( !str_prefix( argument, "on" ) )
{
send_to_char( "#GWelcome to Wiznet!#n\n\r", ch );
SET_BIT( ch->wiznet, WIZ_ON );
return;
}
if( !str_prefix( argument, "off" ) )
{
send_to_char( "#GSigning off of Wiznet.#n\n\r", ch );
REMOVE_BIT( ch->wiznet, WIZ_ON );
return;
}
flag = wiznet_lookup( argument );
if( flag == -1 || get_trust( ch ) < wiznet_table[flag].level )
{
send_to_char( "#wNo such option.#n\n\r", ch );
return;
}
if( IS_SET( ch->wiznet, wiznet_table[flag].flag ) )
{
xprintf( buf, "#BYou will no longer see %s on wiznet.#n\n\r", wiznet_table[flag].name );
send_to_char( buf, ch );
REMOVE_BIT( ch->wiznet, wiznet_table[flag].flag );
return;
}
else
{
xprintf( buf, "#BYou will now see %s on wiznet.#n\n\r", wiznet_table[flag].name );
send_to_char( buf, ch );
SET_BIT( ch->wiznet, wiznet_table[flag].flag );
return;
}
}
void wiznet( char *string, CHAR_DATA * ch, OBJ_DATA * obj, long flag, long flag_skip, int min_level )
{
char buf[MAX_STRING_LENGTH];
DESCRIPTOR_DATA *d;
xprintf( buf, "#W%s#n", string );
for( d = descriptor_list; d != NULL; d = d->next )
{
if(!d->character) return;
if( d->connected == CON_PLAYING && ( IS_HERO( d->character ) ) && IS_SET( d->character->wiznet, WIZ_ON )
&& ( !flag || IS_SET( d->character->wiznet, flag ) ) && ( !flag_skip
|| !IS_SET( d->character->wiznet, flag_skip ) )
&& get_trust( d->character ) >= min_level && d->character != ch )
{
if( IS_SET( d->character->wiznet, WIZ_PREFIX ) )
send_to_char( "#Y-->#n ", d->character );
act( buf, d->character, obj, ch, TO_CHAR );
}
}
return;
}
void wiznet_printf( CHAR_DATA * ch, OBJ_DATA * obj, long flag, long flag_skip, int min_level, char *format, ... )
{
va_list ap;
char buf[MSL], buf2[MSL], Newtime[30];
char *strtime = ( char * )ctime( ¤t_time );
DESCRIPTOR_DATA *d;
int pos = 0, i = 1;
do
{
if( i > 11 )
buf[pos++] = *strtime;
}
while( *strtime++ && i++ && pos < 8 );
buf[pos] = '\0';
mudstrlcpy( Newtime, buf, 30 );
xprintf( buf, "[WiZNET] %s: ", Newtime );
va_start( ap, format );
if( !descriptor_list )
return;
for( d = descriptor_list; d != NULL; d = d->next )
{
char immnetbuffer[MSL];
if( !d->character )
continue;
if( d->connected == CON_PLAYING && IS_IMMORTAL( d->character ) && IS_SET( d->character->wiznet, WIZ_ON )
&& ( !flag || IS_SET( d->character->wiznet, flag ) ) && ( !flag_skip
|| !IS_SET( d->character->wiznet, flag_skip ) )
&& get_trust( d->character ) >= min_level && d->character != ch )
{
vsnprintf( buf2, sizeof( buf2 ), format, ap );
mudstrlcat( buf, buf2, MSL );
xprintf( immnetbuffer, "%s", buf );
act( immnetbuffer, d->character, obj, ch, TO_CHAR );
}
}
va_end( ap );
return;
}
/* returns a flag for wiznet */
long wiznet_lookup( const char *name )
{
int flag;
for( flag = 0; wiznet_table[flag].name != NULL; flag++ )
{
if( LOWER( name[0] ) == LOWER( wiznet_table[flag].name[0] ) && !str_prefix( name, wiznet_table[flag].name ) )
return flag;
}
return -1;
}
void pager_printf( CHAR_DATA * ch, char *fmt, ... )
{
char buf[MSL * 2];
va_list args;
va_start( args, fmt );
vsnprintf( buf, MAX_STRING_LENGTH * 2, fmt, args );
va_end( args );
pager_to_char( buf, ch );
}
void load_arti()
{
char buf[MSL];
//Right now, this will just load an arti randomly to the mud
//But if you want you can make it load by the person who gets the last mkill or whatever
//Zarius
randomize_object(number_range(33960, 33976));
xprintf_2(buf, "#7The Gods smile down and drop an #0Artifact#n into the world!\n\r" );
do_info( NULL, buf );
}