tfe-1.0/area/
tfe-1.0/files/
tfe-1.0/logs/
tfe-1.0/logs/immortal/
tfe-1.0/logs/mob/
tfe-1.0/logs/object/
tfe-1.0/logs/player/
tfe-1.0/logs/room/
tfe-1.0/notes/clans/
tfe-1.0/player/
tfe-1.0/prev/
tfe-1.0/prev/area/
tfe-1.0/prev/player/
tfe-1.0/prev/rooms/
tfe-1.0/rooms/
tfe-1.0/src-gc/
tfe-1.0/src-msvc/
tfe-1.0/src-unix/
tfe-1.0/www/
tfe-1.0/www/html/
#include "define.h"
#include "struct.h"


const char* noteboard_name [ MAX_NOTEBOARD ] = { "general", "immortal",
  "ideas",
  "bugs", "jobs", "announcements", "information", "stories", "changes",
  "wanted", "fixed", "code", "avatar", "clan" };


note_data**  note_list [ MAX_NOTEBOARD ];
int          max_note  [ MAX_NOTEBOARD ];


void         save_mail        ( pfile_data* );   
bool         can_read         ( char_data*, int, bool = FALSE );
bool         can_write        ( char_data*, int, bool = FALSE );
bool         can_remove       ( char_data*, note_data* );
note_data*   find_mail        ( char_data*, int );
void         note_summary     ( char_data* );
void         display_notes    ( player_data* );
void         display_mail     ( char_data* );
void         send_mail        ( char_data*, char, char* );    
void         save_noteboard   ( char*, note_data**, int );
void         load_noteboard   ( char*, note_data**&, int&, int );


inline int noteboard_level( int board )
{
  if( board == NOTE_IMMORTAL || board == NOTE_JOBS
    || board == NOTE_CHANGES )
    return LEVEL_APPRENTICE;

  return( board == NOTE_AVATAR ? LEVEL_AVATAR : 0 );
}


/*
 *   NOTE_DATA CLASS
 */


Note_Data :: Note_Data( )
{
  record_new( sizeof( note_data ), MEM_NOTE );

  next      = NULL;
  from      = empty_string;
  title     = empty_string;
  message   = empty_string;
  date      = 0;
  noteboard = 0;
};


Note_Data :: ~Note_Data( )
{
  record_delete( sizeof( note_data ), MEM_NOTE );

  free_string( title,   MEM_NOTE );
  free_string( message, MEM_NOTE );
  free_string( from,    MEM_NOTE );
};


void extract( char_data* ch, note_data* note )
{
  player_data*    victim;
  int          noteboard  = note->noteboard;
  int                  i;

  for( i = 0; i < player_list; i++ ) {
    victim = player_list[i];
    if( victim->note_edit == note ) {
      if( victim != ch )
        send( victim,
          "%s just deleted the note you were editing.\r\n", ch );
      victim->note_edit = NULL;
      }
    } 

  for( i = 0; i < max_note[noteboard]; i++ )
    if( note_list[noteboard][i] == note ) {
      remove( note_list[noteboard], max_note[noteboard], i );
      delete note;
      return;
      }

  bug( "Extract( note ): Non-existent note!?" );
}        


/*
 *   SUPPORT FUNCTIONS
 */


bool acceptable_title( char_data* ch, const char* title )
{ 
  if( strlen( title ) <= 40 ) 
    return TRUE;

  send( "The title of messages must be less than 40 characters.\r\n", ch );
  return FALSE;
}


void recent_notes( char_data* ch )
{
  char           tmp  [ TWO_LINES ];
  int           i, j;
  int         recent  = 0;
  clan_data*    clan;

  if( ( clan = ch->pcdata->pfile->clan ) != NULL ) {
    note_list[ NOTE_CLAN ] = clan->note_list;
    max_note[ NOTE_CLAN ]  = clan->max_note;
    }

  for( recent = i = 0; i < MAX_NOTEBOARD; i++ ) 
    if( can_read( ch, i ) ) 
      for( j = max_note[i]-1; j >= 0; j--, recent++ ) 
        if( note_list[i][j]->date < ch->pcdata->pfile->last_on )
          break;

  if( recent > 0 ) {
    sprintf( tmp, "%s note%s been posted since last login.",
      number_word( recent ), recent == 1 ? " has" : "s have" );
    *tmp = toupper( *tmp );
    send_centered( ch, tmp );
    }

  return;
}


bool can_remove( char_data* ch, note_data* note )
{
  title_data* title;

  if( !strcmp( ch->descr->name, note->from )
    || has_permission( ch, PERM_NOTEBOARD ) )
    return TRUE;

  if( note->noteboard == NOTE_BUGS && is_apprentice( ch ) )
    return TRUE;

  if( note->noteboard == NOTE_CLAN
    && ( title = get_title( ch->pcdata->pfile ) ) != NULL 
    && is_set( title->flags, TITLE_REMOVE_NOTES ) ) 
    return TRUE;

  return FALSE;
}


bool can_write( char_data* ch, int i, bool msg )
{
  if( !is_apprentice( ch ) && ( i == NOTE_IMMORTAL || i == NOTE_JOBS
    || i == NOTE_CHANGES || i == NOTE_FIXED || i == NOTE_ANNOUNCEMENTS
    || i == NOTE_CODE ) ) {
    if( msg ) 
      send( ch, "Only immortals can write on the %s noteboard.\r\n",
        noteboard_name[i] );
    return FALSE;
    }
  if( i == NOTE_AVATAR && !is_avatar( ch )  ) {
    if( msg )
      send( ch, "You aren't an avatar and cannot write to this board.\r\n" );
    return FALSE;
    }

  if( i == NOTE_CLAN && ch->pcdata->pfile->clan == NULL ) {
    if( msg )
      send( ch, "You aren't in a clan and thus have no noteboard.\r\n" );
    return FALSE;
    }

  return TRUE;
}


bool can_read( char_data* ch, int i, bool msg )
{ 
  if( noteboard_level( i ) > ch->pcdata->trust ) {
    if( msg )
      send( ch, "Only immortals can read the %s noteboard.\r\n",
        noteboard_name[i] );
    return FALSE;
    }

  if( i == NOTE_CLAN && ch->pcdata->pfile->clan == NULL ) {
    if( msg )
      send( ch, "You aren't in a clan and thus have no noteboard.\r\n" );
    return FALSE;
    }

  return TRUE;
}
 

int find_note( char_data* ch, int i, char* argument )
{
  int number = atoi( argument )-1;

  if( is_set( ch->pcdata->pfile->flags, PLR_REVERSE ) )
    number = max_note[i]-number-1;

  if( number < 0 || number >= max_note[i] ) {
    send( ch, "There is no note by that number.\r\n" );
    return -1;
    }

  return number;
}
    

int find_noteboard( char_data* ch, char*& argument, bool msg = FALSE )
{
  int i;

  for( i = 0; i < MAX_NOTEBOARD; i++ ) 
    if( matches( argument, noteboard_name[i] ) ) 
      return i;

  if( msg ) 
    send( ch, "No such noteboard exists.\r\n" );

  return -1;
}


void reverse( note_data*& list )
{
  note_data*  temp;
  note_data*  pntr;

  pntr = list;
  list = NULL;

  for( ; pntr != NULL; ) {
    temp       = pntr->next;
    pntr->next = list;
    list       = pntr;
    pntr       = temp;
    }

  return;
}


/*
 *   NOTEBOARD ROUTINE
 */


void do_notes( char_data* ch, char* argument )
{
  char            tmp1  [ 3*MAX_STRING_LENGTH ];
  char            tmp2  [ THREE_LINES ];
  note_data*      note;
  player_data*      pc;
  wizard_data*     imm;
  clan_data*      clan;
  int        noteboard;
  int           number;
  int                i;

  if( is_mob( ch ) ) 
    return;

  pc        = player( ch );
  imm       = wizard( ch );
  noteboard = pc->noteboard;

  if( ( clan = ch->pcdata->pfile->clan ) != NULL ) {
    note_list[ NOTE_CLAN ] = clan->note_list;
    max_note[ NOTE_CLAN ]  = clan->max_note;
    }

  if( ( note = pc->note_edit ) == NULL ) {
    if( *argument == '\0' ) {
      display_notes( pc );
      return;
      }

    if( ( i = find_noteboard( ch, argument ) ) != -1 ) {
      if( can_read( ch, i, TRUE ) ) {
        pc->noteboard = i;
        send( ch, "Note now works on the %s noteboard. ( %d notes )\r\n",
          noteboard_name[i], max_note[i] );
        }
      return;
      }

    if( fmatches( argument, "summary" ) ) {
      note_summary( ch );
      return;
      }

    if( matches( argument, "move" ) ) {
      if( ( noteboard = find_noteboard( ch, argument, TRUE ) ) == -1
        || !can_write( ch, noteboard, TRUE )
        || ( i = find_note( ch, pc->noteboard, argument ) ) == -1 )
        return;
      
      note = note_list[ pc->noteboard ][i];
      if( strcmp( ch->descr->name, note->from )
        && !has_permission( ch, PERM_NOTEBOARD ) ) {
        send( ch, "You are unable to move that note.\r\n" );
        return;
        }
      if( noteboard == pc->noteboard ) {
        send( ch, "The note is already on the %s board.\r\n",
          noteboard_name[noteboard] );
        return;
        }
      remove( note_list[ pc->noteboard ],
        max_note[ pc->noteboard ], i );
      insert( note_list[noteboard], max_note[noteboard], note,
        max_note[noteboard] );
      send( ch, "Note '%s' moved to %s board.\r\n",
        note->title, noteboard_name[noteboard] );
   
      sprintf( tmp1, "Note '%s' moved by %s to %s board from %s board.",
        note->title, ch->descr->name, noteboard_name[ noteboard ],
        noteboard_name[ pc->noteboard ] );
      info( empty_string, noteboard_level( noteboard ),
        tmp1, MAX_IFLAG+noteboard, 2, ch );
      note->noteboard = noteboard;
      save_notes( noteboard, clan );
      save_notes( pc->noteboard, clan );
      return;
      }

    if( matches( argument, "delete" ) ) {
      if( !strcasecmp( argument, "all" ) ) {
        if( !has_permission( ch, PERM_SHUTDOWN, TRUE ) ) 
          return;
        if( max_note[noteboard] == 0 ) {
          send( ch, "The %s noteboard is already clear.\r\n",
            noteboard_name[noteboard] );
          return;
	  }
        for( ; max_note[noteboard] > 0; ) 
          extract( ch, note_list[noteboard][0] );
        send( ch, "You clear the %s noteboard.\r\n", 
          noteboard_name[noteboard] );
        sprintf( tmp1, "%s noteboard cleared by %s.",
          noteboard_name[noteboard], ch->real_name( ) );
        *tmp1 = toupper( *tmp1 );
        info( empty_string, noteboard_level( noteboard ),
          tmp1, MAX_IFLAG+noteboard, 1, ch );
        save_notes( noteboard, clan );
        return;
        }
      if( *argument == '\0' ) {
        send( ch, "Which note do you wish to delete?\r\n" );
        return;
        }
      if( ( i = find_note( ch, noteboard, argument ) ) == -1 )
        return;
      note = note_list[noteboard][i];
      if( !can_remove( ch, note ) ) {
        send( ch, "You can't remove that note.\r\n" );
        return;
        }
      sprintf( tmp1, "Note '%s' deleted from the %s board by %s.",
        note->title, noteboard_name[noteboard], ch->descr->name );
      sprintf( tmp2, "Note '%s' deleted from the %s board by a mail daemon.",
        note->title, noteboard_name[noteboard] );
      info( tmp2, max( imm == NULL ? 0 : imm->wizinvis,
        noteboard_level( noteboard ) ),
        tmp1, MAX_IFLAG+noteboard, 3, ch, 
        noteboard == NOTE_CLAN ? ch->pcdata->pfile->clan : NULL );
      extract( ch, note );
      save_notes( noteboard, clan );
      send( ch, "Note removed.\r\n" );
      return;
      }

    if( isdigit( *argument ) ) {
      if( ( i = find_note( ch, noteboard, argument ) ) == -1 )
        return;
      note = note_list[noteboard][i]; 
      page( ch, "Title: %s\r\nFrom: %s\r\n\r\n",
        note->title, note->from );
      convert_to_ansi( ch, note->message, tmp1 );
      page( ch, tmp1 );
      return;
      }

    if( matches( argument, "edit" ) ) {
      if( ( number = atoi( argument )-1 ) < 0
        || number >= max_note[noteboard] ) {
        send( ch, "There is no note by that number.\r\n" );
        return;
        }

      if( is_set( ch->pcdata->pfile->flags, PLR_REVERSE ) )
        number = max_note[noteboard]-number-1;
      note = note_list[noteboard][number];

      if( strcmp( ch->descr->name, note->from )
        && !has_permission( ch, PERM_NOTEBOARD ) ) {
        send( ch, "You can't edit that note.\r\n" );
        return;
        }

      send( ch, "You now edit that note.\r\n" );
      pc->note_edit = note;
      return;
      }
 
    if( !can_write( ch, noteboard, TRUE ) )
      return;

    if( !acceptable_title( ch, argument ) )
      return;

    note              = new note_data;
    note->title       = alloc_string( argument, MEM_NOTE );
    note->from        = alloc_string( ch->descr->name, MEM_NOTE );
    note->noteboard   = -1;
    pc->note_edit = note;
    send( ch, "Note created.\r\n" );
    return;
    }

  if( !strcasecmp( argument, "delete" ) ) {
    if( note->noteboard != -1 ) {
      send( ch, "You stop editing the note.\r\n" );
      pc->note_edit = NULL;
      return;
      }
    delete note;
    pc->note_edit = NULL;
    send( ch, "Message deleted.\r\n" );
    return;
    }

  if( !strncasecmp( "title ", argument, 6 ) ) {
    argument += 6;
    if( !acceptable_title( ch, argument ) )
      return;
    free_string( note->title, MEM_NOTE );
    note->title = alloc_string( argument, MEM_NOTE );
    send( ch, "Note title changed.\r\n" );
    return;
    }

  if( !strcasecmp( "post", argument ) ) {
    note->date = current_time;
    if( note->noteboard == -1 ) {
      note->noteboard = noteboard;
      send( ch, "Note posted on %s board.\r\n",
        noteboard_name[noteboard] );
      sprintf( tmp1, "Note posted by %s on the %s board.",
        ch->descr->name, noteboard_name[noteboard] );
      info( empty_string, noteboard_level( noteboard ),
        tmp1, MAX_IFLAG+noteboard, 1, ch, 
        noteboard == NOTE_CLAN ? ch->pcdata->pfile->clan : NULL );
      }
    else {
      send( ch, "Modifications saved.\r\n" );
      sprintf( tmp1, "Note '%s' on %s board modified by %s.",
        note->title, noteboard_name[ note->noteboard ],
        ch->descr->name );
      info( empty_string, noteboard_level( noteboard ),
        tmp1, MAX_IFLAG+noteboard, 2, ch,
        noteboard == NOTE_CLAN ? ch->pcdata->pfile->clan : NULL );
      for( i = 0; note_list[noteboard][i] != note; i++ )
        if( i == max_note[noteboard]-1 ) {
          bug( "Do_Note: Modified note not found!" );
          return;
	  } 
      remove( note_list[noteboard], max_note[noteboard], i );
      }
    insert( note_list[noteboard], max_note[noteboard], note,
      max_note[noteboard] );
    pc->note_edit = NULL;
    save_notes( noteboard, clan );
    return;
    }

  page( ch, "Title: %s\r\n\r\n", note->title );
 
  pc->note_edit->message = edit_string( ch, argument,
    pc->note_edit->message, MEM_NOTE );

  return;
}


void display_notes( player_data* ch )
{
  char           tmp  [ TWO_LINES ];
  note_data*    note;
  bool       reverse;
  int              i;
  int            max;
  int      noteboard;

  reverse   = is_set( ch->pcdata->pfile->flags, PLR_REVERSE );
  noteboard = ch->noteboard;
  max       = max_note[ noteboard ];

  *tmp = '\0';

  for( i = 0; i < max; i++ ) {
    note = note_list[ noteboard ][ reverse ? max-i-1 : i ];
    if( *tmp == '\0' ) { 
      page_title( ch, "%s Noteboard", noteboard_name[ noteboard ] );
      }
    sprintf( tmp, "[%2d] %-15s %-40s %s\r\n", i+1, note->from,
      note->title, ltime( note->date ) );
    page( ch, tmp );
    }

  if( *tmp == '\0' ) 
    send( ch, "There are no messages.\r\n" );

  return;
}


void note_summary( char_data* ch )
{
  clan_data*    clan;
  int           i, j;
  int            max;
  bool         found  = FALSE;

  if( ( clan = ch->pcdata->pfile->clan ) != NULL ) {
    note_list[ NOTE_CLAN ] = clan->note_list;
    max_note[ NOTE_CLAN ]  = clan->max_note;
    }

  for( i = 0; i < MAX_NOTEBOARD; i++ ) {
    if( !can_read( ch, i ) )
      continue; 
    max = max_note[i];
    for( j = 0; j < max; j++ )
      if( note_list[i][max-j-1]->date < ch->pcdata->pfile->last_on ) 
        break;
    if( j > 0 ) {
      if( !found ) { 
        send_underlined( ch, "New Notes\r\n" );
        found = TRUE;
        }
      send( ch, "%15s : %d\r\n", noteboard_name[i], j );
      }
    }

  if( !found )
    send( ch, "There have been no new notes since last login.\r\n" );

  return;
}


/*
 *   MAIL ROUTINES
 */


const char* message1 =
  "The mail daemon takes the letter, opens it, reads it carefully,\
 rolls on\r\nthe floor laughing, and wanders off to find %s.\r\n";

const char* message2 =
  "The mail daemon takes the letter and sprints off to find %s.\r\n";

const char* message3 =
  "You give a mail daemon your letter.  The mail daemon loiters nearby and\
 whistles a tune.  When he realizes you aren't going to pay postage, he\
 stamps around just out of reach and mumbles rudely about immortals,\
 before slowly wandering off in the wrong direction.";

const char* message4 =
  "You give a mail daemon your letter.  He stands nearby with his hand out\
 for a few minutes and then grumbles and wanders off while chewing on a\
 corner of the letter.";

const char* dream_msg =
  "You really don't want to invite a daemon into your dreams.\r\n";


void mail_message( char_data* ch )
{
  char           tmp  [ TWO_LINES ];
  note_data*    note;
  int          total  = 0;
  int         recent  = 0;

  for( note = ch->pcdata->pfile->mail; note != NULL; note = note->next ) {
    total++;
    if( note->date > ch->pcdata->pfile->last_on ) 
      recent++;
    }

  if( total != 0 ) {
    if( recent != 0 ) 
      sprintf( tmp, "You have %s mail message%s.",
        number_word( total ), total == 1 ? "" : "s" );
    else 
      sprintf( tmp, "You have %s mail message%s.",
        number_word( total ), total == 1 ? "" : "s" );
    send_centered( ch, tmp );
    }

  return;
}


note_data* find_mail( char_data* ch, int number )
{
  note_data*   note  = ch->pcdata->pfile->mail;
  int          line  = 0;

  if( is_set( ch->pcdata->pfile->flags, PLR_REVERSE ) )
    number = count( note )-number+1;

  for( ; note != NULL; note = note->next )
    if( ++line == number )
      return note;

  send( ch, "You have no mail by that number.\r\n" );

  return NULL;
}


void do_mail( char_data* ch, char* argument )
{
  char               tmp  [ 3*MAX_STRING_LENGTH ];
  note_data*        note;
  note_data*    note_new;
  int                  i;

  if( is_confused_pet( ch ) || ch->pcdata == NULL )
    return;

  if( ch->species != NULL ) {
    send( ch, "You can only use the mail system in human form.\r\n" );
    return;
    }

  if( ( note = ch->pcdata->mail_edit ) == NULL ) {
    if( *argument == '\0' ) {
      display_mail( ch );
      return;
      }

    if( isdigit( *argument ) ) {
      if( ( note = find_mail( ch, atoi( argument ) ) ) == NULL )
        return;
      page( ch, "Title: %s\r\n", note->title );
      page( ch, "From:  %s\r\n\r\n", note->from );
      convert_to_ansi( ch, note->message, tmp );
      page( ch, tmp );
      return;
      }

    if( exact_match( argument, "delete" ) ) {
      if( ch->pcdata->pfile->mail == NULL ) {
        send( ch, "You have no mail to delete.\r\n" );
        return;
        }
      if( !strcasecmp( argument, "all" ) ) {
        delete_list( ch->pcdata->pfile->mail );
        send( ch, "All mail messages deleted.\r\n" );
        }
      else {
        if( ( note = find_mail( ch, atoi( argument ) ) ) == NULL )
          return;
        remove( ch->pcdata->pfile->mail, note );
        delete note;
        send( ch, "Mail message deleted.\r\n" );
        }
      save_mail( ch->pcdata->pfile );
      return;
      }

    if( exact_match( argument, "edit" ) ) {
      if( ( note = find_mail( ch, i = atoi( argument ) ) ) == NULL )
        return;
      note_new               = new note_data;
      note_new->title        = alloc_string( note->title, MEM_NOTE );
      note_new->message      = alloc_string( note->message, MEM_NOTE );
      note_new->from         = alloc_string( ch->real_name( ), MEM_NOTE );
      note_new->noteboard    = NOTE_PRIVATE;
      ch->pcdata->mail_edit  = note_new;
      send( ch, "Copied message %d to mail buffer.\r\n", i );
      return;
      }

    if( !acceptable_title( ch, argument ) )
      return;
 
    note                   = new note_data;
    note->title            = alloc_string( argument, MEM_NOTE );
    note->message          = alloc_string( "", MEM_NOTE );
    note->from             = alloc_string( ch->real_name( ), MEM_NOTE );
    note->noteboard        = NOTE_PRIVATE;
    ch->pcdata->mail_edit  = note;
    send( ch, "Starting new message with subject %s.\r\n", note->title );
    return;
    }

  if( exact_match( argument, "title" ) ) {
    if( !acceptable_title( ch, argument ) )
      return;
    free_string( note->title, MEM_NOTE );
    note->title = alloc_string( argument, MEM_NOTE );
    send( ch, "Mail title changed to '%s'.\r\n", argument );
    return;
    }    

  if( exact_match( argument, "send" ) ) {
    if( *argument == '\0' ) {
      send( ch, "Whom do you want to send the message to?\r\n" );
      return;
      } 
    send_mail( ch, 'S', argument );
    return;
    }

  if( exact_match( argument, "cc" ) ) {
    send_mail( ch, 'C', argument );
    return;
    }

  if( !strcasecmp( argument, "delete" ) ) {
    send( ch, "The message you were editing has been deleted.\r\n" );
    delete note;
    ch->pcdata->mail_edit = NULL;
    return;
    }
  
  sprintf( tmp, "Subject: %s\r\n\r\n", note->title );
  page( ch, tmp );
 
  ch->pcdata->mail_edit->message = edit_string( ch, argument,
    ch->pcdata->mail_edit->message, MEM_NOTE );

  return;
}


void display_mail( char_data* ch )
{
  char          tmp  [ TWO_LINES ];
  note_data*   note;
  int          line  = 0;

  if( ch->pcdata->pfile->mail == NULL ) { 
    send( "You have no mail.\r\n", ch );
    return;
    }

  if( is_set( ch->pcdata->pfile->flags, PLR_REVERSE ) )
    reverse( ch->pcdata->pfile->mail );

  for( note = ch->pcdata->pfile->mail; note != NULL; note = note->next ) {
    sprintf( tmp, "[%2d] %-34s %-15s %s\r\n", ++line, note->title,
      note->from, ltime( note->date ) );
    page( ch, tmp );
    }

  if( is_set( ch->pcdata->pfile->flags, PLR_REVERSE ) )
    reverse( ch->pcdata->pfile->mail );

  return;
}


void send_mail( char_data* ch, char letter, char* argument )    
{
  char             tmp  [ TWO_LINES ];
  note_data*      note;
  note_data*  note_new;
  link_data*      link;
  pfile_data*    pfile;

  note = ch->pcdata->mail_edit;

  if( *argument == '\0' ) {
    send( ch, "%s the message to whom?\r\n",
      letter == 'C' ? "Cc" : "Send" );
    return;
    }

  if( ( pfile = find_pfile( argument ) ) == NULL ) {
    send( ch, "There is noone by that name.\r\n" );
    return;
    } 

  if( ch->position == POS_SLEEPING ) {
    send( ch, dream_msg );
    return;
    }

  if( ch->pcdata->pfile != pfile ) {
    sprintf( tmp, "You give a mail daemon your letter and" );
    if( !remove_coins( ch, 10, tmp ) ) {
      if( ch->shdata->level < LEVEL_APPRENTICE ) {
        send( ch,
          "You don't have the silver coin required to mail a letter.\r\n" );
        return;
        }
      fsend( ch, number_range( 0, 1 ) == 0 ? message3 : message4 );
      }
    else {
      send( ch, number_range( 0, 50 ) == 0 ? message1 : message2,
        pfile->name );
      }
    }
  else {
    send( ch, "You %s the letter to yourself.\r\n",
      letter == 'S' ? "send" : "cc a copy of" );
    }

  if( letter != 'S' ) {
    note_new              = new note_data;
    note_new->title       = alloc_string( note->title,    MEM_NOTE );
    note_new->message     = alloc_string( note->message,  MEM_NOTE );
    note_new->from        = alloc_string( note->from,     MEM_NOTE );
    note_new->noteboard   = NOTE_PRIVATE;
    note                  = note_new;
    }
  else {
    ch->pcdata->mail_edit = NULL;
    }  

  note->date = current_time;

  append( pfile->mail, note );
  save_mail( pfile );

  if( ch->pcdata->pfile != pfile ) 
    for( link = link_list; link != NULL; link = link->next ) {
      if( link->character != NULL && link->connected == CON_PLAYING
        && link->character->pcdata->pfile == pfile ) {
        send( link->character,
          "A mail daemon runs up and hands you a letter from %s.\r\n", ch );
        break;
        }
      }

  return;
}


/*
 *   DISK ROUTINES
 */


void read_mail( pfile_data *pfile )
{
  char          tmp  [ TWO_LINES ];
  note_data*   note;
  char*       title;
  FILE*          fp;

  sprintf( tmp, "%s%s", MAIL_DIR, pfile->name );

  if( ( fp = fopen( tmp, "r" ) ) != NULL ) { 
    if( strcmp( fread_word( fp ), "#MAIL" ) ) {
      bug( "Read_mail: missing header", 0 );
      exit( 1 );
      }

    for( ; ; ) {
      title = fread_string( fp, MEM_NOTE );
      if( title[0] == '$' ) {
        free_string( title, MEM_NOTE );
        break;
        }

      if( strlen( title ) > 40 )
        title[40] = '\0';

      note            = new note_data;
      note->title     = title;
      note->from      = fread_string( fp, MEM_NOTE );
      note->message   = fread_string( fp, MEM_NOTE ); 
      note->noteboard = NOTE_PRIVATE;
      note->date      = fread_number( fp ); 

      append( pfile->mail, note );
      }
    fclose( fp );
    }

  return;
}


void save_mail( pfile_data *pfile )
{
  FILE*         fp;
  note_data*  note;

  if( pfile->mail == NULL ) {
    delete_file( MAIL_DIR, pfile->name, FALSE );
    }     
  else if( ( fp = open_file( MAIL_DIR, pfile->name, "w" ) ) != NULL ) {
    fprintf( fp, "#MAIL\n\n" );

    for( note = pfile->mail; note != NULL; note = note->next ) {
      fprintf( fp, "%s~\n", note->title );
      fprintf( fp, "%s~\n", note->from );
      fprintf( fp, "%s~\n", note->message );
      fprintf( fp, "%d\n",  int( note->date ) );
      }

    fprintf( fp, "$~\n" );
    fclose( fp );
    }

  return;
}


/*
 *   NOTEBOARD DISK ROUTINES
 */


void load_notes( void )
{
  char          tmp  [ TWO_LINES ];
  int             i;

  echo( "Loading Notes ...\r\n" );

  for( i = 0; i < MAX_NOTEBOARD; i++ ) 
    if( i != NOTE_CLAN ) {
      sprintf( tmp, "%s%s", NOTE_DIR, noteboard_name[i] );
      load_noteboard( tmp, note_list[i], max_note[i], i );
      }

  return;
}


void load_notes( clan_data* clan )
{
  char tmp [ ONE_LINE ];

  sprintf( tmp, "%s%s", CLAN_NOTE_DIR, clan->abbrev );
  load_noteboard( tmp, clan->note_list, clan->max_note, NOTE_CLAN );

  return;
}


void load_noteboard( char* file, note_data**& list, int& max, int noteboard )
{
  note_data*   note;
  char*       title;
  FILE*          fp;

  list = NULL;
  max  = 0;

  fp = open_file( file, "r" );

  if( strcmp( fread_word( fp ), "#NOTES" ) )
    panic( "Load_notes: missing header" );

  for( ; ; ) {
    title = fread_string( fp, MEM_NOTE );

    if( *title == '$' ) {
      free_string( title, MEM_NOTE );
      break;
      }
 
    note            = new note_data;
    note->title     = title;
    note->from      = fread_string( fp, MEM_NOTE );
    note->message   = fread_string( fp, MEM_NOTE ); 
    note->date      = fread_number( fp ); 
    note->noteboard = noteboard;

    insert( list, max, note, max );
    }

  fclose( fp );
  return;
}


void save_notes( int i, clan_data* clan )
{
  char          tmp  [ TWO_LINES ];

  if( i == -1 ) {
    for( i = 0; i < MAX_NOTEBOARD; i++ )
      if( i != NOTE_CLAN ) 
        save_notes( i );
    return;
    }

  if( i == NOTE_CLAN ) {
    clan->note_list = note_list[ NOTE_CLAN ];
    clan->max_note  = max_note[ NOTE_CLAN ];
    save_notes( clan );
    }
  else {
    sprintf( tmp, "%s%s", NOTE_DIR, noteboard_name[i] );
    save_noteboard( tmp, note_list[i], max_note[i] );
    }
}


void save_notes( clan_data* clan )
{
  char tmp [ ONE_LINE ];

  sprintf( tmp, "%s%s", CLAN_NOTE_DIR, clan->abbrev );
  save_noteboard( tmp, clan->note_list, clan->max_note );

  return;
}


void save_noteboard( char* file, note_data** list, int max )
{ 
  FILE*          fp;
  note_data*   note;
  int             i;

  if( ( fp = open_file( file, "w" ) ) == NULL ) 
    return;

  fprintf( fp, "#NOTES\n\n" );

  for( i = 0; i < max; i++ ) {
    note = list[i];
    fprintf( fp, "%s~\n", note->title );
    fprintf( fp, "%s~\n", note->from );
    fprintf( fp, "%s~\n", note->message );
    fprintf( fp, "%d\n",  int( note->date ) );
    }

  fprintf( fp, "$~\n" );
  fclose( fp );

  return;
}