dbna/clans/
dbna/councils/
dbna/deity/
dbna/gods/
dbna/houses/
dbna/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"
#ifdef USE_IMC
#include "imc.h"
#include "icec.h"
#endif

// 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
   * and we did -Karn 
   */
  /*
   * Check for Mystic 
   */
  for( vch = first_char; vch; vch = vch->next )
  {
    if( vch->tmystic > 0 )
    {
      ch_printf( ch, "&R%s is teaching mystic.\n\r", vch->name );
      ch_printf( ch, "&RHotboot Failed.\n\r" );
      return FALSE;
    }
  }

  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], buf4[100], buf5[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(  );

#ifdef USE_IMC
  log_string( "Initiating IMC2 shutdown...." );
  imc_shutdown(  ); /* shut down IMC */
  log_string( "IMC2 shutdown completed." );
#endif


  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 );
#ifdef I3
      I3_close_char( d );
#endif
      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 );

#ifdef I3
  log_string( "Initiating Intermud-3 shutdown...." );
  I3_shutdown( 0 );
  log_string( "Intermud-3 shutdown completed." );
#endif

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

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

//    execl( EXE_FILE, "dbsaga", buf, "hotboot",  buf2, buf3, buf4, buf5, (char *)NULL );
  execl( EXE_FILE, "dbsaga", buf, "hotboot", buf2, ( 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;
}