dbsc/clans/
dbsc/deity/
dbsc/houses/
dbsc/player/a/
dbsc/space/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *			         Hotboot support code                             *
 ****************************************************************************/

#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "mud.h"

// bool write_to_descriptor( DESCRIPTOR_DATA *d, char *txt, int length );
bool write_to_descriptor( int desc, char *txt, int length );
bool write_to_descriptor_old( int desc, char *txt, int length );

#ifdef MCCP
#define TELOPT_COMPRESS 85
#define TELOPT_COMPRESS2 86
bool    compressStart   args( ( DESCRIPTOR_DATA *d, unsigned char telopt ) );
bool    compressEnd     args( ( DESCRIPTOR_DATA *d ) );
const   char    compress2_on_str_2 [] = { '\xFF', '\xFB', TELOPT_COMPRESS2, '\0' };
#endif

extern int		    control;		/* Controlling descriptor	*/

/* Used by hotboot code */
void save_areas( void )
{
   AREA_DATA   *tarea;
   char         filename[256];

   for( tarea = first_build; tarea; tarea = tarea->next )
   {
      if( !IS_SET( tarea->status, AREA_LOADED ) )
         continue;
      sprintf( filename, "%s%s", BUILD_DIR, tarea->filename );
      fold_area( tarea, filename, FALSE );
   }
   return;
}
/*
 * Check to see if people are busy doing stuff that they wouldn't
 * want a hotboot to off during it  -Goku
 */
bool isSafeToHotboot(CHAR_DATA *ch)
{
	ROOM_INDEX_DATA *tRoom;
	CHAR_DATA *vch;
	bool found = FALSE;
	bool extrafound = FALSE;
	char buf [MAX_STRING_LENGTH];

	/* Check for people in the HBTC */
	tRoom = get_room_index(ROOM_HBTC);
	/*
	if (tRoom->first_person)
	{
		send_to_char( "The HBTC is in use, hotboot aborted.\n\r", ch );
		return FALSE;
	}
	*/

	/* Fixed so that hotboot will still occur if the only person(s)
	 * in the HBTC are mobs or immortals. - Karma
	 */
	for( vch = tRoom->first_person; vch; vch = vch->next_in_room )
	{
	  if( IS_NPC(vch) )
	    continue;
	  if( !IS_NPC(vch) && !IS_IMMORTAL(vch) )
	  {
	    if( !found )
	    {
		sprintf(buf,"%s",vch->name);
		found = TRUE;
	    }
	    else
	    {
		strcat(buf," and ");
		strcat(buf,vch->name);
		extrafound = TRUE;
	    }
	    
	    //send_to_char( "The HBTC is in use, hotboot aborted.\n\r", ch );
	  }
	}
	if( found )
	{
	  if( buf[0] == '\0' )
	    bug("Hotboot hbtc check: NULL buf",0);
	  if( extrafound )
	    ch_printf(ch,"%s are in the HBTC. Hotboot aborted.\n\r",buf);
	  else
	    ch_printf(ch,"%s is in the HBTC. Hotboot aborted.\n\r",buf);
	  return FALSE;
	}

	/* we could check for other stuff as well  -Goku */

	return TRUE;
}

/*  Warm reboot stuff, gotta make sure to thank Erwin for this :) */
void do_hotboot( CHAR_DATA *ch, char *argument )
{
    FILE *fp;
    DESCRIPTOR_DATA *d, *de_next;
    char buf [100], buf2[100], buf3[100];
	char arg [MAX_STRING_LENGTH];
    
    one_argument(argument, arg);
    
    /* typing "hotboot force" will force a hotboot */
    if (str_cmp(arg, "force"))
    	if (!isSafeToHotboot(ch))
    		return;

    sprintf( log_buf, "Hotboot initiated by %s.", ch->name );
    log_string( log_buf );

    fp = fopen( HOTBOOT_FILE, "w" );

    if( !fp )
    {
      send_to_char( "Hotboot file not writeable, aborted.\n\r", ch );
	sprintf( log_buf, "Could not write to hotboot file: %s. Hotboot aborted.", HOTBOOT_FILE );
	log_string( log_buf );
      perror( "do_copyover:fopen" );
      return;
    }

    /* Consider changing all loaded prototype areas here, if you use OLC */
    log_string( "Saving modified area files..." );
    save_areas();

    log_string( "Saving player files and connection states...." );
    if( ch && ch->desc )
        write_to_descriptor( ch->desc->descriptor, "\e[0m", 0 );
    sprintf( buf, "\n\rThe flow of time is halted momentarily as the world is reshaped!\n\r" );

    if ( auction->item )
    {
      sprintf(buf, "Sale of %s has been stopped by mud.\n\r",
          auction->item->short_descr);
      talk_auction(buf);
      obj_to_char(auction->item, auction->seller);
      auction->item = NULL;
      if ( auction->buyer && auction->buyer != auction->seller )
      {
        auction->buyer->gold += auction->bet;
        send_to_char("Your money has been returned.\n\r", auction->buyer);
      }
    }

    /* For each playing descriptor, save its state */
    for( d = first_descriptor; d ; d = de_next )
    {
        CHAR_DATA * och = CH(d);
        de_next = d->next; /* We delete from the list , so need to save this */
        if( !d->character || d->connected < CON_PLAYING ) /* drop those logging on */
        {
            write_to_descriptor( d->descriptor, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r", 0 );
            close_socket( d, FALSE ); /* throw'em out */
        }
        else
        {
            fprintf( fp, "%d %d %d %d %d %s %s %s\r",
                     d->descriptor,
#ifdef MCCP
                     (int)d->compressing,
#else
                     0,
#endif
                     och->in_room->vnum, d->port, d->idle, och->name, d->user, d->host );
            save_char_obj( och );
            write_to_descriptor( d->descriptor, buf, 0 );
#ifdef MCCP
            compressEnd( d );
#endif
        }
    }
    fprintf( fp, "-1 0 0 0 0 x x x\r" );
    FCLOSE( fp );

    log_string( "Executing hotboot...." );
    /* Close reserve and other always-open files and release other resources */
    FCLOSE( fpReserve );
    FCLOSE( fpLOG );

#ifdef IMC
   imc_hotboot();
#endif

    /* exec - descriptors are inherited */
    sprintf( buf,  "%d", port );
    sprintf( buf2, "%d", control );

#ifdef IMC
   if( this_imcmud )
      snprintf( buf3, 100, "%d", this_imcmud->desc );
   else
      strncpy( buf3, "-1", 100 );
#else
   strncpy( buf3, "-1", 100 );
#endif

    execl( EXE_FILE, "dbsaga", buf, "hotboot", buf2, buf3, (char *)NULL );
    /* Failed - sucessful exec will not return */
    perror( "do_hotboot: execl" );

    /* Here you might want to reopen fpReserve */
    /* Since I'm a neophyte type guy, I'll assume this is a good idea and cut and past from main()  */

    if( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
    {
        perror( NULL_FILE );
        exit( 1 );
    }
    if( ( fpLOG = fopen( NULL_FILE, "r" ) ) == NULL )
    {
        perror( NULL_FILE );
        exit( 1 );
    }
    log_string( "Hotboot execution failed!!" );
    send_to_char( "Hotboot FAILED!\n\r", ch );
}

/* Recover from a hotboot - load players */
void hotboot_recover()
{
    DESCRIPTOR_DATA *d = NULL;
    FILE *fp;
    char name[100];
    char host[MAX_STRING_LENGTH];
    char user[MAX_STRING_LENGTH];
    int desc, dcompress, room, dport, idle;
//    char *lock = NULL;
    bool fOld;

    fp = fopen( HOTBOOT_FILE, "r" );

    if (!fp) /* there are some descriptors open which will hang forever then ? */
    {
        perror( "hotboot_recover: fopen" );
        log_string( "Hotboot file not found. Exitting.\n\r" );
        exit( 1 );
    }

    unlink( HOTBOOT_FILE ); /* In case something crashes - doesn't prevent reading */
    for( ; ; )
    {
        d = NULL;

	// 4 %s is one too many.  03.29.05 --Saiyr
        fscanf( fp, "%d %d %d %d %d %s %s %s\r", // %s\r",
	    &desc,
	    &dcompress,
	    &room,
	    &dport,
	    &idle,
	    name,
	    user,
	    host );
//	    lock );

	if (desc == -1 || feof(fp) )
	{
		break;
	}
            
        /* Write something, and check if it goes error-free */
//        if( !dcompress && !write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
//        if( !dcompress)
//        {
//bug("desc:%d dcompress:%d - %d %d %d %s %s %s", desc,dcompress, room, dport, idle, name, user, host );
//        	if (!write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
//        {
//            close( desc ); /* nope */
//            continue;
//        }
//    	}
#ifdef MCCP
        if( !dcompress && !write_to_descriptor_old( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
#else
        if( !write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
#endif
        {
            close( desc ); /* nope */
            continue;
        }
        CREATE( d, DESCRIPTOR_DATA, 1 );

        d->next		= NULL;
        d->descriptor	= desc;
        d->connected	= CON_GET_NAME;
        d->outsize	= 2000;
        d->idle		= 0;
        d->lines		= 0;
        d->scrlen		= 24;
        d->newstate	= 0;
        d->prevcolor	= 0x07;
        d->ansi = TRUE;
		d->ifd		= -1;
		d->ipid		= -1;

        CREATE( d->outbuf, char, d->outsize );

        d->user = STRALLOC( user );
        d->host = STRALLOC( host );
        d->port = dport;
        d->idle = idle;
#ifdef MCCP
		/* Start MCCP back up for who ever had it enabled */
		if (dcompress)
			write_to_buffer( d, compress2_on_str_2, 0 );
//			compressStart(d, TELOPT_COMPRESS2);

#endif
        LINK( d, first_descriptor, last_descriptor, next, prev );
        d->connected = CON_COPYOVER_RECOVER; /* negative so close_socket will cut them off */

        /* Now, find the pfile */
        fOld = load_char_obj( d, name, FALSE );

       if( !fOld ) /* Player file not found?! */
        {
            write_to_descriptor( d->descriptor, "\n\rSomehow, your character was lost during hotboot. Contact the immortals ASAP.\n\r", 0 );
            close_socket( d, FALSE );
        }
        else /* ok! */
        {
           write_to_descriptor( d->descriptor, "\n\rTime resumes its normal flow.\n\r", 0 );
            d->character->in_room = get_room_index( room );
            if( !d->character->in_room )
                d->character->in_room = get_room_index( ROOM_VNUM_TEMPLE );

            /* Insert in the char_list */
            add_char( d->character );

            char_to_room( d->character, d->character->in_room );
	      act( AT_MAGIC, "A puff of ethereal smoke disipates around you!", d->character, NULL, NULL, TO_CHAR );
            act( AT_MAGIC, "$n appears in a puff of ethereal smoke!", d->character, NULL, NULL, TO_ROOM );
            d->connected = CON_PLAYING;
            if ( ++num_descriptors > sysdata.maxplayers )
	         sysdata.maxplayers = num_descriptors;
#ifdef I3
	      I3_char_login( d->character );
#endif
        }
    }
    FCLOSE( fp );
    log_string( "Hotboot recovery complete." );
    return;
}