toc/
toc/account/a/
toc/area/backup/
toc/area/imc/
toc/caste/
toc/caste/backup/
toc/clans/
toc/classes/
toc/crash/
toc/gods/
toc/guilds/
toc/lname/s/
toc/maps/backup/
toc/player/a/
toc/src/
toc/system/backup/
toc/tableprog/
/****************************************************************************
 * [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.     *
 * ------------------------------------------------------------------------ *
 *			     Special boards module (Old Ones)                         *     
 ****************************************************************************/

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


/* Defines for voting on notes. -- Narn */
#define VOTE_NONE 0
#define VOTE_OPEN 1
#define VOTE_CLOSED 2

BOARD_DATA *first_board;
BOARD_DATA *last_board;

bool is_note_to args((CHAR_DATA * ch, NOTE_DATA * pnote));
void note_attach args((CHAR_DATA * ch));
void note_remove args((CHAR_DATA * ch, BOARD_DATA * board, NOTE_DATA * pnote));
void do_note args((CHAR_DATA * ch, char *arg_passed, bool IS_MAIL));



bool can_remove(CHAR_DATA * ch, BOARD_DATA * board)
{
   /* If your trust is high enough, you can remove it. */
   if (get_trust(ch) >= board->min_remove_level)
      return TRUE;

   if (board->extra_removers[0] != '\0')
   {
      if (is_name(ch->name, board->extra_removers))
         return TRUE;
   }
   return FALSE;
}

bool can_read(CHAR_DATA * ch, BOARD_DATA * board)
{
   /* If your trust is high enough, you can read it. */
   if (get_trust(ch) >= board->min_read_level)
      return TRUE;

   /* Your trust wasn't high enough, so check if a read_group or extra 
      readers have been set up. */
   if (board->read_group[0] != '\0')
   {
      if (ch->pcdata->clan && !str_cmp(ch->pcdata->clan->name, board->read_group))
         return TRUE;
      if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, board->read_group))
         return TRUE;
   }
   if (board->extra_readers[0] != '\0')
   {
      if (is_name(ch->name, board->extra_readers))
         return TRUE;
   }
   return FALSE;
}

bool can_post(CHAR_DATA * ch, BOARD_DATA * board)
{
   /* If your trust is high enough, you can post. */
   if (get_trust(ch) >= board->min_post_level)
      return TRUE;

   /* Your trust wasn't high enough, so check if a post_group has been set up. */
   if (board->post_group[0] != '\0')
   {
      if (ch->pcdata->clan && !str_cmp(ch->pcdata->clan->name, board->post_group))
         return TRUE;
      if (ch->pcdata->council && !str_cmp(ch->pcdata->council->name, board->post_group))
         return TRUE;
   }
   return FALSE;
}


/*
 * board commands.
 */
void write_boards_txt()
{
   BOARD_DATA *tboard;
   FILE *fpout;
   char filename[256];

   sprintf(filename, "%s%s", BOARD_DIR, BOARD_FILE);
   fpout = fopen(filename, "w");
   if (!fpout)
   {
      bug("FATAL: cannot open board.txt for writing!\n\r", 0);
      return;
   }
   for (tboard = first_board; tboard; tboard = tboard->next)
   {
      fprintf(fpout, "Filename          %s~\n", tboard->note_file);
      fprintf(fpout, "Vnum              %d\n", tboard->board_obj);
      fprintf(fpout, "Min_read_level    %d\n", tboard->min_read_level);
      fprintf(fpout, "Min_post_level    %d\n", tboard->min_post_level);
      fprintf(fpout, "Min_remove_level  %d\n", tboard->min_remove_level);
      fprintf(fpout, "Max_posts         %d\n", tboard->max_posts);
      fprintf(fpout, "Type 	           %d\n", tboard->type);
      fprintf(fpout, "Read_group        %s~\n", tboard->read_group);
      fprintf(fpout, "Post_group        %s~\n", tboard->post_group);
      fprintf(fpout, "Extra_readers     %s~\n", tboard->extra_readers);
      fprintf(fpout, "Extra_removers    %s~\n", tboard->extra_removers);

      fprintf(fpout, "End\n");
   }
   fclose(fpout);
}

BOARD_DATA *get_board(OBJ_DATA * obj)
{
   BOARD_DATA *board;

   for (board = first_board; board; board = board->next)
      if (board->board_obj == obj->pIndexData->vnum)
         return board;
   return NULL;
}

BOARD_DATA *find_board(CHAR_DATA * ch)
{
   OBJ_DATA *obj;
   BOARD_DATA *board;

   for (obj = ch->in_room->first_content; obj; obj = obj->next_content)
   {
      if ((board = get_board(obj)) != NULL && IN_SAME_ROOM_OBJ(ch, obj))
         return board;
   }

   return NULL;
}

/*
bool is_note_to( CHAR_DATA *ch, NOTE_DATA *pnote )
{
    if ( !str_cmp( ch->name, pnote->sender ) )
	return TRUE;

    if ( is_name( "all", pnote->to_list ) )
	return TRUE;

    if ( IS_HERO(ch) && is_name( "immortal", pnote->to_list ) )
	return TRUE;

    if ( is_name( ch->name, pnote->to_list ) )
	return TRUE;

    return FALSE;
}   */



void note_attach(CHAR_DATA * ch)
{
   NOTE_DATA *pnote;

   if (ch->pnote)
      return;

   CREATE(pnote, NOTE_DATA, 1);
   pnote->next = NULL;
   pnote->prev = NULL;
   pnote->sender = QUICKLINK(ch->name);
   pnote->date = STRALLOC("");
   pnote->to_list = STRALLOC("");
   pnote->subject = STRALLOC("");
   pnote->text = STRALLOC("");
   ch->pnote = pnote;
   return;
}

void write_board(BOARD_DATA * board)
{
   FILE *fp;
   char filename[256];
   NOTE_DATA *pnote;

   /*
    * Rewrite entire list.
    */
   fclose(fpReserve);
   sprintf(filename, "%s%s", BOARD_DIR, board->note_file);
   if ((fp = fopen(filename, "w")) == NULL)
   {
      perror(filename);
   }
   else
   {
      for (pnote = board->first_note; pnote; pnote = pnote->next)
      {
         fprintf(fp, "Sender  %s~\nDate    %s~\nTo      %s~\nSubject %s~\nVoting %d\nYesvotes %s~\nNovotes %s~\nAbstentions %s~\nText\n%s~\n\n",
            pnote->sender,
            pnote->date, pnote->to_list, pnote->subject, pnote->voting, pnote->yesvotes, pnote->novotes, pnote->abstentions, pnote->text);
      }
      fclose(fp);
   }
   fpReserve = fopen(NULL_FILE, "r");
   return;
}


void free_note(NOTE_DATA * pnote)
{
   STRFREE(pnote->text);
   STRFREE(pnote->subject);
   STRFREE(pnote->to_list);
   STRFREE(pnote->date);
   STRFREE(pnote->sender);
   if (pnote->yesvotes)
      DISPOSE(pnote->yesvotes);
   if (pnote->novotes)
      DISPOSE(pnote->novotes);
   if (pnote->abstentions)
      DISPOSE(pnote->abstentions);
   DISPOSE(pnote);
}

void note_remove(CHAR_DATA * ch, BOARD_DATA * board, NOTE_DATA * pnote)
{

   if (!board)
   {
      bug("note remove: null board", 0);
      return;
   }

   if (!pnote)
   {
      bug("note remove: null pnote", 0);
      return;
   }

   /*
    * Remove note from linked list.
    */
   UNLINK(pnote, board->first_note, board->last_note, next, prev);

   --board->num_posts;
   free_note(pnote);
   write_board(board);
}


OBJ_DATA *find_quill(CHAR_DATA * ch)
{
   OBJ_DATA *quill;

   for (quill = ch->last_carrying; quill; quill = quill->prev_content)
      if (quill->item_type == ITEM_PEN && can_see_obj(ch, quill))
         return quill;
   return NULL;
}

void do_noteroom(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;
   char arg[MSL];
   char arg_passed[MSL];

   strcpy(arg_passed, argument);

   switch (ch->substate)
   {
      case SUB_WRITING_NOTE:
         do_note(ch, arg_passed, FALSE);
         break;

      default:

         argument = one_argument(argument, arg);
         smash_tilde(argument);
         if (!str_cmp(arg, "write") || !str_cmp(arg, "to") || !str_cmp(arg, "subject") || !str_cmp(arg, "show"))
         {
            do_note(ch, arg_passed, FALSE);
            return;
         }

         board = find_board(ch);
         if (!board)
         {
            send_to_char("There is no bulletin board here to look at.\n\r", ch);
            return;
         }

         if (board->type != BOARD_NOTE)
         {
            send_to_char("You can only use note commands on a note board.\n\r", ch);
            return;
         }
         else
         {
            do_note(ch, arg_passed, FALSE);
            return;
         }
   }
}

void do_mailroom(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;
   char arg[MSL];
   char arg_passed[MSL];

   strcpy(arg_passed, argument);

   switch (ch->substate)
   {
      case SUB_WRITING_NOTE:
         do_note(ch, arg_passed, TRUE);
         break;

      default:

         argument = one_argument(argument, arg);
         smash_tilde(argument);
         if (!str_cmp(arg, "write") || !str_cmp(arg, "to") || !str_cmp(arg, "subject") || !str_cmp(arg, "show"))
         {
            do_note(ch, arg_passed, TRUE);
            return;
         }

         board = find_board(ch);
         if (!board)
         {
            send_to_char("There is no mail facility here.\n\r", ch);
            return;
         }

         if (board->type != BOARD_MAIL)
         {
            send_to_char("You can only use mail commands in a post office.\n\r", ch);
            return;
         }
         else
         {
            do_note(ch, arg_passed, TRUE);
            return;
         }
   }
}

OBJ_DATA *find_inote(CHAR_DATA * ch)
{
   OBJ_DATA *note;

   for (note = ch->first_carrying; note; note = note->next_content)
   {
      if (note->item_type == ITEM_PAPER)
         return note;
   }
   return NULL;
}

void do_note(CHAR_DATA * ch, char *arg_passed, bool IS_MAIL)
{
   char buf[MSL];
   char arg[MIL];
   NOTE_DATA *pnote;
   BOARD_DATA *board;
   int vnum;
   int anum;
   int first_list;
   OBJ_DATA *quill = NULL, *paper = NULL;
   EXTRA_DESCR_DATA *ed = NULL;
   char notebuf[MSL];
   char short_desc_buf[MSL];
   char long_desc_buf[MSL];
   char keyword_buf[MSL];
   bool mfound = FALSE;

   if (IS_NPC(ch))
      return;

   if (!ch->desc)
   {
      bug("do_note: no descriptor", 0);
      return;
   }

   switch (ch->substate)
   {
      default:
         break;
      case SUB_WRITING_NOTE:
         if ((paper = find_inote(ch)) == NULL || paper->item_type != ITEM_PAPER)
         {
            bug("do_note: player not holding paper", 0);
            stop_editing(ch);
            return;
         }
         ed = ch->dest_buf;
         STRFREE(ed->description);
         ed->description = copy_buffer(ch);
         stop_editing(ch);
         return;
   }

   set_char_color(AT_NOTE, ch);
   arg_passed = one_argument(arg_passed, arg);
   smash_tilde(arg_passed);

   /* Reusing alot of code but this will have to do till I can think
    * of a better way to do it. --Shaddai
    */

   if (!str_cmp(arg, "date"))
   {
      board = find_board(ch);
      if (!board)
      {
         send_to_char("There is no board here to look at.\n\r", ch);
         return;
      }
      if (!can_read(ch, board))
      {
         send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch);
         return;
      }

      first_list = atoi(arg_passed);
      if (first_list)
      {
         if (IS_MAIL)
         {
            send_to_char("You cannot use a list number (at this time) with mail.\n\r", ch);
            return;
         }

         if (first_list < 1)
         {
            send_to_char("You can't read a note before 1!\n\r", ch);
            return;
         }
      }


      if (!IS_MAIL)
      {
         set_pager_color(AT_NOTE, ch);
         vnum = 0;
         for (pnote = board->first_note; pnote; pnote = pnote->next)
         {
            vnum++;
            if ((first_list && vnum >= first_list) || !first_list)
               pager_printf(ch, "%2d%c %-12s%c %-24s : %-35s\n\r",
                  vnum,
                  is_note_to(ch, pnote) ? ')' : '}',
                  pnote->sender, (pnote->voting != VOTE_NONE) ? (pnote->voting == VOTE_OPEN ? 'V' : 'C') : ':', pnote->date, pnote->subject);
         }
         act(AT_ACTION, "$n glances over the notes.", ch, NULL, NULL, TO_CANSEE);
         return;
      }
      else
      {
         vnum = 0;


         if (IS_MAIL) /* SB Mail check for Brit */
         {
            for (pnote = board->first_note; pnote; pnote = pnote->next)
               if (is_note_to(ch, pnote))
                  mfound = TRUE;

            if (!mfound && get_trust(ch) < sysdata.read_all_mail)
            {
               ch_printf(ch, "You have no mail.\n\r");
               return;
            }
         }

         for (pnote = board->first_note; pnote; pnote = pnote->next)
            if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail)
               ch_printf(ch, "%2d%c %-12s: %-13s : %s\n\r", ++vnum, is_note_to(ch, pnote) ? '-' : '}', pnote->sender, pnote->subject);
         return;
      }
   }

   if (!str_cmp(arg, "list"))
   {
      board = find_board(ch);
      if (!board)
      {
         send_to_char("There is no board here to look at.\n\r", ch);
         return;
      }
      if (!can_read(ch, board))
      {
         send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch);
         return;
      }

      first_list = atoi(arg_passed);
      if (first_list)
      {
         if (IS_MAIL)
         {
            send_to_char("You cannot use a list number (at this time) with mail.\n\r", ch);
            return;
         }

         if (first_list < 1)
         {
            send_to_char("You can't read a note before 1!\n\r", ch);
            return;
         }
      }


      if (!IS_MAIL)
      {
         set_pager_color(AT_NOTE, ch);
         vnum = 0;
         for (pnote = board->first_note; pnote; pnote = pnote->next)
         {
            vnum++;
            if ((first_list && vnum >= first_list) || !first_list)
               pager_printf(ch, "%2d%c %-12s%c %-12.12s : %s\n\r",
                  vnum,
                  is_note_to(ch, pnote) ? ')' : '}',
                  pnote->sender, (pnote->voting != VOTE_NONE) ? (pnote->voting == VOTE_OPEN ? 'V' : 'C') : ':', pnote->to_list, pnote->subject);
         }
         act(AT_ACTION, "$n glances over the notes.", ch, NULL, NULL, TO_CANSEE);
         return;
      }
      else
      {
         vnum = 0;


         if (IS_MAIL) /* SB Mail check for Brit */
         {
            for (pnote = board->first_note; pnote; pnote = pnote->next)
               if (is_note_to(ch, pnote))
                  mfound = TRUE;

            if (!mfound && get_trust(ch) < sysdata.read_all_mail)
            {
               ch_printf(ch, "You have no mail.\n\r");
               return;
            }
         }

         for (pnote = board->first_note; pnote; pnote = pnote->next)
            if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail)
               ch_printf(ch, "%2d%c %s: %s\n\r", ++vnum, is_note_to(ch, pnote) ? '-' : '}', pnote->sender, pnote->subject);
         return;
      }
   }

   if (!str_cmp(arg, "read"))
   {
      bool fAll;

      board = find_board(ch);
      if (!board)
      {
         send_to_char("There is no board here to look at.\n\r", ch);
         return;
      }
      if (!can_read(ch, board))
      {
         send_to_char("You cannot make any sense of the cryptic scrawl on this board...\n\r", ch);
         return;
      }

      if (!str_cmp(arg_passed, "all"))
      {
         fAll = TRUE;
         anum = 0;
      }
      else if (is_number(arg_passed))
      {
         fAll = FALSE;
         anum = atoi(arg_passed);
      }
      else
      {
         send_to_char("Note read which number?\n\r", ch);
         return;
      }

      set_pager_color(AT_NOTE, ch);
      if (!IS_MAIL)
      {
         vnum = 0;
         for (pnote = board->first_note; pnote; pnote = pnote->next)
         {
            vnum++;
            if (vnum == anum || fAll)
            {
               pager_printf(ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s", vnum, pnote->sender, pnote->subject, pnote->date, pnote->to_list, pnote->text);

               if (pnote->yesvotes[0] != '\0' || pnote->novotes[0] != '\0' || pnote->abstentions[0] != '\0')
               {
                  send_to_pager("------------------------------------------------------------\n\r", ch);
                  pager_printf(ch, "Votes:\n\rYes:     %s\n\rNo:      %s\n\rAbstain: %s\n\r", pnote->yesvotes, pnote->novotes, pnote->abstentions);
               }
               act(AT_ACTION, "$n reads a note.", ch, NULL, NULL, TO_CANSEE);
               return;
            }
         }
         send_to_char("No such note.\n\r", ch);
         return;
      }
      else
      {
         vnum = 0;
         for (pnote = board->first_note; pnote; pnote = pnote->next)
         {
            if (is_note_to(ch, pnote) || get_trust(ch) >= sysdata.read_all_mail)
            {
               vnum++;
               if (vnum == anum || fAll)
               {
                  if (ch->gold < 10 && get_trust(ch) < sysdata.read_mail_free)
                  {
                     send_to_char("It costs 10 gold coins to read a message.\n\r", ch);
                     return;
                  }
                  if (get_trust(ch) < sysdata.read_mail_free)
                     ch->gold -= 10;
                  pager_printf(ch, "[%3d] %s: %s\n\r%s\n\rTo: %s\n\r%s",
                     vnum, pnote->sender, pnote->subject, pnote->date, pnote->to_list, pnote->text);
                  return;
               }
            }
         }
         send_to_char("No such message.\n\r", ch);
         return;
      }
   }

   /* Voting added by Narn, June '96 */
   if (!str_cmp(arg, "vote"))
   {
      char arg2[MIL];

      arg_passed = one_argument(arg_passed, arg2);

      board = find_board(ch);
      if (!board)
      {
         send_to_char("There is no bulletin board here.\n\r", ch);
         return;
      }
      if (!can_read(ch, board))
      {
         send_to_char("You cannot vote on this board.\n\r", ch);
         return;
      }

      if (is_number(arg2))
         anum = atoi(arg2);
      else
      {
         send_to_char("Note vote which number?\n\r", ch);
         return;
      }

      vnum = 1;
      for (pnote = board->first_note; pnote && vnum < anum; pnote = pnote->next)
         vnum++;
      if (!pnote)
      {
         send_to_char("No such note.\n\r", ch);
         return;
      }

      /* Options: open close yes no abstain */
      /* If you're the author of the note and can read the board you can open 
         and close voting, if you can read it and voting is open you can vote.
       */
      if (!str_cmp(arg_passed, "open"))
      {
         if (str_cmp(ch->name, pnote->sender))
         {
            send_to_char("You are not the author of this note.\n\r", ch);
            return;
         }
         pnote->voting = VOTE_OPEN;
         act(AT_ACTION, "$n opens voting on a note.", ch, NULL, NULL, TO_ROOM);
         send_to_char("Voting opened.\n\r", ch);
         write_board(board);
         return;
      }
      if (!str_cmp(arg_passed, "close"))
      {
         if (str_cmp(ch->name, pnote->sender))
         {
            send_to_char("You are not the author of this note.\n\r", ch);
            return;
         }
         pnote->voting = VOTE_CLOSED;
         act(AT_ACTION, "$n closes voting on a note.", ch, NULL, NULL, TO_ROOM);
         send_to_char("Voting closed.\n\r", ch);
         write_board(board);
         return;
      }

      /* Make sure the note is open for voting before going on. */
      if (pnote->voting != VOTE_OPEN)
      {
         send_to_char("Voting is not open on this note.\n\r", ch);
         return;
      }

      /* Can only vote once on a note. */
      sprintf(buf, "%s %s %s", pnote->yesvotes, pnote->novotes, pnote->abstentions);
      if (is_name(ch->name, buf))
      {
         send_to_char("You have already voted on this note.\n\r", ch);
         return;
      }
      if (!str_cmp(arg_passed, "yes"))
      {
         sprintf(buf, "%s %s", pnote->yesvotes, ch->name);
         DISPOSE(pnote->yesvotes);
         pnote->yesvotes = str_dup(buf);
         act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM);
         send_to_char("Ok.\n\r", ch);
         write_board(board);
         return;
      }
      if (!str_cmp(arg_passed, "no"))
      {
         sprintf(buf, "%s %s", pnote->novotes, ch->name);
         DISPOSE(pnote->novotes);
         pnote->novotes = str_dup(buf);
         act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM);
         send_to_char("Ok.\n\r", ch);
         write_board(board);
         return;
      }
      if (!str_cmp(arg_passed, "abstain"))
      {
         sprintf(buf, "%s %s", pnote->abstentions, ch->name);
         DISPOSE(pnote->abstentions);
         pnote->abstentions = str_dup(buf);
         act(AT_ACTION, "$n votes on a note.", ch, NULL, NULL, TO_ROOM);
         send_to_char("Ok.\n\r", ch);
         write_board(board);
         return;
      }
      do_note(ch, "", FALSE);
   }
   if (!str_cmp(arg, "write"))
   {
      if (ch->substate == SUB_RESTRICTED)
      {
         send_to_char("You cannot write a note from within another command.\n\r", ch);
         return;
      }
      if (get_trust(ch) < sysdata.write_mail_free)
      {
         quill = find_quill(ch);
         if (!quill)
         {
            send_to_char("You need a quill to write a note.\n\r", ch);
            return;
         }
         if (quill->value[0] < 1)
         {
            send_to_char("Your quill is dry.\n\r", ch);
            return;
         }
      }
      if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER)
      {
         if (get_trust(ch) < sysdata.write_mail_free)
         {
            send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch);
            return;
         }
         paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0);
         paper = obj_to_char(paper, ch);
         act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM);
         act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR);
      }
      if (paper->value[0] < 2)
      {
         paper->value[0] = 1;
         ed = SetOExtra(paper, "_text_");
         ch->substate = SUB_WRITING_NOTE;
         ch->dest_buf = ed;
         if (get_trust(ch) < sysdata.write_mail_free)
            --quill->value[0];
         start_editing(ch, ed->description);

         {
            char *subject, *to_list;

            if ((subject = get_extra_descr("_subject_", paper->first_extradesc)) == NULL)
               subject = "(no subject)";
            if ((to_list = get_extra_descr("_to_", paper->first_extradesc)) == NULL)
               to_list = "(nobody)";

            editor_desc_printf(ch, "Note entitled '%s', addressed to %s.", subject, to_list);
         }
         return;
      }
      else
      {
         send_to_char("You cannot modify this note.\n\r", ch);
         return;
      }
   }

   if (!str_cmp(arg, "subject"))
   {
      if (get_trust(ch) < sysdata.write_mail_free)
      {
         quill = find_quill(ch);
         if (!quill)
         {
            send_to_char("You need a quill to write a note.\n\r", ch);
            return;
         }
         if (quill->value[0] < 1)
         {
            send_to_char("Your quill is dry.\n\r", ch);
            return;
         }
      }
      if (!arg_passed || arg_passed[0] == '\0')
      {
         send_to_char("What do you wish the subject to be?\n\r", ch);
         return;
      }
      if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER)
      {
         if (get_trust(ch) < sysdata.write_mail_free)
         {
            send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch);
            return;
         }
         paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0);
         paper = obj_to_char(paper, ch);
         act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM);
         act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR);
      }
      if (paper->value[1] > 1)
      {
         send_to_char("You cannot modify this note.\n\r", ch);
         return;
      }
      else
      {
         paper->value[1] = 1;
         ed = SetOExtra(paper, "_subject_");
         STRFREE(ed->description);
         ed->description = STRALLOC(arg_passed);
         send_to_char("Ok.\n\r", ch);
         return;
      }
   }

   if (!str_cmp(arg, "to"))
   {
      struct stat fst;

/*	char *pn;*/
      char fname[1024];
      bool imc = FALSE;

      if (get_trust(ch) < sysdata.write_mail_free)
      {
         quill = find_quill(ch);
         if (!quill)
         {
            send_to_char("You need a quill to write a note.\n\r", ch);
            return;
         }
         if (quill->value[0] < 1)
         {
            send_to_char("Your quill is dry.\n\r", ch);
            return;
         }
      }
      if (!arg_passed || arg_passed[0] == '\0')
      {
         send_to_char("Please specify an addressee.\n\r", ch);
         return;
      }
      if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER)
      {
         if (get_trust(ch) < sysdata.write_mail_free)
         {
            send_to_char("You need to be holding a fresh piece of parchment to write a note.\n\r", ch);
            return;
         }
         paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0);
         paper = obj_to_char(paper, ch);
         act(AT_MAGIC, "A piece of parchment magically appears in $n's hands!", ch, NULL, NULL, TO_ROOM);
         act(AT_MAGIC, "A piece of parchment appears in your hands.", ch, NULL, NULL, TO_CHAR);
      }

      if (paper->value[2] > 1)
      {
         send_to_char("You cannot modify this note.\n\r", ch);
         return;
      }

      arg_passed[0] = UPPER(arg_passed[0]);

/*	if ((pn = strchr(arg_passed, '@'))!=NULL)*/
      if (strchr(arg_passed, '@') != NULL)
      {
         if (get_trust(ch) < sysdata.imc_mail_level)
         {
            ch_printf(ch, "You need to be at least level %d to send " "notes to other muds.\n\r", sysdata.imc_mail_level);
            return;
         }
/*	    *pn = '\0';
	    if (is_name("all", arg_passed))
	    {
	        ch_printf(ch, "You cannot send IMC mail to ALL.\n\r");
	        return;
	    }
	    *pn = '@';*/
         imc = TRUE;
      }

      sprintf(fname, "%s%c/%s", PLAYER_DIR, tolower(arg_passed[0]), capitalize(arg_passed));

      if (!IS_MAIL || imc || stat(fname, &fst) != -1 || !str_cmp(arg_passed, "all"))
      {
         paper->value[2] = 1;
         ed = SetOExtra(paper, "_to_");
         STRFREE(ed->description);
         ed->description = STRALLOC(arg_passed);
         send_to_char("Ok.\n\r", ch);
         return;
      }
      else
      {
         send_to_char("No player exists by that name.\n\r", ch);
         return;
      }

   }

   if (!str_cmp(arg, "show"))
   {
      char *subject, *to_list, *text;

      if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER)
      {
         send_to_char("You are not holding a note.\n\r", ch);
         return;
      }

      if ((subject = get_extra_descr("_subject_", paper->first_extradesc)) == NULL)
         subject = "(no subject)";
      if ((to_list = get_extra_descr("_to_", paper->first_extradesc)) == NULL)
         to_list = "(nobody)";
      sprintf(buf, "%s: %s\n\rTo: %s\n\r", ch->name, subject, to_list);
      send_to_char(buf, ch);
      if ((text = get_extra_descr("_text_", paper->first_extradesc)) == NULL)
         text = "The note is blank.\n\r";
      send_to_char(text, ch);
      return;
   }

   if (!str_cmp(arg, "post"))
   {
      char *strtime, *to, *subj, *text /*, *np = NULL */ ;
      bool imc = FALSE;

      if (((paper = find_inote(ch)) == NULL) || paper->item_type != ITEM_PAPER)
      {
         send_to_char("You are not holding a note.\n\r", ch);
         return;
      }

      if (paper->value[0] == 0)
      {
         send_to_char("There is nothing written on this note.\n\r", ch);
         return;
      }

      if (paper->value[1] == 0)
      {
         send_to_char("This note has no subject.\n\r", ch);
         return;
      }

      if (paper->value[2] == 0)
      {
         send_to_char("This note is addressed to no one!\n\r", ch);
         return;
      }

      strtime = ctime(&current_time);
      strtime[strlen(strtime) - 1] = '\0';

      /* handle IMC notes */
      to = get_extra_descr("_to_", paper->first_extradesc);
      subj = get_extra_descr("_subject_", paper->first_extradesc);
      text = get_extra_descr("_text_", paper->first_extradesc);

/*	if (to && (np = strchr(to, '@'))!=NULL)*/
      if (to && strchr(to, '@') != NULL)
      {
         if (!subj || !*subj)
         {
            send_to_char("You must specify a subject for IMC mail.\n\r", ch);
            return;
         }
         if (!text || !*text)
         {
            send_to_char("You must have text in IMC mail.\n\r", ch);
            return;
         }

/*	    {
	      send_to_char( "The IMC board is not here.\n\r", ch );
	      return;
	    }*/
         imc = TRUE;
      }
      board = find_board(ch);

      if (!board)
      {
         send_to_char("There is no bulletin board here to post your note on.\n\r", ch);
         return;
      }
      if ((imc && board->board_obj != sysdata.imc_mail_vnum) || (!imc && board->board_obj == sysdata.imc_mail_vnum))
      {
         send_to_char("You can only post IMC mail on the IMC board.\n\r", ch);
         return;
      }
/*	if (imc)
	{
	  if (np)
	    *np = '\0';
	  if (is_name("all", to))
	  {
	    send_to_char( "You may not post notes to ALL on the IMC board.\n\r", ch);
	    return;
	  }
	  if (np)
	    *np = '@';
	}*/
      if (!can_post(ch, board))
      {
         send_to_char("A magical force prevents you from posting your note here...\n\r", ch);
         return;
      }

      if (board->num_posts >= board->max_posts)
      {
         send_to_char("There is no room on this board to post your note.\n\r", ch);
         return;
      }

      act(AT_ACTION, "$n posts a note.", ch, NULL, NULL, TO_ROOM);

      CREATE(pnote, NOTE_DATA, 1);
      pnote->date = STRALLOC(strtime);

      pnote->to_list = to ? STRALLOC(to) : STRALLOC("all");
      pnote->text = text ? STRALLOC(text) : STRALLOC("");
      pnote->subject = subj ? STRALLOC(subj) : STRALLOC("");
      pnote->sender = QUICKLINK(ch->name);
      pnote->voting = 0;
      pnote->yesvotes = str_dup("");
      pnote->novotes = str_dup("");
      pnote->abstentions = str_dup("");

      LINK(pnote, board->first_note, board->last_note, next, prev);
      board->num_posts++;
      write_board(board);
      send_to_char("You post your note on the board.\n\r", ch);
      extract_obj(paper);
      return;
   }

   if (!str_cmp(arg, "remove") || !str_cmp(arg, "take") || !str_cmp(arg, "copy"))
   {
      char take;

      board = find_board(ch);
      if (!board)
      {
         send_to_char("There is no board here to take a note from!\n\r", ch);
         return;
      }
      if (!str_cmp(arg, "take"))
         take = 1;
      else if (!str_cmp(arg, "copy"))
      {
         if (!IS_IMMORTAL(ch))
         {
            send_to_char("Huh?  Type 'help note' for usage.\n\r", ch);
            return;
         }
         take = 2;
      }
      else
         take = 0;

      if (!is_number(arg_passed))
      {
         send_to_char("Note remove which nunumber?\n\r", ch);
         return;
      }

      if (!can_read(ch, board))
      {
         send_to_char("You can't make anyense of what's posted here, let alone remove anything!\n\r", ch);
         return;
      }

      anum = atoi(arg_passed);
      vnum = 0;
      for (pnote = board->first_note; pnote; pnote = pnote->next)
      {
         if (IS_MAIL && ((is_note_to(ch, pnote)) || get_trust(ch) >= sysdata.take_others_mail))
            vnum++;
         else if (!IS_MAIL)
            vnum++;
         if ((is_note_to(ch, pnote) || can_remove(ch, board)) && (vnum == anum))
         {
            if ((is_name("all", pnote->to_list)) && (get_trust(ch) < sysdata.take_others_mail) && (take == 1))
            {
               send_to_char("Notes addressed to 'all' can not be taken.\n\r", ch);
               return;
            }

            if (take != 0)
            {
               if (ch->gold < 50 && get_trust(ch) < sysdata.read_mail_free)
               {
                  if (take == 1)
                     send_to_char("It costs 50 coins to take your mail.\n\r", ch);
                  else
                     send_to_char("It costs 50 coins to copy your mail.\n\r", ch);
                  return;
               }
               if (get_trust(ch) < sysdata.read_mail_free)
                  ch->gold -= 50;
               paper = create_object(get_obj_index(OBJ_VNUM_NOTE), 0);
               ed = SetOExtra(paper, "_sender_");
               STRFREE(ed->description);
               ed->description = QUICKLINK(pnote->sender);
               ed = SetOExtra(paper, "_text_");
               STRFREE(ed->description);
               ed->description = QUICKLINK(pnote->text);
               ed = SetOExtra(paper, "_to_");
               STRFREE(ed->description);
               ed->description = QUICKLINK(pnote->to_list);
               ed = SetOExtra(paper, "_subject_");
               STRFREE(ed->description);
               ed->description = QUICKLINK(pnote->subject);
               ed = SetOExtra(paper, "_date_");
               STRFREE(ed->description);
               ed->description = QUICKLINK(pnote->date);
               ed = SetOExtra(paper, "note");
               STRFREE(ed->description);
               sprintf(notebuf, "From: ");
               strcat(notebuf, pnote->sender);
               strcat(notebuf, "\n\rTo: ");
               strcat(notebuf, pnote->to_list);
               strcat(notebuf, "\n\rSubject: ");
               strcat(notebuf, pnote->subject);
               strcat(notebuf, "\n\r\n\r");
               strcat(notebuf, pnote->text);
               strcat(notebuf, "\n\r");
               ed->description = STRALLOC(notebuf);
               paper->value[0] = 2;
               paper->value[1] = 2;
               paper->value[2] = 2;
               sprintf(short_desc_buf, "a note from %s to %s", pnote->sender, pnote->to_list);
               STRFREE(paper->short_descr);
               paper->short_descr = STRALLOC(short_desc_buf);
               sprintf(long_desc_buf, "A note from %s to %s lies on the ground.", pnote->sender, pnote->to_list);
               STRFREE(paper->description);
               paper->description = STRALLOC(long_desc_buf);
               sprintf(keyword_buf, "note parchment paper %s", pnote->to_list);
               STRFREE(paper->name);
               paper->name = STRALLOC(keyword_buf);
            }
            if (take != 2)
               note_remove(ch, board, pnote);
            send_to_char("Ok.\n\r", ch);
            if (take == 1)
            {
               act(AT_ACTION, "$n takes a note.", ch, NULL, NULL, TO_ROOM);
               obj_to_char(paper, ch);
            }
            else if (take == 2)
            {
               act(AT_ACTION, "$n copies a note.", ch, NULL, NULL, TO_ROOM);
               obj_to_char(paper, ch);
            }
            else
               act(AT_ACTION, "$n removes a note.", ch, NULL, NULL, TO_ROOM);
            return;
         }
      }

      send_to_char("No such note.\n\r", ch);
      return;
   }

   send_to_char("Huh?  Type 'help note' for usage.\n\r", ch);
   return;
}



BOARD_DATA *read_board(char *boardfile, FILE * fp)
{
   BOARD_DATA *board;
   char *word;
   char buf[MSL];
   bool fMatch;
   char letter;

   do
   {
      letter = getc(fp);
      if (feof(fp))
      {
         fclose(fp);
         return NULL;
      }
   }
   while (isspace(letter));
   ungetc(letter, fp);

   CREATE(board, BOARD_DATA, 1);

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


   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("Extra_readers", board->extra_readers, fread_string_nohash(fp));
            KEY("Extra_removers", board->extra_removers, fread_string_nohash(fp));
            if (!str_cmp(word, "End"))
            {
               board->num_posts = 0;
               board->first_note = NULL;
               board->last_note = NULL;
               board->next = NULL;
               board->prev = NULL;
               if (!board->read_group)
                  board->read_group = str_dup("");
               if (!board->post_group)
                  board->post_group = str_dup("");
               if (!board->extra_readers)
                  board->extra_readers = str_dup("");
               if (!board->extra_removers)
                  board->extra_removers = str_dup("");
               return board;
            }
         case 'F':
            KEY("Filename", board->note_file, fread_string_nohash(fp));
         case 'M':
            KEY("Min_read_level", board->min_read_level, fread_number(fp));
            KEY("Min_post_level", board->min_post_level, fread_number(fp));
            KEY("Min_remove_level", board->min_remove_level, fread_number(fp));
            KEY("Max_posts", board->max_posts, fread_number(fp));
         case 'P':
            KEY("Post_group", board->post_group, fread_string_nohash(fp));
         case 'R':
            KEY("Read_group", board->read_group, fread_string_nohash(fp));
         case 'T':
            KEY("Type", board->type, fread_number(fp));
         case 'V':
            KEY("Vnum", board->board_obj, fread_number(fp));
      }
      if (!fMatch)
      {
         sprintf(buf, "read_board: no match: %s", word);
         bug(buf, 0);
      }
   }

   return board;
}

NOTE_DATA *read_note(char *notefile, FILE * fp)
{
   NOTE_DATA *pnote;
   char *word;

   for (;;)
   {
      char letter;

      do
      {
         letter = getc(fp);
         if (feof(fp))
         {
            fclose(fp);
            return NULL;
         }
      }
      while (isspace(letter));
      ungetc(letter, fp);

      CREATE(pnote, NOTE_DATA, 1);

      if (str_cmp(fread_word(fp), "sender"))
         break;
      pnote->sender = fread_string(fp);

      if (str_cmp(fread_word(fp), "date"))
         break;
      pnote->date = fread_string(fp);

      if (str_cmp(fread_word(fp), "to"))
         break;
      pnote->to_list = fread_string(fp);

      if (str_cmp(fread_word(fp), "subject"))
         break;
      pnote->subject = fread_string(fp);

      word = fread_word(fp);
      if (!str_cmp(word, "voting"))
      {
         pnote->voting = fread_number(fp);

         if (str_cmp(fread_word(fp), "yesvotes"))
            break;
         pnote->yesvotes = fread_string_nohash(fp);

         if (str_cmp(fread_word(fp), "novotes"))
            break;
         pnote->novotes = fread_string_nohash(fp);

         if (str_cmp(fread_word(fp), "abstentions"))
            break;
         pnote->abstentions = fread_string_nohash(fp);

         word = fread_word(fp);
      }

      if (str_cmp(word, "text"))
         break;
      pnote->text = fread_string(fp);

      if (!pnote->yesvotes)
         pnote->yesvotes = str_dup("");
      if (!pnote->novotes)
         pnote->novotes = str_dup("");
      if (!pnote->abstentions)
         pnote->abstentions = str_dup("");
      pnote->next = NULL;
      pnote->prev = NULL;
      return pnote;
   }
   bug("read_note: bad key word.");
   exit(1);
}

/*
 * Load boards file.
 */
void load_boards(void)
{
   FILE *board_fp;
   FILE *note_fp;
   BOARD_DATA *board;
   NOTE_DATA *pnote;
   char boardfile[256];
   char notefile[256];

   first_board = NULL;
   last_board = NULL;

   sprintf(boardfile, "%s%s", BOARD_DIR, BOARD_FILE);
   if ((board_fp = fopen(boardfile, "r")) == NULL)
      return;

   while ((board = read_board(boardfile, board_fp)) != NULL)
   {
      LINK(board, first_board, last_board, next, prev);
      sprintf(notefile, "%s%s", BOARD_DIR, board->note_file);
      log_string(notefile);
      if ((note_fp = fopen(notefile, "r")) != NULL)
      {
         while ((pnote = read_note(notefile, note_fp)) != NULL)
         {
            LINK(pnote, board->first_note, board->last_note, next, prev);
            board->num_posts++;
         }
      }
   }
   return;
}


void do_makeboard(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;

   if (!argument || argument[0] == '\0')
   {
      send_to_char("Usage: makeboard <filename>\n\r", ch);
      return;
   }

   smash_tilde(argument);

   CREATE(board, BOARD_DATA, 1);

   LINK(board, first_board, last_board, next, prev);
   board->note_file = str_dup(strlower(argument));
   board->read_group = str_dup("");
   board->post_group = str_dup("");
   board->extra_readers = str_dup("");
   board->extra_removers = str_dup("");
}

void do_bset(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;
   bool found;
   char arg1[MIL];
   char arg2[MIL];
   char buf[MSL];
   int value;

   argument = one_argument(argument, arg1);
   argument = one_argument(argument, arg2);

   set_char_color(AT_NOTE, ch);
   if (arg1[0] == '\0' || arg2[0] == '\0')
   {
      send_to_char("Usage: bset <board filename> <field> value\n\r", ch);
      send_to_char("\n\rField being one of:\n\r", ch);
      send_to_char("  ovnum read post remove maxpost filename type\n\r", ch);
      send_to_char("  read_group post_group extra_readers extra_removers\n\r", ch);
      return;
   }

   value = atoi(argument);
   found = FALSE;
   for (board = first_board; board; board = board->next)
      if (!str_cmp(arg1, board->note_file))
      {
         found = TRUE;
         break;
      }
   if (!found)
   {
      send_to_char("Board not found.\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "ovnum"))
   {
      if (!get_obj_index(value))
      {
         send_to_char("No such object.\n\r", ch);
         return;
      }
      board->board_obj = value;
      write_boards_txt();
      send_to_char("Done.  (board's object vnum set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "read"))
   {
      if (value < 0 || value > MAX_LEVEL)
      {
         send_to_char("Value outside valid character level range.\n\r", ch);
         return;
      }
      board->min_read_level = value;
      write_boards_txt();
      send_to_char("Done.  (minimum reading level set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "read_group"))
   {
      if (!argument || argument[0] == '\0')
      {
         send_to_char("No reading group specified.\n\r", ch);
         return;
      }
      DISPOSE(board->read_group);
      if (!str_cmp(argument, "none"))
         board->read_group = str_dup("");
      else
         board->read_group = str_dup(argument);
      write_boards_txt();
      send_to_char("Done.  (reading group set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "post_group"))
   {
      if (!argument || argument[0] == '\0')
      {
         send_to_char("No posting group specified.\n\r", ch);
         return;
      }
      DISPOSE(board->post_group);
      if (!str_cmp(argument, "none"))
         board->post_group = str_dup("");
      else
         board->post_group = str_dup(argument);
      write_boards_txt();
      send_to_char("Done.  (posting group set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "extra_removers"))
   {
      if (!argument || argument[0] == '\0')
      {
         send_to_char("No names specified.\n\r", ch);
         return;
      }
      if (!str_cmp(argument, "none"))
         buf[0] = '\0';
      else
         sprintf(buf, "%s %s", board->extra_removers, argument);
      DISPOSE(board->extra_removers);
      board->extra_removers = str_dup(buf);
      write_boards_txt();
      send_to_char("Done.  (extra removers set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "extra_readers"))
   {
      if (!argument || argument[0] == '\0')
      {
         send_to_char("No names specified.\n\r", ch);
         return;
      }
      if (!str_cmp(argument, "none"))
         buf[0] = '\0';
      else
         sprintf(buf, "%s %s", board->extra_readers, argument);
      DISPOSE(board->extra_readers);
      board->extra_readers = str_dup(buf);
      write_boards_txt();
      send_to_char("Done.  (extra readers set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "filename"))
   {
      if (!argument || argument[0] == '\0')
      {
         send_to_char("No filename specified.\n\r", ch);
         return;
      }
      DISPOSE(board->note_file);
      board->note_file = str_dup(argument);
      write_boards_txt();
      send_to_char("Done.  (board's filename set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "post"))
   {
      if (value < 0 || value > MAX_LEVEL)
      {
         send_to_char("Value outside valid character level range.\n\r", ch);
         return;
      }
      board->min_post_level = value;
      write_boards_txt();
      send_to_char("Done.  (minimum posting level set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "remove"))
   {
      if (value < 0 || value > MAX_LEVEL)
      {
         send_to_char("Value outside valid character level range.\n\r", ch);
         return;
      }
      board->min_remove_level = value;
      write_boards_txt();
      send_to_char("Done.  (minimum remove level set)\n\r", ch);
      return;
   }

   if (!str_cmp(arg2, "maxpost"))
   {
      if (value < 1 || value > 999)
      {
         send_to_char("Value out of range.\n\r", ch);
         return;
      }
      board->max_posts = value;
      write_boards_txt();
      send_to_char("Done.  (maximum number of posts set)\n\r", ch);
      return;
   }
   if (!str_cmp(arg2, "type"))
   {
      if (value < 0 || value > 1)
      {
         send_to_char("Value out of range.\n\r", ch);
         return;
      }
      board->type = value;
      write_boards_txt();
      send_to_char("Done.  (board's type set)\n\r", ch);
      return;
   }

   do_bset(ch, "");
   return;
}


void do_bstat(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;
   bool found;
   char arg[MIL];

   argument = one_argument(argument, arg);
   found = FALSE;
   for (board = first_board; board; board = board->next)
      if (!str_cmp(arg, board->note_file))
      {
         found = TRUE;
         break;
      }

   if (!found)
   {
      if (argument && argument[0] != '\0')
      {
         send_to_char_color("&GBoard not found.  Usage: bstat <board filename>\n\r", ch);
         return;
      }
      else
      {
         board = find_board(ch);
         if (!board)
         {
            send_to_char_color("&GNo board present.  Usage: bstat <board filename>\n\r", ch);
            return;
         }
      }
   }

   ch_printf_color(ch,
      "\n\r&GFilename: &W%-15.15s &GOVnum: &W%-5d  &GRead: &W%-2d  &GPost: &W%-2d  &GRemove: &W%-2d\n\r&GMaxpost:  &W%-3d              &GType: &W%d\n\r&GPosts:    %d\n\r",
      board->note_file, board->board_obj, board->min_read_level, board->min_post_level, board->min_remove_level, board->max_posts, board->type,
      board->num_posts);

   ch_printf_color(ch, "&GRead_group:     &W%s\n\r&GPost_group:     &W%s\n\r&GExtra_readers:  &W%s\n\r&GExtra_removers: &W%s\n\r",
      board->read_group, board->post_group, board->extra_readers, board->extra_removers);
   return;
}


void do_boards(CHAR_DATA * ch, char *argument)
{
   BOARD_DATA *board;

   if (!first_board)
   {
      send_to_char_color("T&Ghere are no boards yet.\n\r", ch);
      return;
   }
   for (board = first_board; board; board = board->next)
      pager_printf_color(ch, "&G%-15.15s #: %5d Read: %2d Post: %2d Rmv: %2d Max: %3d Posts: &g%3d &GType: %d\n\r",
         board->note_file, board->board_obj,
         board->min_read_level, board->min_post_level, board->min_remove_level, board->max_posts, board->num_posts, board->type);
}

void mail_count(CHAR_DATA * ch)
{
   BOARD_DATA *board;
   NOTE_DATA *note;
   int cnt = 0;

   for (board = first_board; board; board = board->next)
      if (board->type == BOARD_MAIL && can_read(ch, board))
         for (note = board->first_note; note; note = note->next)
            if (is_note_to(ch, note))
               ++cnt;
   if (cnt)
      ch_printf(ch, "You have %d mail message%swaiting.\n\r", cnt, (cnt > 1) ? "s " : " ");
   return;
}