RaM Fire Updated/
/*
 * RAM $Id: bug.c 26 2008-11-02 07:01:25Z ram $
 */

/***************************************************************************
 *  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.                                               *
 *                                                                         *
 *  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.                                                  *
 ***************************************************************************/

/***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
*       ROM has been brought to you by the ROM consortium                  *
*           Russ Taylor (rtaylor@hypercube.org)                            *
*           Gabrielle Taylor (gtaylor@hypercube.org)                       *
*           Brian Moore (zump@rom.org)                                     *
*       By using this code, you have agreed to follow the terms of the     *
*       ROM license, in the file Rom24/doc/rom.license                     *
***************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>

#include "merc.h"
#include "db.h"

/*
 * Reports a bug.
 */
void bug( const char *str, int param )
{
    event_logger( LOG_ERROR, NULL, NULL, NULL, 0, NULL, NULL, GOD, str, param );
}

/*
 * Writes a string to the log.
 */
void log_string( const char *str )
{
    event_logger( LOG_INFO, NULL, NULL, NULL, 0, NULL, NULL, GOD, str, 0 );
}

/*
 * These should NOT be longer than 8 characters
 */
static const char      *LogNames[] = {
    "INFO",
    "ERROR",
    "FATAL",
    "BOOT",
    "AUTH",
    "KILL",
    "BALANCE",
    "RESET"
};

/*
 * Things we want to have when logging events.....
 *
 * Type is the type of error, typically things like
 * LOG_INFO, LOG_ERROR, LOG_FATAL, LOG_BOOT, LOG_AUTH
 *
 * LogFile is the filename you want to log to, NULL means stderr
 *
 * File, Func, Line can all be provided by the compiler as
 * __FILE__, __PRETTY_FUNCTION__, and __LINE__
 *
 * ch is the character structure that caused the log,
 * victim is the target of the action, if any.
 *
 * Level is the minimum character level which will see the
 * bug if they're logged in.
 *
 * Str is, of course, the message, and it gets printed
 * using varargs, so you can have this be a printf type
 * set of macros.
 */
void event_logger( unsigned int Type, const char *LogFile,
                   const char *File, const char *Func, int Line,
                   struct char_data *ch, struct char_data *victim,
                   int Level, const char *Str, ... )
{
    va_list                 arg;
    char                    Result[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0";
    char                    Temp[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0";
    FILE                   *fp = NULL;
    struct timeval          right_now;
    struct tm              *now_part = NULL;
    struct descriptor_data *d = NULL;

    /*
     * Cat got your tongue? 
     */
    if ( !Str || !*Str )
        return;

    /*
     * Get the time we logged the error 
     */
    gettimeofday( &right_now, NULL );

    /*
     * Parse the varargs 
     */
    va_start( arg, Str );
    vsnprintf( Temp, MAX_STRING_LENGTH, Str, arg );
    va_end( arg );

    /*
     * Construct a message and send to everyone 
     * This should eventually have bits to disable certain
     * types of messages.
     */
    sprintf( Result, "LOG_%s> %s\r\n", LogNames[Type], Temp );

    for ( d = descriptor_list; d; d = d->next )
        if ( d->connected == CON_PLAYING && get_trust( d->character ) >= Level )
            switch ( Type )
            {
                default:
                    write_to_buffer( d, Result, 0 );
                    break;
                case LOG_BOOT:
                    break;
                case LOG_RESET:
                    if ( IS_SET( d->character->wiznet, WIZ_RESETS ) )
                        write_to_buffer( d, Result, 0 );
                    break;
                case LOG_KILL:
                    if ( IS_SET( d->character->wiznet, WIZ_DEATHS )
                         || IS_SET( d->character->wiznet, WIZ_MOBDEATHS ) )
                        write_to_buffer( d, Result, 0 );
                    break;
            }

    /*
     * Format the data for the logs now, not the whizzards 
     */
    now_part = localtime( ( const time_t * ) &( right_now.tv_sec ) );
    snprintf( Result, MAX_STRING_LENGTH, "<: %04d-%02d-%02d %02d:%02d:%02d.%03d : %-8.8s",
              now_part->tm_year + 1900, now_part->tm_mon + 1, now_part->tm_mday,
              now_part->tm_hour, now_part->tm_min, now_part->tm_sec,
              ( int ) ( right_now.tv_usec / 1000 ), LogNames[Type] );

    /*
     * If we're booting, we want the area file information 
     */
    if ( fpArea )
    {
        int                     iLine = 0;
        long                    iChar = 0;
        int                     c = 0;

        if ( fpArea == stdin )
        {
            iLine = 0;
        }
        else
        {
            iChar = ftell( fpArea );
            fseek( fpArea, 0, SEEK_SET );
            for ( iLine = 0; ( ftell( fpArea ) < iChar ) && !feof( fpArea ); iLine++ )
            {
                while ( ( c = fgetc( fpArea ) ) != '\n' )
                    if ( c == EOF )
                        break;
            }
            fseek( fpArea, iChar, SEEK_SET );
        }

        snprintf( Result + strlen( Result ), MAX_STRING_LENGTH - strlen( Result ),
                  " [ FILE: %s, LINE: %d ]", strArea, iLine );
    }

    /*
     * Now, hook us up with file/function/line from the bug macros 
     */
    if ( File || Func || Line )
    {
        strncat( Result, " (", MAX_STRING_LENGTH - strlen( Result ) - 1 );
        if ( File && *File )
        {
            strncat( Result, File, MAX_STRING_LENGTH - strlen( Result ) - 1 );
        }
        if ( Func && *Func )
            snprintf( Result + strlen( Result ), MAX_STRING_LENGTH - strlen( Result ),
                      ";%s", Func );
        if ( Line )
            snprintf( Result + strlen( Result ), MAX_STRING_LENGTH - strlen( Result ),
                      ",%d)", Line );
        else
            strncat( Result, ")", MAX_STRING_LENGTH - strlen( Result ) - 1 );
    }

    /*
     * And then let us know who did it, and where they were, and whom they were with 
     */
    if ( ch || victim )
    {
        if ( ch )
            snprintf( Result + strlen( Result ), MAX_STRING_LENGTH - strlen( Result ),
                      " ch \"%s\" [#%d]", NAME( ch ),
                      ch->in_room ? ch->in_room->vnum : -1 );
        if ( victim )
            snprintf( Result + strlen( Result ), MAX_STRING_LENGTH - strlen( Result ),
                      " victim \"%s\" [#%d]", NAME( victim ),
                      victim->in_room ? victim->in_room->vnum : -1 );
        strncat( Result, "\n", MAX_STRING_LENGTH - strlen( Result ) - 1 );
    }
    else
    {
        if ( File || Func || Line || fpArea )
            strncat( Result, "\n", MAX_STRING_LENGTH - strlen( Result ) - 1 );
    }

    /*
     * Finally, slap on the actual message 
     */
    strncat( Result, " : ", MAX_STRING_LENGTH - strlen( Result ) - 1 );
    strncat( Result, Temp, MAX_STRING_LENGTH - strlen( Result ) - 1 );

    /*
     * Shoot it to a file, if desired 
     */
    if ( LogFile && *LogFile )
    {
        if ( !( fp = fopen( LogFile, "a" ) ) )
        {
            char                   *e = strerror( errno );

            fprintf( stderr, "bug_logger: %s: %s\n", LogFile, e );
            if ( ch )
                ch_printf( ch, "Could not open the file!\r\n" );
        }
        else
        {
            fprintf( fp, "%s\n", Result );
            fclose( fp );
        }
    }
    else if ( stderr )
    {
        fprintf( stderr, "%s\n", Result );
        fflush( stderr );
    }
}