dbna/clans/
dbna/councils/
dbna/deity/
dbna/gods/
dbna/houses/
dbna/space/
/****************************************************************************
 *                   ^     +----- |  / ^     ^ |     | +-\                  *
 *                  / \    |      | /  |\   /| |     | |  \                 *
 *                 /   \   +---   |<   | \ / | |     | |  |                 *
 *                /-----\  |      | \  |  v  | |     | |  /                 *
 *               /       \ |      |  \ |     | +-----+ +-/                  *
 ****************************************************************************
 * AFKMud Copyright 1997-2002 Alsherok. Contributors: Samson, Dwip, Whir,   *
 * Cyberfox, Karangi, Rathian, Cam, Raine, and Tarl.                        *
 *                                                                          *
 * Original SMAUG 1.4a written by Thoric (Derek Snider) with Altrag,        *
 * Blodkai, Haus, Narn, Scryn, Swordbearer, Tricops, Gorog, Rennard,        *
 * Grishnakh, Fireblade, and Nivek.                                         *
 *                                                                          *
 * Original MERC 2.1 code by Hatchet, Furey, and Kahn.                      *
 *                                                                          *
 * Original DikuMUD code by: Hans Staerfeldt, Katja Nyboe, Tom Madsen,      *
 * Michael Seifert, and Sebastian Hammer.                                   *
 ****************************************************************************
 *                        Finger and Wizinfo Module                         *
 ****************************************************************************/

/******************************************************
        Additions and changes by Edge of Acedia
              Rewritten do_finger to better
             handle info of offline players.
           E-mail: nevesfirestar2002@yahoo.com
 ******************************************************/

#include <ctype.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include "mud.h"

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !str_cmp( word, literal ) )	\
				{					\
				      field = value;			\
				      fMatch = TRUE;			\
				      break;				\
				}

/* Begin wizinfo stuff - Samson 6-6-99 */

bool check_parse_name args( ( char *name, bool newchar ) );

WIZINFO_DATA *first_wizinfo;
WIZINFO_DATA *last_wizinfo;

/* Construct wizinfo list from god dir info - Samson 6-6-99 */
void add_to_wizinfo( char *name, WIZINFO_DATA * wiz )
{
  WIZINFO_DATA *wiz_prev;

  wiz->name = str_dup( name );
  if( !wiz->email )
    wiz->email = str_dup( "Not Set" );

  for( wiz_prev = first_wizinfo; wiz_prev; wiz_prev = wiz_prev->next )
    if( strcasecmp( wiz_prev->name, name ) >= 0 )
      break;

  if( !wiz_prev )
    LINK( wiz, first_wizinfo, last_wizinfo, next, prev );
  else
    INSERT( wiz, wiz_prev, first_wizinfo, next, prev );

  return;
}

void clear_wizinfo( bool bootup )
{
  WIZINFO_DATA *wiz, *next;

  if( !bootup )
  {
    for( wiz = first_wizinfo; wiz; wiz = next )
    {
      next = wiz->next;
      UNLINK( wiz, first_wizinfo, last_wizinfo, next, prev );
      DISPOSE( wiz->name );
      DISPOSE( wiz->email );
      DISPOSE( wiz );
    }
  }

  first_wizinfo = NULL;
  last_wizinfo = NULL;

  return;
}

void fread_info( WIZINFO_DATA * wiz, FILE * fp )
{
  char *word;
  bool fMatch;

  for( ;; )
  {
    word = feof( fp ) ? "End" : fread_word( fp );
    fMatch = FALSE;

    switch ( UPPER( word[0] ) )
    {
      case '*':
        fMatch = TRUE;
        fread_to_eol( fp );
        break;

      case 'E':
        KEY( "Email", wiz->email, fread_string_nohash( fp ) );
        if( !str_cmp( word, "End" ) )
          return;
        break;

      case 'I':
        KEY( "ICQ", wiz->icq, fread_number( fp ) );
        break;

      case 'L':
        KEY( "Level", wiz->level, fread_number( fp ) );
        break;
    }

    if( !fMatch )
      fread_to_eol( fp );
  }
}

void build_wizinfo( bool bootup )
{
  DIR *dp;
  struct dirent *dentry;
  FILE *fp;
  WIZINFO_DATA *wiz;
  char buf[MAX_STRING_LENGTH];

  clear_wizinfo( bootup );  /* Clear out the table before rebuilding a new one */

  dp = opendir( GOD_DIR );

  dentry = readdir( dp );

  while( dentry )
  {
    /*
     * Added by Tarl 3 Dec 02 because we are now using CVS 
     */
    if( !str_cmp( dentry->d_name, "CVS" ) )
    {
      dentry = readdir( dp );
      continue;
    }
    if( dentry->d_name[0] != '.' )
    {
      sprintf( buf, "%s%s", GOD_DIR, dentry->d_name );
      fp = fopen( buf, "r" );
      if( fp )
      {
        CREATE( wiz, WIZINFO_DATA, 1 );
        fread_info( wiz, fp );
        add_to_wizinfo( dentry->d_name, wiz );
        FCLOSE( fp );
      }
    }
    dentry = readdir( dp );
  }
  closedir( dp );
  return;
}

/*
 * Wizinfo information.
 * Added by Samson on 6-6-99
 */
void do_wizinfo( CHAR_DATA * ch, char *argument )
{
  WIZINFO_DATA *wiz;
  char buf[MAX_STRING_LENGTH];

  send_to_pager( "Contact Information for the Immortals:\n\r\n\r", ch );
  send_to_pager( "Name         Email Address                     ICQ#\n\r", ch );
  send_to_pager( "------------+---------------------------------+----------\n\r", ch );

  for( wiz = first_wizinfo; wiz; wiz = wiz->next )
  {
    if( !str_cmp( wiz->name, "normed" ) )
      continue;
    sprintf( buf, "%-12s %-33s %10d", wiz->name, wiz->email, wiz->icq );
    strcat( buf, "\n\r" );
    send_to_pager( buf, ch );
  }
  return;
}

/* End wizinfo stuff - Samson 6-6-99 */

/* Finger snippet courtesy of unknown author. Installed by Samson 4-6-98 */
/* File read/write code redone using standard Smaug I/O routines - Samson 9-12-98 */
/* Data gathering now done via the pfiles, eliminated separate finger files - Samson 12-21-98 */
/* Improvements for offline players by Edge of Acedia 8-26-03 */
/* Further refined by Samson on 8-26-03 */

//Added extra Immortal info to finger so whois is now invalid -Karn
//Added clan support -Karn 12.13.05
void do_finger( CHAR_DATA * ch, char *argument )
{
  CHAR_DATA *victim = NULL;
  CMDTYPE *command;
  ROOM_INDEX_DATA *temproom, *original = NULL;
  int level = LEVEL_IMMORTAL;
  char buf[MAX_STRING_LENGTH], fingload[MAX_INPUT_LENGTH];
  struct stat fst;
  char *laston = NULL;
  bool loaded = FALSE, skip = FALSE;
  char buf2[MAX_STRING_LENGTH];

  if( IS_NPC( ch ) )
  {
    send_to_char( "Mobs can't use the finger command.\n\r", ch );
    return;
  }

  if( !argument || argument[0] == '\0' )
  {
    send_to_char( "Finger whom?\n\r", ch );
    return;
  }

  sprintf( buf, "0.%s", argument );

  /*
   * If player is online, check for fingerability (yeah, I coined that one)  -Edge 
   */
  if( ( victim = get_char_world( ch, buf ) ) != NULL )
  {
    if( IS_SET( victim->pcdata->flags, PCFLAG_PRIVACY ) && !IS_IMMORTAL( ch ) )
    {
      ch_printf( ch, "%s has privacy enabled.\n\r", victim->name );
      return;
    }

    if( IS_IMMORTAL( victim ) && !IS_IMMORTAL( ch ) )
    {
      send_to_char( "You cannot finger an immortal.\n\r", ch );
      return;
    }
  }

  /*
   * Check for offline players - Edge 
   */
  else
  {
    DESCRIPTOR_DATA *d;

    sprintf( fingload, "%s%c/%s", PLAYER_DIR, tolower( argument[0] ), capitalize( argument ) );
    /*
     * Bug fix here provided by Senir to stop /dev/null crash 
     */
    if( stat( fingload, &fst ) == -1 || !check_parse_name( capitalize( argument ), FALSE )
        || !str_cmp( argument, "normed" ) )
    {
      ch_printf( ch, "&YNo such player named '%s'.\n\r", argument );
      return;
    }

    /*
     * laston = ctime( &fst.st_mtime );
     */
    temproom = get_room_index( ROOM_VNUM_LIMBO );
    if( !temproom )
    {
      bug( "%s", "do_finger: Limbo room is not available!" );
      send_to_char( "Fatal error, report to the immortals.\n\r", ch );
      return;
    }

    CREATE( d, DESCRIPTOR_DATA, 1 );
    d->next = NULL;
    d->prev = NULL;
    d->connected = CON_GET_NAME;
    d->outsize = 2000;
    CREATE( d->outbuf, char, d->outsize );
    argument[0] = UPPER( argument[0] );

    loaded = load_char_obj( d, argument, FALSE ); /* Remove second FALSE if compiler complains */
    LINK( d->character, first_char, last_char, next, prev );
    original = d->character->in_room;
    char_to_room( d->character, temproom );
    victim = d->character;  /* Hopefully this will work, if not, we're SOL */
    d->character->desc = NULL;
    d->character = NULL;
    DISPOSE( d->outbuf );
    DISPOSE( d );

    /*
     * Link dead check?  Was crashing on "IP Info" line below
     * * hopefully this will fix it. -Goku 10.11.03 
     */
    if( !victim->desc )
      loaded = FALSE;

    if( IS_SET( victim->pcdata->flags, PCFLAG_PRIVACY ) && !IS_IMMORTAL( ch ) )
    {
      ch_printf( ch, "%s has privacy enabled.\n\r", victim->name );
      skip = TRUE;
    }

    if( IS_IMMORTAL( victim ) && !IS_IMMORTAL( ch ) )
    {
      ch_printf( ch, "%s has privacy enabled.\n\r", victim->name );
      skip = TRUE;
    }
    loaded = TRUE;
  }

  if( !skip )
  {
    send_to_char( "&w          Finger Info\n\r", ch );
    send_to_char( "          -----------\n\r", ch );
    ch_printf( ch, "&wName    : &G%-20s &wMUD Age: &G%d\n\r", victim->name, get_newage( victim ) );
    ch_printf( ch, "&wRank    : &G%-20s &wRace   : &G%s\n\r", get_rank( victim ), capitalize( get_race( victim ) ) );
    ch_printf( ch, "&wSex     : &G%-20s &wAuth'd : &G%s\n\r",
               victim->sex == SEX_MALE ? "Male" : victim->sex == SEX_FEMALE ? "Female" : "Neutral", 
               victim->pcdata->authed_by == NULL ? "Yes" : "No" );
    ch_printf( ch, "&wTitle   : &G%s\n\r", victim->pcdata->title );
    if( victim->pcdata->clan != NULL )
      ch_printf( ch, "&wClan    : &G%s\n\r", victim->pcdata->clan->name );
    ch_printf( ch, "&wHomepage: &G%s\n\r", victim->pcdata->homepage != NULL ? victim->pcdata->homepage : "Not specified" );
    ch_printf( ch, "&wEmail   : &G%s\n\r", victim->pcdata->email != NULL ? victim->pcdata->email : "Not specified" );
    ch_printf( ch, "&wICQ#    : &G%d\n\r", victim->pcdata->icq );
    if( loaded /*&& victim->level < 50*/ )
      ch_printf( ch, "&wLast on : &G%s\n\r", ctime( &victim->pcdata->lastlogon ) );
    else
      ch_printf( ch, "&wLast on : &GCurrently Online\n\n\r", laston );
    if( IS_IMMORTAL( ch ) )
    {
      send_to_char( "&wImmortal Information\n\r", ch );
      send_to_char( "--------------------\n\r", ch );
      pager_printf_color( ch, "&wPlayer Level  : &G%d\n\r", victim->level );
      ch_printf( ch, "&wTime played   : &G%ld hours\n\r", ( long int )GET_TIME_PLAYED( victim ) );
      ch_printf( ch, "&wAuthorized by : &G%s\n\r",
                 victim->pcdata->authed_by ? victim->pcdata->authed_by : ( sysdata.
                                                                           WAIT_FOR_AUTH ? "Not Authed" : "The Code" ) );
      ch_printf( ch, "&wRP Points     : &G%d/%d\n\r", victim->pcdata->quest_curr, victim->pcdata->quest_accum );
      ch_printf( ch, "&wPrivacy Status: &G%s&D\n\r",
                 IS_SET( victim->pcdata->flags, PCFLAG_PRIVACY ) ? "Enabled" : "Disabled" );
      if( is_android( victim ) || is_superandroid( victim ) )
        pager_printf( ch, "Base Techlevel: &G%s&D\n\r", num_punct_ld( victim->exp ) );
      else
        pager_printf( ch, "Base Powerlevl: &G%s&D\n\r", num_punct_ld( victim->exp ) );
      if( ch->level >= 55 )
      {
        if( victim->desc && victim->desc->host[0] != '\0' ) //Online IP Check - Karn 5.21.05
        {
          sprintf( buf2, "Ip Address    : &G%s&Y ", victim->desc->host );
          if( get_trust( ch ) >= LEVEL_GOD )
            strcat( buf2, victim->desc->user );
          strcat( buf2, "&D\n\r" );
          send_to_pager( buf2, ch );
        }
        if( !victim->desc ) //Offline IP Check - Karn & Geh 5.21.05
        {
          sprintf( buf2, "Ip Address    : &G%s&Y (Offline)", victim->pcdata->lasthost );
          strcat( buf2, "&D\n\r" );
          send_to_pager( buf2, ch );
        }
      }
      if( IS_SET( victim->fusionflags, FUSION_STASIS ) )
        pager_printf( ch, "&R%s is PWNT!!!&D\n\r", victim->name );
      else
        pager_printf( ch, "&G%s is Safe.&D\n\r", victim->name );
      pager_printf( ch, "%s is %shelled at the moment.\n\r",
                    victim->sex == SEX_MALE ? "He" :
                    victim->sex == SEX_FEMALE ? "She" : "It", ( victim->pcdata->release_date == 0 ) ? "not " : "" );
      if( victim->pcdata->release_date != 0 )
        pager_printf( ch, "%s was helled by %s, and will be released on %24.24s.\n\r",
                      victim->sex == SEX_MALE ? "He" :
                      victim->sex == SEX_FEMALE ? "She" : "It",
                      victim->pcdata->helled_by, ctime( &victim->pcdata->release_date ) );

      if( victim->pcdata->silence != 0 )
      {
        pager_printf( ch, "%s was silenced by %s for %d minutes.\n\r",
                      victim->sex == SEX_MALE ? "He" :
                      victim->sex == SEX_FEMALE ? "She" : "It", victim->pcdata->silencedby, victim->pcdata->silence );
      }

      if( xIS_SET( victim->act, PLR_SILENCE ) || xIS_SET( victim->act, PLR_NO_EMOTE )
          || xIS_SET( victim->act, PLR_NO_TELL ) || xIS_SET( victim->act, PLR_THIEF ) || xIS_SET( victim->act, PLR_KILLER ) )
      {
        sprintf( buf2, "This player has the following flags set:" );
        if( xIS_SET( victim->act, PLR_SILENCE ) )
          strcat( buf2, " silence" );
        if( xIS_SET( victim->act, PLR_NO_EMOTE ) )
          strcat( buf2, " noemote" );
        if( xIS_SET( victim->act, PLR_NO_TELL ) )
          strcat( buf2, " notell" );
        if( xIS_SET( victim->act, PLR_THIEF ) )
          strcat( buf2, " thief" );
        if( xIS_SET( victim->act, PLR_KILLER ) )
          strcat( buf2, " killer" );
        strcat( buf2, ".\n\r" );
        send_to_pager( buf2, ch );
      }
      if( victim->level < ch->level )
      {
        /*
         * Added by Tarl 19 Dec 02 to remove Huh? when ch not high enough to view comments. 
         */
        command = find_command( "comment" );
        if( !command )
          level = LEVEL_IMMORTAL;
        else
          level = command->level;
        if( ch->level >= command->level )
        {
          sprintf( buf, "comment list %s", victim->name );
          interpret( ch, buf );
        }
        pager_printf( ch, "\n\r" );
      }
    }
    pager_printf_color( ch, "&wBio:\n\r&G%s\n\r", victim->pcdata->bio ? victim->pcdata->bio : "Not created" );
    pager_printf_color( ch, "\n\r&wDescription:\n\r&G%s\n\r", victim->description ? victim->description : "Not created" );
  }

  if( loaded )
  {
    int x, y;

    char_from_room( victim );
    char_to_room( victim, original );

    quitting_char = victim;
    /*
     * save_char_obj( victim );
     */

    if( sysdata.save_pets && victim->pcdata->pet )
      extract_char( victim->pcdata->pet, TRUE );

    saving_char = NULL;

    /*
     * After extract_char the ch is no longer valid!
     */
    extract_char( victim, TRUE );
    for( x = 0; x < MAX_WEAR; x++ )
      for( y = 0; y < MAX_LAYERS; y++ )
        save_equipment[x][y] = NULL;
  }
  return;
}

/* Added a clone of homepage to let players input their email addy - Samson 4-18-98 */
void do_email( CHAR_DATA * ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];

  if( IS_NPC( ch ) )
    return;

  if( argument[0] == '\0' )
  {
    if( !ch->pcdata->email )
      ch->pcdata->email = str_dup( "" );
    ch_printf( ch, "Your email address is: %s\n\r", show_tilde( ch->pcdata->email ) );
    return;
  }

  if( !str_cmp( argument, "clear" ) )
  {
    if( ch->pcdata->email )
      DISPOSE( ch->pcdata->email );
    ch->pcdata->email = str_dup( "" );

    if( IS_IMMORTAL( ch ) );
    {
      save_char_obj( ch );
      build_wizinfo( FALSE );
    }

    send_to_char( "Email address cleared.\n\r", ch );
    return;
  }

  strcpy( buf, argument );

  if( strlen( buf ) > 70 )
    buf[70] = '\0';

  hide_tilde( buf );
  if( ch->pcdata->email )
    DISPOSE( ch->pcdata->email );
  ch->pcdata->email = str_dup( buf );
  if( IS_IMMORTAL( ch ) );
  {
    save_char_obj( ch );
    build_wizinfo( FALSE );
  }
  send_to_char( "Email address set.\n\r", ch );
}

void do_icq_number( CHAR_DATA * ch, char *argument )
{
  int icq;

  if( IS_NPC( ch ) )
    return;

  if( argument[0] == '\0' )
  {
    if( !ch->pcdata->icq )
      ch->pcdata->icq = 0;
    ch_printf( ch, "Your ICQ# is: %d\n\r", ch->pcdata->icq );
    return;
  }

  if( !str_cmp( argument, "clear" ) )
  {
    ch->pcdata->icq = 0;

    if( IS_IMMORTAL( ch ) );
    {
      save_char_obj( ch );
      build_wizinfo( FALSE );
    }

    send_to_char( "ICQ# cleared.\n\r", ch );
    return;
  }

  if( !is_number( argument ) )
  {
    send_to_char( "You must enter numeric data.\n\r", ch );
    return;
  }

  icq = atoi( argument );

  if( icq < 1 )
  {
    send_to_char( "Valid range is greater than 0.\n\r", ch );
    return;
  }

  ch->pcdata->icq = icq;

  if( IS_IMMORTAL( ch ) );
  {
    save_char_obj( ch );
    build_wizinfo( FALSE );
  }

  send_to_char( "ICQ# set.\n\r", ch );
  return;
}

void do_homepage( CHAR_DATA * ch, char *argument )
{
  char buf[MAX_STRING_LENGTH];

  if( IS_NPC( ch ) )
    return;

  if( !argument || argument[0] == '\0' )
  {
    if( !ch->pcdata->homepage )
      ch->pcdata->homepage = str_dup( "" );
    ch_printf( ch, "Your homepage is: %s\n\r", show_tilde( ch->pcdata->homepage ) );
    return;
  }

  if( !str_cmp( argument, "clear" ) )
  {
    if( ch->pcdata->homepage )
      DISPOSE( ch->pcdata->homepage );
    ch->pcdata->homepage = str_dup( "" );
    send_to_char( "Homepage cleared.\n\r", ch );
    return;
  }

  if( strstr( argument, "://" ) )
    strcpy( buf, argument );
  else
    sprintf( buf, "http://%s", argument );
  if( strlen( buf ) > 70 )
    buf[70] = '\0';

  hide_tilde( buf );
  if( ch->pcdata->homepage )
    DISPOSE( ch->pcdata->homepage );
  ch->pcdata->homepage = str_dup( buf );
  send_to_char( "Homepage set.\n\r", ch );
}

void do_privacy( CHAR_DATA * ch, char *argument )
{
  if( IS_NPC( ch ) )
  {
    send_to_char( "Mobs can't use the privacy toggle.\n\r", ch );
    return;
  }

  TOGGLE_BIT( ch->pcdata->flags, PCFLAG_PRIVACY );

  if( IS_SET( ch->pcdata->flags, PCFLAG_PRIVACY ) )
  {
    send_to_char( "Privacy flag enabled.\n\r", ch );
    return;
  }
  else
  {
    send_to_char( "Privacy flag disabled.\n\r", ch );
    return;
  }
}

/*
 * basicly a copy of do_finger but checks pfiles in the backup dir -Goku 09.29.04
 */
void do_backfinger( CHAR_DATA * ch, char *argument )
{
  CHAR_DATA *victim = NULL;
  CMDTYPE *command;
  ROOM_INDEX_DATA *temproom, *original = NULL;
  int level = LEVEL_IMMORTAL;
  char buf[MAX_STRING_LENGTH], fingload[MAX_INPUT_LENGTH];
  char *laston = NULL;
  struct stat fst;
  bool loaded = FALSE, skip = FALSE;
  DESCRIPTOR_DATA *d;

  if( IS_NPC( ch ) )
  {
    send_to_char( "Mobs can't use the finger command.\n\r", ch );
    return;
  }

  if( !argument || argument[0] == '\0' )
  {
    send_to_char( "Back finger whom?\n\r", ch );
    return;
  }

  sprintf( buf, "0.%s", argument );


  sprintf( fingload, "%s%c/%s", BACKUP_DIR, tolower( argument[0] ), capitalize( argument ) );
  /*
   * Bug fix here provided by Senir to stop /dev/null crash 
   */
  if( stat( fingload, &fst ) == -1 || !check_parse_name( capitalize( argument ), FALSE ) )
  {
    ch_printf( ch, "&YNo such player named '%s'.\n\r", argument );
    return;
  }

  /*
   * laston = ctime( &fst.st_mtime );
   */
  temproom = get_room_index( ROOM_VNUM_LIMBO );
  if( !temproom )
  {
    bug( "%s", "do_backfinger: Limbo room is not available!" );
    send_to_char( "Fatal error, report to the immortals.\n\r", ch );
    return;
  }

  CREATE( d, DESCRIPTOR_DATA, 1 );
  d->next = NULL;
  d->prev = NULL;
  d->connected = CON_GET_NAME;
  d->outsize = 2000;
  CREATE( d->outbuf, char, d->outsize );
  argument[0] = UPPER( argument[0] );

  loaded = load_char_obj( d, argument, FALSE ); /* Remove second FALSE if compiler complains */
  LINK( d->character, first_char, last_char, next, prev );
  original = d->character->in_room;
  char_to_room( d->character, temproom );
  victim = d->character;  /* Hopefully this will work, if not, we're SOL */
  d->character->desc = NULL;
  d->character = NULL;
  DISPOSE( d->outbuf );
  DISPOSE( d );

  /*
   * Link dead check?  Was crashing on "IP Info" line below
   * * hopefully this will fix it. -Goku 10.11.03 
   */
  if( !victim->desc )
    loaded = FALSE;

  if( IS_SET( victim->pcdata->flags, PCFLAG_PRIVACY ) && !IS_IMMORTAL( ch ) )
  {
    ch_printf( ch, "%s has privacy enabled.\n\r", victim->name );
    skip = TRUE;
  }

  if( IS_IMMORTAL( victim ) && !IS_IMMORTAL( ch ) )
  {
    send_to_char( "You cannot back finger an immortal.\n\r", ch );
    skip = TRUE;
  }
  loaded = TRUE;

  if( !skip )
  {
    send_to_char( "&w          Back Finger Info\n\r", ch );
    send_to_char( "          -----------\n\r", ch );
    ch_printf( ch, "&wName    : &G%-20s &wMUD Age: &G%d\n\r", victim->name, get_newage( victim ) );
    ch_printf( ch, "&wRank    : &G%-20s &wRace   : &G%s\n\r", get_rank( victim ), capitalize( get_race( victim ) ) );
    ch_printf( ch, "&wSex     : &G%-20s\n\r",
               victim->sex == SEX_MALE ? "Male" : victim->sex == SEX_FEMALE ? "Female" : "Neutral" );
    ch_printf( ch, "&wTitle   : &G%s\n\r", victim->pcdata->title );
    ch_printf( ch, "&wHomepage: &G%s\n\r", victim->pcdata->homepage != NULL ? victim->pcdata->homepage : "Not specified" );
    ch_printf( ch, "&wEmail   : &G%s\n\r", victim->pcdata->email != NULL ? victim->pcdata->email : "Not specified" );
    ch_printf( ch, "&wICQ#    : &G%d\n\r", victim->pcdata->icq );
    if( loaded )
      ch_printf( ch, "&wLast on : &G%s\n\r", ctime( &victim->pcdata->lastlogon ) );
    else
      ch_printf( ch, "&wLast on : &GCurrently Online\n\n\r", laston );
    if( IS_IMMORTAL( ch ) )
    {
      send_to_char( "&wImmortal Information\n\r", ch );
      send_to_char( "--------------------\n\r", ch );
//     ch_printf( ch, "&wIP Info       : &G%s\n\r", loaded ? "Unknown" : victim->desc->host );
      ch_printf( ch, "&wTime played   : &G%ld hours\n\r", ( long int )GET_TIME_PLAYED( victim ) );
      ch_printf( ch, "&wAuthorized by : &G%s\n\r",
                 victim->pcdata->authed_by ? victim->pcdata->authed_by : ( sysdata.
                                                                           WAIT_FOR_AUTH ? "Not Authed" : "The Code" ) );
      ch_printf( ch, "&wPrivacy Status: &G%s\n\r",
                 IS_SET( victim->pcdata->flags, PCFLAG_PRIVACY ) ? "Enabled" : "Disabled" );
      if( victim->level < ch->level )
      {
        /*
         * Added by Tarl 19 Dec 02 to remove Huh? when ch not high enough to view comments. 
         */
        command = find_command( "comment" );
        if( !command )
          level = LEVEL_IMMORTAL;
        else
          level = command->level;
        if( ch->level >= command->level )
        {
          sprintf( buf, "comment list %s", victim->name );
          interpret( ch, buf );
        }
      }
    }
    pager_printf_color( ch, "&wBio:\n\r&G%s\n\r", victim->pcdata->bio ? victim->pcdata->bio : "Not created" );
    pager_printf_color( ch, "\n\r&wDescription:\n\r&G%s\n\r", victim->description ? victim->description : "Not created" );
  }

  if( loaded )
  {
    int x, y;

    char_from_room( victim );
    char_to_room( victim, original );

    quitting_char = victim;
    /*
     * save_char_obj( victim );
     */

    if( sysdata.save_pets && victim->pcdata->pet )
      extract_char( victim->pcdata->pet, TRUE );

    saving_char = NULL;

    /*
     * After extract_char the ch is no longer valid!
     */
    extract_char( victim, TRUE );
    for( x = 0; x < MAX_WEAR; x++ )
      for( y = 0; y < MAX_LAYERS; y++ )
        save_equipment[x][y] = NULL;
  }
  return;
}

void fread_pfile2( CHAR_DATA * ch, FILE * fp )
{
  char *word;
  char *name = NULL;
  sh_int level = 0;
  sh_int file_ver = 0;
  bool fMatch;
  long double exp = 0;
  char *description = NULL;
  char *bio = NULL;

  for( ;; )
  {
    word = feof( fp ) ? "End" : fread_word( fp );
    fMatch = FALSE;

/*        if (StopFP)
        {
                bug("Bad Pfile detected.  Stoping proccessing of bad Pfile.");
                StopFP = FALSE;
                return;
        }
*/ switch ( UPPER( word[0] ) )
    {

      case '*':
        fMatch = TRUE;
        fread_to_eol( fp );
        break;

      case 'B':
        KEY( "Bio", bio, fread_string( fp ) );
        break;
      case 'D':
        KEY( "Description", description, fread_string( fp ) );
        break;

      case 'E':
        KEY( "Exp", exp, fread_number_ld( fp ) );
        if( !strcmp( word, "End" ) )
          goto timecheck;
        break;

      case 'L':
        KEY( "Level", level, fread_number( fp ) );
        break;

      case 'N':
        KEY( "Name", name, fread_string( fp ) );
        break;

      case 'V':
        KEY( "Version", file_ver, fread_number( fp ) );
        break;
    }

    if( !fMatch )
      fread_to_eol( fp );
  }
timecheck:
  {
    send_to_char( "Name: ", ch );
    send_to_char( name, ch );
    send_to_char( "\n\rBio:\n\r", ch );
    send_to_char( bio, ch );
    send_to_char( "\n\r\n\rDesc:\n\r", ch );
    send_to_char( description, ch );
  }
}

void do_finger2( CHAR_DATA * ch, char *argument )
{
  char buf[MAX_STRING_LENGTH], fingload[MAX_INPUT_LENGTH];
  FILE *fp;

  if( IS_NPC( ch ) )
  {
    send_to_char( "Mobs can't use the finger command.\n\r", ch );
    return;
  }

  if( !argument || argument[0] == '\0' )
  {
    send_to_char( "Finger whom?\n\r", ch );
    return;
  }

  sprintf( buf, "0.%s", argument );

  /*
   * Check for offline players - Edge 
   */
//   else
  {
    sprintf( fingload, "%s%c/%s", BACKUP_DIR, tolower( argument[0] ), capitalize( argument ) );
    /*
     * Bug fix here provided by Senir to stop /dev/null crash 
     */

    if( ( fp = fopen( fingload, "r" ) ) == NULL )
    {
      send_to_char( "Error.\n\r", ch );
      return;
    }

    for( ;; )
    {
      char letter;
      char *word;
/*            if (StopFP)   
            {
                bug("Bad Pfile detected.  Stoping proccessing of bad Pfile.");
                StopFP = FALSE;
                return;
            }
*/ letter = fread_letter( fp );

      if( letter != '#' )
        continue;

      word = fread_word( fp );

      if( !str_cmp( word, "End" ) )
        break;

      if( !str_cmp( word, "PLAYER" ) )
        fread_pfile2( ch, fp );
      else if( !str_cmp( word, "END" ) )  /* Done         */
        break;
    }
    fclose( fp );

  }
  return;
}